Spring MVC ExceptionHandler для спокойного и нормального

Я хочу обрабатывать исключения как для обычных, так и для остальных/ajax-запросов. Вот мой код,

@ControllerAdvice
public class MyExceptionHandler {

    @ExceptionHandler(Exception.class)
    public ModelAndView handleCustomException(Exception ex) {

        ModelAndView model = new ModelAndView("error");
        model.addObject("errMsg", ex.getMessage());
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);
        sw.toString();
        model.addObject("errTrace", sw);
        return model;

    }

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAjaxException(Exception ex) {
        JSONObject model = new JSONObject();
        model.put("status", "error");
        model.put("errMsg", ex.getMessage());
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        ex.printStackTrace(pw);
        sw.toString();
        model.put("errTrace", sw);

        return model.toString();
    }
}

Это выдаст мне ошибку, так как я не могу использовать @ExceptionHandler(Exception.class) дважды. Итак, что может быть решением?


person odedravijay    schedule 18.08.2015    source источник


Ответы (4)


см. конфигурацию @ControllerAdvice: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html

Таким образом, вы можете создать два класса (обработчики ошибок) и указать аннотации/базовые пакеты/назначенные типы.

Например, для REST (ajax) используйте аннотацию @RestController для ваших контроллеров, и вы можете обрабатывать такие ошибки:

@ControllerAdvice(annotations = RestController.class)
public class MyExceptionHandler {

    @ExceptionHandler(Exception.class)
    @ResponseBody
    public String handleAjaxException(Exception ex) {
        ...
    }
}

для других случаев это может быть обработчик ошибок с аннотацией

@ControllerAdvice(annotations = Controller.class)
person Anatoly Deyneka    schedule 18.08.2015
comment
У меня есть аннотированный класс с @Controller, и некоторые методы имеют @ ResponseBody, а некоторые являются обычными возвращаемыми моделями. Я использовал ваш пример, но всегда называю annotation = Controller.class. Я думаю, только потому, что я использовал @Controller для класса контроллера?!! - person odedravijay; 18.08.2015
comment
да, ваши REST-методы должны быть в отдельном контроллере с аннотацией @RestController вместо @Controller (чтобы это решение работало). - person Anatoly Deyneka; 18.08.2015

Это глобальный обработчик исключений весной mvc. Он вызывается каждый раз, когда в вашем приложении обнаруживается исключение. Я думаю, что вы можете контролировать только исключение 404 с помощью web.xml.

@ControllerAdvice
public class GlobalExceptionController {

    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public ModelAndView handleAllException(Throwable ex,
            HttpServletResponse response) {

        ex.printStackTrace();
        // Set Status
        response.setStatus(500);
        // Set View
        ModelAndView model = new ModelAndView("500");
        model.addObject("navlabel", "");
        model.addObject("userActivity", new ArrayList<String>());
        // Set exception Message
        model.addObject("errMsg", ex.getMessage());
        return model;
    }
}
person Charnjeet Singh    schedule 18.08.2015
comment
Спасибо за ответ. Этот глобальный возвращает ModelAndView, это нормально для обычного запроса, такого как server/app/getCustomer, и мы устанавливаем имя представления. Но с запросом ajax в случае какой-либо ошибки он должен отправить сообщение об ошибке в виде строки, чтобы его можно было отобразить с помощью alert(). - person odedravijay; 18.08.2015
comment
Я думаю, что @ResponseBody преобразует его в json. Вы пробовали? - person Charnjeet Singh; 18.08.2015

Вы можете создать внутренний статический класс @RestControllerAdvice. Для этого не нужно было создавать отдельный @RestController.

@ControllerAdvice
public class BaseController {
private static final Logger logger = 
LoggerFactory.getLogger(BaseController.class);

@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handleException(Exception error, Model model) {
    logger.error("Error was: " + error.getMessage(), error);
    model.addAttribute("message", error.getMessage());
    model.addAttribute("stackTrace", error.getStackTrace());
    model.addAttribute("exception", error);
    return "error"; //return view
}

@RestControllerAdvice
public static class RestBaseController {

    private static final Logger logger = LoggerFactory.getLogger(RestBaseController.class);

    @ExceptionHandler(Exception.class)
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public String handleException(Exception error) {
        logger.error("Error was: " + error.getMessage(), error);

        return "error"; //return "error"
    }
}
}
person Bogdan Samondros    schedule 27.04.2017

Вы можете написать два обработчика исключений для обработки как обычных запросов, так и запросов rest/ajax. Вот пример кода для иллюстрации решения.

@ControllerAdvice(annotations = RestController.class)
@Order(1)
class RestExceptionHandler {
    @ExceptionHandler(MyException.class)
    @ResponseBody
    ResponseEntity<ErrorResponse> exceptionHandler() {
        ....
    }   
}

@ControllerAdvice(annotations = Controller.class)
@Order(2)
class ExceptionHandler {
    @ExceptionHandler(Exception.class)
    public ModelAndView handleError500(HttpServletRequest request, HttpServletResponse response, Exception ex) {
        ModelAndView mav = new ModelAndView("error");
        mav.addObject("error", "500");
        return mav;
    }
}
person Mohd Yasin    schedule 09.10.2017