SpringBoot encapsulates the global exception handler
1. Cause
Global exception handling refers to the unified and automatic handling of exceptions in the whole system, which can handle exceptions in the project without some try/catch.
-
Instead of forcing to write try/catch, exceptions are captured by a unified exception handling mechanism.
@GetMapping("/error1") public String error1() { int i = 1 / 0; return "success"; }
In development, if try/catch is not used for capture. The client will jump to the default exception page of springboot. An error message of 500 is reported.
When exceptions are encountered during development, general program developers will use try/catch to capture and handle them, as follows:@GetMapping("/error2") public String error2() { try { int i = 1 / 0; } catch (Exception ex) { log.info("An exception occurred:{}", ex); return "no"; } return "success"; }
-
Custom exceptions can only be caught with global exceptions.
@GetMapping("/error4") public void error4() { throw new RuntimeException("Incorrect user name or password!!!"); }
The above method cannot be processed through try/catch.
-
In the parameter validator of JSR303, if the parameter verification fails, an exception will be thrown, and it cannot be directly captured and processed through try/catch.
2. Realize
2.1 uniformly encapsulate exception handling enumeration classes
package com.example.exception; import lombok.AllArgsConstructor; import lombok.Getter; /** * @Auther: giraffe * @Date: 2021/07/22/11:19 * @Description: */ @Getter @AllArgsConstructor public enum ResultCodeEnum { UNKNOWN_REASON(false, 20001, "unknown error"), SERVER_ERROR(false, 500, "The server is busy, please try again later"), ORDER_CREATE_FAIL(false, 601, "Order placing failed"); private Boolean success; private Integer code; private String message; }
2.2 handling of abnormal results of encapsulated controller
package com.example.exception; import lombok.*; @Builder @AllArgsConstructor @NoArgsConstructor @Data @ToString public class ErrorHandler { // ErrorHandler === R answer: do not destroy r class. // Exception status code, obtained from enumeration private Integer status; // Exception information, obtained from enumeration private String message; // Exception name private String exception; /** * Encapsulate exception enumeration * @param resultCodeEnum Exception enumeration * @param throwable abnormal * @return */ public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable) { ErrorHandler errorHandler = new ErrorHandler(); errorHandler.setMessage(resultCodeEnum.getMessage()); errorHandler.setStatus(resultCodeEnum.getCode()); errorHandler.setException(throwable.getClass().getName()); return errorHandler; } /** * Unified encapsulation of exception handling * @param resultCodeEnum Exception enumeration * @param throwable abnormal * @param message Abnormal information * @return */ public static ErrorHandler fail(ResultCodeEnum resultCodeEnum, Throwable throwable, String message) { ErrorHandler errorHandler = ErrorHandler.fail(resultCodeEnum, throwable); errorHandler.setMessage(message); return errorHandler; } }
2.3 define a global exception handler
package com.example.config; import com.example.exception.ErrorHandler; import com.example.exception.ResultCodeEnum; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; @RestControllerAdvice @Slf4j public class GlobalExceptionHandler { /** * Handle 500 exceptions on the server uniformly * @param e * @param request * @return */ @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Throwable.class) // All exceptions public ErrorHandler makeExcepton(Throwable e, HttpServletRequest request) { ErrorHandler errorHandler = ErrorHandler.fail(ResultCodeEnum.SERVER_ERROR, e); log.error("Request address:{},Exception occurred:{}", request.getRequestURL(), e); return errorHandler; } }
- The makeexception method is used to encapsulate runtime exceptions as ErrorHandler objects for unified capture and processing.
- @RestControllerAdvice and @ ControllerAdvice are enhanced extension processing for controller, and global exception is one of the extension capabilities.
- @ExceptionHandler(Throwable.class): handle certain types of exceptions in a unified way, so as to reduce the complexity and repetition rate of exceptions in the code,
- @Responsestatus (httpstatus. International_server_error): Specifies the http status code received by the client. If 500 is configured here, it will be displayed as 500 error. It's OK not to specify. Because the return will be processed according to the enumeration.
2.4 defining test classes
package com.example.controller; import com.example.common.R; import com.example.entity.User; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; /** * @Auther: giraffe * @Date: 2021/07/22/9:28 * @Description: */ @RestController @Api(description = "User center") public class IndexController { @GetMapping("/get") public User getUser(Integer id){ int i = 1 / 0; User user = new User(); user.setId(1); user.setNickname("After King Jing of Zhongshan"); user.setPassword("123456"); user.setAdddress("Zhuozhou City, Hebei Province"); return user; } }
2.5 run view results
{ "status":500, "message":"The server is busy, please try again later", "exception":"java.lang.ArithmeticException" }
All exceptions are intercepted to global exception handling.
Accessing error4 does not display the corresponding custom exception handling information. How to handle it?
Answer: unified handling of custom exceptions
3. Custom exception and integrated custom exception handler
Benefits of user-defined exception: you can quickly locate the module where the error occurs according to the information of user-defined exception, record log files, and quickly analyze and determine the error.
3.1 add custom exception
package com.example.exception; import lombok.AllArgsConstructor; import lombok.Data; /** * @Auther: giraffe * @Date: 2021/07/22/13:10 * @Description: */ @Data @AllArgsConstructor public class OrderException extends RuntimeException { private Integer code; private String message; public OrderException(ResultCodeEnum resultCodeEnum) { this.code = resultCodeEnum.getCode(); this.message = resultCodeEnum.getMessage(); } }
3.2 add custom exception handling method
@ExceptionHandler(OrderException.class) public ErrorHandler makeOrderException(OrderException orderException, HttpServletRequest request) { ErrorHandler errorHandler = ErrorHandler.builder() .status(orderException.getCode()) .message(orderException.getMessage()) .exception(orderException.getClass().getName()) .build(); log.error("Request address:{},Exception occurred:{}", request.getRequestURL(), orderException); return errorHandler; }
3.3 define methods for testing
@GetMapping("/createOrder") public String createOrder(Integer id){ if(id.equals(1)){ throw new OrderException(ResultCodeEnum.ORDER_CREATE_FAIL); } return "success"; }
{ "code":601, "data":null, "message":"Order placing failed" }
4. Unified return & exception return
package com.example.config; import com.example.common.R; import com.example.exception.ErrorHandler; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.SneakyThrows; import org.springframework.core.MethodParameter; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice; /** * @Auther: giraffe * @Date: 2021/07/22/9:41 * @Description: */ @ControllerAdvice(basePackages = "com.example") public class ResultResponseHandler implements ResponseBodyAdvice<Object> { /** * Whether the advice function is supported. true means yes and false means No * * @param methodParameter * @param aClass * @return */ @Override public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) { return true; } /** * @param o Represents the result of the request method of springMvc * @param methodParameter * @param mediaType * @param aClass * @param serverHttpRequest * @param serverHttpResponse * @return */ @SneakyThrows @Override public Object beforeBodyWrite(Object o, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) { // The returned results are returned and processed uniformly if (o instanceof ErrorHandler) { ErrorHandler errorHandler = (ErrorHandler) o; return R.fail(errorHandler.getStatus(), errorHandler.getMessage()); } else if (o instanceof String) { // Because the spring MVC data converter has special processing for strings, StringHttpMessageConverter ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.writeValueAsString(R.success(o)); } return R.success(o); } }