This is the 9th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021

preface

This section introduces how to use global exception capture in ruoyi-Vue module. Global exception capture is a must for every project. With the help of global exception capture, we can focus on the development of business code without considering the handling of exceptions. Ruoyi uses @RestControllerAdvice, which reduces the @responseBody annotation compared to @ControllerAdvice. It only needs to add @ExceptionHandler annotation to the specific method. Just use @RestControllerAdvice.

@RestControllerAdvice

In general, our RestControllerAdvice must handle the following

Custom validation exception

It mainly deals with the @Validated error and is used to format the returned validation message into our already written return class. MethodArgumentNotValidException is BindException subclasses.

/** * Custom validation exception */
@ExceptionHandler(BindException.class)
public AjaxResult handleBindException(BindException e) {
    log.error(e.getMessage(), e);
    String message = e.getAllErrors().get(0).getDefaultMessage();
    return AjaxResult.error(message);
}

/** * Verification exception */
@ExceptionHandler(MethodArgumentNotValidException.class)
public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
    log.error(e.getMessage(), e);
    String message = e.getBindingResult().getFieldError().getDefaultMessage();
    return AjaxResult.error(message);
}
Copy the code

Here’s another exception ConstraintViolationException can also capture the custom validation is unusual, but is in javax.mail validation package, rather than the above two anomalies in spring, the above two exceptions are not in a bag.

Business exceptions

We also typically define a custom business exception that can be used to throw an error when there is a logical problem

/** * Service exception */
@ExceptionHandler(ServiceException.class)
public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
{
    log.error(e.getMessage(), e);
    Integer code = e.getCode();
    return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
}
Copy the code

A system exception

This is usually used for backstopping, and if nothing else can be stopped it will be intercepted with a system exception.

/** * System exception */
@ExceptionHandler(Exception.class)
public AjaxResult handleException(Exception e, HttpServletRequest request) {
    String requestURI = request.getRequestURI();
    log.error("Requested address '{}', system exception occurred.", requestURI, e);
    return AjaxResult.error(e.getMessage());
}
Copy the code

Multiple exception call order

AbstractHandlerMethodExceptionResolver exception handling is the abstract base class, it is on the HandlerExceptionResolver implementation of this interface, Inherited AbstractHandlerExceptionResolver

The processing location is

In thedoResolveHandlerMethodException

In obtaininggetExceptionHandlerMethodThe error type is used to find the appropriate method to handle the error

@Nullable
public Method resolveMethodByThrowable(Throwable exception) {
   Method method = resolveMethodByExceptionType(exception.getClass());
   if (method == null) {
      Throwable cause = exception.getCause();
      if(cause ! =null) { method = resolveMethodByThrowable(cause); }}return method;
}

@Nullable
public Method resolveMethodByExceptionType(Class<? extends Throwable> exceptionType) {
   Method method = this.exceptionLookupCache.get(exceptionType);
   if (method == null) {
      method = getMappedMethod(exceptionType);
      this.exceptionLookupCache.put(exceptionType, method);
   }
   return(method ! = NO_MATCHING_EXCEPTION_HANDLER_METHOD ? method :null);
}

Copy the code

The point here is to use the getMappedMethod to find the closest comparator to the Throwable using the ExceptionDepthComparator.

And you can see that getDepth is using a recursive depth check,

Multiple @RestControllerAdvice load sequences

If we reference another API package that already has @RestControllerAdvice and calls its handler each time, and we want to change it to our own, we can use the @order (Ordered.HIGHEST_PRECEDENCE) annotation to promote our handler class. But generally speaking, do not do this, it may overwrite other people’s processing class, so if we must do this, we must write our Exception as thin as possible, so as not to affect the original logic, to prevent processing other people’s logic.