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 obtaininggetExceptionHandlerMethod
The 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.