Various postures of exception handling in Spring

Keywords: Programming Spring JSON REST JSP

1. Preface

The importance of unified exception handling for application is self-evident. Today, let's talk about how Spring can handle unified Rest exception handling. At the same time, we will simply compare their advantages and disadvantages.

2. @Controller Combine @ ExceptionHandler

Declare a method in the controller and mark it with the @ ExceptionHandler annotation:

 @Controller
 @RequestMapping("/test")
 public class TestController {
  
     @RequestMapping("/err")
     @ResponseBody
     public Object demo1(){
         int i = 1 / 0;
         return new Date();
     }
  
     @ExceptionHandler({RuntimeException.class})
     public ModelAndView fix(Exception ex){
         System.out.println(ex.getMessage());
         return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
     }
 }

Advantage:

  • Highest priority.
  • @The method return value type of ExceptionHandler tag supports multiple types. It can be views, json, etc.

Disadvantages:

  • The exception type on the @ ExceptionHandler annotation in a Controller cannot be the same, otherwise the runtime throws an exception.
  • An exception type that requires explicit declaration handling.
  • Scope is just that Controller is not a real global exception. If you want to work globally, you need to put it in the parent class of all controllers.

3. @ControllerAdvice combined with @ ExceptionHandler

This is an improved version of 2. By defining the @ ControllerAdvice class and marking @ ExceptionHandler on the method, the purpose of global exception handling is achieved:

 @ControllerAdvice
 public class TestController {
 
  
     @ExceptionHandler({RuntimeException.class})
     public ModelAndView fix(Exception ex){
         System.out.println(ex.getMessage());
         return new ModelAndView("error",new ModelMap("ex",ex.getMessage()));
     }
 }

Advantage:

  • Global exception handling.
  • Subject and status code of complete control response
  • Multiple exceptions are mapped to the same method for handling together, and it makes full use of the updated response entity response

Disadvantages:

  • The exception type on the @ ExceptionHandler annotation in a Controller cannot be the same, otherwise the runtime throws an exception.
  • An exception type that requires explicit declaration handling.

In general, this method is also recommended for exception handling. Compatible in most cases.

4. HandlerExceptionResolver interface

Implement the HandlerExceptionResolver interface. Here we inherit its abstract implementation AbstractHandlerExceptionResolver:

 @Component
 public class RestResponseStatusExceptionResolver extends AbstractHandlerExceptionResolver {
  
     @Override
     protected ModelAndView doResolveException(
       HttpServletRequest request, 
       HttpServletResponse response, 
       Object handler, 
       Exception ex) {
         try {
             if (ex instanceof IllegalArgumentException) {
                 return handleIllegalArgument((IllegalArgumentException) ex, response, handler);
             }
            //todo more exception
         } catch (Exception handlerException) {
               //todo 
         }
         return null;
     }
  
     private ModelAndView 
       handleIllegalArgument(IllegalArgumentException ex, HttpServletResponse response) 
       throws IOException {
         response.sendError(HttpServletResponse.SC_CONFLICT);
         String accept = request.getHeader(HttpHeaders.ACCEPT);
           //todo  more  response
         return new ModelAndView();
     }
 }

Advantage:

  • This is a global exception handler.
  • In this way, it is convenient to return JSP, velocity and other template views.
  • Multiple formats of response are supported. Although the overridden method returns ModelAndView, we can use it to customize the response results because there is HttpServletResponse in the parameter. For example, if the client asks for application / json, then in case of an error situation, we need to make sure that we return a response encoded in application / json.

Disadvantages:

  • We need to interact with low-level HttpServletResponse to implement various forms of response bodies.
  • Low priority

5. Exception handling in spring boot

If you use Spring Boot as the framework We can also use it in a unique way. The advantage is that the low-level API is shielded, and the disadvantages are obvious, so specific exceptions cannot be caught.

5.1 implementation of ErrorController

By default, Spring Boot provides / error mapping to handle all errors, registers the global error page in the Servlet container and returns it to the client. By implementing the ErrorController interface and registering as a Bean. No more examples here. Refer to BasicErrorController.

5.2 add ErrorAttributes

We can also add a Bean of type ErrorAttributes to replace the default exception handling.

 @Component
 public class MyCustomErrorAttributes extends DefaultErrorAttributes {
  
     @Override
     public Map<String, Object> getErrorAttributes(
       WebRequest webRequest, boolean includeStackTrace) {
         Map<String, Object> errorAttributes = 
           super.getErrorAttributes(webRequest, includeStackTrace);
         errorAttributes.put("locale", webRequest.getLocale()
             .toString());
         errorAttributes.remove("error");
  
         //todo your business
  
         return errorAttributes;
     }
 }

5.3 inherit the base class BasicErrorController

Spring Boot auto configuration also provides a base class BasicErrorController to implement the exception handling of ErrorController interface. By default, it processes the error of text/html type request. It can inherit the base class to customize and handle more request types, add public methods and specify the processing type by using the product attribute of @ RequestMapping annotation.

 @Component
 public class MyErrorController extends BasicErrorController {
  
     public MyErrorController(ErrorAttributes errorAttributes) {
         super(errorAttributes, new ErrorProperties());
     }
  
     @RequestMapping(produces = MediaType.APPLICATION_XML_VALUE)
     public ResponseEntity<Map<String, Object>> xmlError(HttpServletRequest request) {
          
     //todo your business
  
     }
 }

6. ResponseStatusException of spring 5

In addition, in the latest Spring 5, you can handle it by throwing a ResponseStatusException exception.

Benefits:

  • Easy to use
  • One type, many status codes: an exception type can lead to many different responses. This reduces tight coupling compared to @ ExceptionHandler
  • We will not have to create so many custom exception classes
  • Because exceptions can be created programmatically, exception handling can be better controlled

Disadvantages:

  • Without a unified exception handling method, it is more difficult to enforce some application wide conventions
  • There may be a lot of duplicate code.

7. summary

We summarize and analyze the common and uncommon ways of Spring handling exceptions I believe you can find the right way to deal with it. If it's useful to you, please give me a compliment, your encouragement and my motivation!

Pay attention to the public address: Felordcn for more information

Personal blog: https://felord.cn

Posted by birwin on Sun, 17 Nov 2019 18:51:14 -0800