实际上,通常需要集中处理控制器甚至整个应用程序中的异常。在本文中,我们将分析Spring框架提供的解决此问题的主要功能,并通过简单的示例,让我们了解一切的工作原理。谁对此主题感兴趣-欢迎参加!
最初,在Spring 3.2之前,处理应用程序中异常的主要方法是HandlerExceptionResolver和@ExceptionHandler注解。我们将在下面更详细地分析它们,但是它们具有某些缺点。从3.2版开始,出现了@ControllerAdvice批注,该批注消除了先前解决方案的限制。在春季5中,添加了一个新的ResponseStatusException类,该类对于处理REST API的基本错误非常方便。
现在,首先要开始!
控制器异常处理-@ExceptionHandler
@ExceptionHandler . , , .
:
@RestController
public class Example1Controller {
@GetMapping(value = "/testExceptionHandler", produces = APPLICATION_JSON_VALUE)
public Response testExceptionHandler(@RequestParam(required = false, defaultValue = "false") boolean exception)
throws BusinessException {
if (exception) {
throw new BusinessException("BusinessException in testExceptionHandler");
}
return new Response("OK");
}
@ExceptionHandler(BusinessException.class)
public Response handleException(BusinessException e) {
return new Response(e.getMessage());
}
}
testExceptionHandler, BusinessException, — . , , .
handleException . @ExceptionHandler(BusinessException.class), BusinessException. @ExceptionHandler , : @ExceptionHandler({BusinessException.class, ServiceException.class}).
— 200 JSON . , @ResponseStatus, @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR).
:
:
@ExceptionHandler , . @ExceptionHandler , , , .
HandlerExceptionResolver
HandlerExceptionResolver Spring. HandlerExceptionResolver. , , Spring . :
ExceptionHandlerExceptionResolver — @ExceptionHandler, .
DefaultHandlerExceptionResolver — Spring , :
Exception | HTTP Status Code |
---|---|
BindException | 400 (Bad Request) |
ConversionNotSupportedException | 500 (Internal Server Error) |
HttpMediaTypeNotAcceptableException | 406 (Not Acceptable) |
HttpMediaTypeNotSupportedException | 415 (Unsupported Media Type) |
HttpMessageNotReadableException | 400 (Bad Request) |
HttpMessageNotWritableException | 500 (Internal Server Error) |
HttpRequestMethodNotSupportedException | 405 (Method Not Allowed) |
MethodArgumentNotValidException | 400 (Bad Request) |
MissingServletRequestParameterException | 400 (Bad Request) |
MissingServletRequestPartException | 400 (Bad Request) |
NoSuchRequestHandlingMethodException | 404 (Not Found) |
TypeMismatchException | 400 (Bad Request) |
, REST API . . ModelAndView, , .
ResponseStatusExceptionResolver — @ResponseStatus.
ServiceException:
@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class ServiceException extends Exception {
public ServiceException(String message) {
super(message);
}
}
ServiceException @ResponseStatus value INTERNAL_SERVER_ERROR, - 500.
:
@RestController
public class Example2Controller {
@GetMapping(value = "/testResponseStatusExceptionResolver", produces = APPLICATION_JSON_VALUE)
public Response testResponseStatusExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
throws ServiceException {
if (exception) {
throw new ServiceException("ServiceException in testResponseStatusExceptionResolver");
}
return new Response("OK");
}
}
GET- exception=true, 500- :
— . , @ResponseStatus .
HandlerExceptionResolver , - JSON XML . , .
:
@Component
public class CustomExceptionResolver extends AbstractHandlerExceptionResolver {
@Override
protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
if (ex instanceof CustomException) {
modelAndView.setStatus(HttpStatus.BAD_REQUEST);
modelAndView.addObject("message", "CustomException was handled");
return modelAndView;
}
modelAndView.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
modelAndView.addObject("message", "Another exception was handled");
return modelAndView;
}
}
, . , : , ModelAndView. JSON, .
-, . . , . , — :
@RestController
public class Example3Controller {
@GetMapping(value = "/testCustomExceptionResolver", produces = APPLICATION_JSON_VALUE)
public Response testCustomExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
throws CustomException {
if (exception) {
throw new CustomException("CustomException in testCustomExceptionResolver");
}
return new Response("OK");
}
}
:
200 JSON .
@ControllerAdvice
— . Spring 3.2 @ControllerAdvice.
:
@ControllerAdvice
public class DefaultAdvice {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Response> handleException(BusinessException e) {
Response response = new Response(e.getMessage());
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
, @ControllerAdvice , .
DefaultAdvice handleException. handleException @ExceptionHandler, , , . BusinessException.
: @ExceptionHandler({BusinessException.class, ServiceException.class}). @ExceptionHandler .
, handleException ResponseEntity Response:
public class Response {
private String message;
public Response() {
}
public Response(String message) {
this.message = message;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
, JSON . message HttpStatus.OK, 200.
:
@RestController
public class Example4Controller {
@GetMapping(value = "/testDefaultControllerAdvice", produces = APPLICATION_JSON_VALUE)
public Response testDefaultControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
throws BusinessException {
if (exception) {
throw new BusinessException("BusinessException in testDefaultControllerAdvice");
}
return new Response("OK");
}
}
, , JSON 200:
?
! :
@ControllerAdvice(annotations = CustomExceptionHandler.class)
public class CustomAdvice {
@ExceptionHandler(BusinessException.class)
public ResponseEntity<Response> handleException(BusinessException e) {
String message = String.format("%s %s", LocalDateTime.now(), e.getMessage());
Response response = new Response(message);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
@ControllerAdvice(annotations = CustomExceptionHandler.class). CustomAdvice , @CustomExceptionHandler.
@CustomExceptionHandler :
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExceptionHandler {
}
:
@RestController
@CustomExceptionHandler
public class Example5Controller {
@GetMapping(value = "/testCustomControllerAdvice", produces = APPLICATION_JSON_VALUE)
public Response testCustomControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
throws BusinessException {
if (exception) {
throw new BusinessException("BusinessException in testCustomControllerAdvice");
}
return new Response("OK");
}
}
Example5Controller @CustomExceptionHandler, Example4Controller . BusinessException CustomAdvice, DefaultAdvice, .
CustomAdvice — :
. @ControllerAdvice, . .
ResponseStatusException.
ResponseStatusException:
@RestController
public class Example6Controller {
@GetMapping(value = "/testResponseStatusException", produces = APPLICATION_JSON_VALUE)
public Response testResponseStatusException(@RequestParam(required = false, defaultValue = "false") boolean exception) {
if (exception) {
throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "ResponseStatusException in testResponseStatusException");
}
return new Response("OK");
}
}
ResponseStatusException , , . @ResponseStatus — -. , .
:
简介:我们已经看到了处理异常的不同方法,每种方法都有其自身的特征。在大型应用程序中,您可以一次找到几种方法,但是您需要非常小心,并且不要使错误处理逻辑过于复杂。否则,将会发现某些异常将在错误的处理程序中处理,并且响应将不同于预期的响应。例如,如果应用程序有多个顾问程序,则在创建新顾问程序时,您需要确保它不会破坏处理旧控制器异常的现有顺序。
所以要小心,一切都会很好!