This is the second day of my participation in the November Gwen Challenge. Check out the details: the last Gwen Challenge 2021

(a) what is global exception handling

When the front end requests data from the back end, the interface normally returns the format we want. But in the case of problems in the back-end program, the default data returned is not necessarily the type we want, so when there is an exception in the program, we need to have a unified global exception handler to process the exception data into the format that we need and return it to the foreground

(2) Which exceptions need to be handled

1. Exceptions thrown by controller

This exception is an exception caused by the running of the business, which occurs in controller, or can be thrown up to Controller. This exception can be achieved by customizingthe exception class and annotating @ControllerAdvice or @RestControllerAdvice:

@RestControllerAdvice //@ControllerAdvice @Slf4j public class AllExceptionHandler{ @ExceptionHandler(value = customexception.class) public R customExceptionHandle(Exception e){// this place should create multiple Exception classes and classify them to catch log.error(" CustomException: {}",e); return R.fail(e.getMessage()); } @ExceptionHandler(value = org.springframework.validation.BindException.class) public R bindExceptionHandle(BindException ex){ StringBuffer defaultMessage = new StringBuffer(); List<ObjectError> list = ex.getBindingResult().getAllErrors(); if(list! =null && list.size()>0){ try { int i=0; for (ObjectError error : list) { if(i>0){ defaultMessage.append(","); } defaultMessage.append(error.getDefaultMessage()); i++; } } catch (Exception e) { e.printStackTrace(); } } String s = defaultMessage.toString(); Log.warn (" User data parameter exception: {}",s); return R.fail(s); } @ExceptionHandler(value = Exception.class) public R exceptionHandle(Exception e){ Log.error (" unknown exception {},{}", LLDB message (),e); Return R.fast (" system exception ", LLDB etMessage()); } public AllExceptionHandler() { super(); }Copy the code

Use attention

  1. The @RestControllerAdvice or @ControllerAdvice annotation tells the program that you have defined controller global exception catching and pass it on to the class for handling.

  2. @RestControllerAdvice subclasses the @ControllerAdvice function and writes the return message to the Body of the Response (since @responseBody is also annotated), so use @restco if it is a single item before and after a JSON interaction NtrollerAdvice is better.

  3. The @RestControllerAdvice and @ControllerAdvice annotations contain some properties:

    attribute explain
    @ControllerAdvice(“org.zdc.controllers”) Catches an exception for the controller in the specified package
    @ControllerAdvice(annotations = RestController.class) Catch an exception for a controller with the @restController annotation
    @ControllerAdvice(assignableTypes = {AbstractController.class}) Catch a controller exception with the specified signature
  4. If this does not work, you need to watch to see if it is intercepted by filter,Aspect, etc., or if the exception is not thrown under the scanned package.

  5. You can define multiple @ExceptionHandler. When an Exception occurs, the program will match the Exception from top to bottom. After the match is successful, the program will stop and continue to match the Exception

  6. The principle defined by @ExceptionHandler is that all exceptions except the last exception. class need to be implemented on demand. For example, if the CustomException. Class is a service exception, only LLDB etMessage() is returned. If the @ parameter is used to verify the exception BindException As a result of

2. Intercept 404 or server error exceptions that do not enter the controller

When an undefined request is requested or a resolution request fails, the program will throw an error and forward the error to the /error interface, which will return the error data, but the data returned may not be in the desired format, so we need to implement a default Controller and implement the /error method.

@RestController @Slf4j public class OtherExceptionHandler implements ErrorController { @Override public String getErrorPath() { return "/error"; } @RequestMapping("/error") public R otherError(HttpServletRequest request, HttpServletResponse Response) {response.setStatus(200); Integer statusCode = (Integer)request.getAttribute("javax.servlet.error.status_code"); String errorMsg = "error "; If (statusCode == null) {errorMsg = "Internal error "; } / / forwarded if custom CustomException exceptions (statusCode = = 5001 && request. The getAttribute (" javax.mail. Servlet. Error. Exception ") instanceof CustomException) {log. Warn (" Filter abnormal: {} ", ((Exception) request. GetAttribute (" javax.mail. Servlet. Error. Exception "))); return R.fail(((Exception)request.getAttribute("javax.servlet.error.exception")).getMessage()); } try { return R.fail(errorMsg, statusCode, HttpStatus.valueOf(statusCode)); } catch (Exception ex) {errorMsg = "error :" + statusCode; } log.error(" server error, error code :{}",statusCode); return R.fail(errorMsg); }}Copy the code

Here you should see the custom CustomException exception being forwarded. In fact, we can manually forward the exception here (for example in custom Filter) by using the global search method to manually forward the /error interface

3. Exceptions occur in user-defined codes such as filter

In a custom filter, we need to interrupt the operation to throw an exception if the business judgment is inconsistent, in a custom Aspect, the proxy method needs to throw an exception if it fails, and so on

In the filter

@Component public class ZdcFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {if(false){// Interrupt throws an exception // The first manual forward to the /error interface request.setAttribute("javax.servlet.error.status_code",5001); Request. SetAttribute (" javax.mail. Servlet. Error. Status_msg ", "setup data returned through the forward/error"); request.getRequestDispatcher("/error").forward(request, response); return; // Throw new CustomException(" MyFilter, return value "); SetContentType (" Application /json; charset=utf-8"); Response.getwriter ().print(" call response directly from MyFilter to return data "); response.getWriter().flush(); response.getWriter().close(); return; }else{// Pass chain.dofilter (request,response); }}}Copy the code

Of course, here we’re basically going to use the third way to write back directly in response.