简体   繁体   中英

Spring Boot intercept all exception handlers

I am trying to perform some common logic that applies to all my @ExceptionHandler s in code. I know I can write a HandlerInterceptor to intercept happy paths. But I would like to hook into the exception handling lifecycle so that I can execute some common logic such as logging, before the error response is rendered.

Is there anyway to do this in Spring Boot / Spring MVC? I would like to avoid having to write a servlet filter for this purpose if possible.

There is a way with @RestControllerAdvice and @ExceptionHandler , an example:

@RestControllerAdvice
public class GlobalControllerExceptionHandler {

    @ExceptionHandler(value = {DeniedPermissionException.class})
    @ResponseStatus(HttpStatus.FORBIDDEN)
    public String deniedPermissionException(DeniedPermissionException ex) {
        return "Denied permission";
    }

    @ExceptionHandler(value = {ConstraintViolationException.class})
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public String constraintViolationException(ConstraintViolationException ex) {
        return "Bad request";
    }

    @ExceptionHandler(value = {Exception.class})
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    public String internalServerError(Exception ex) {
         return "Internal error";
    }
}

* DeniedPermissionException is a custom exception.

I have a solution. It's about using HandlerInterceptor.afterCompletion method. However, there is a line in the documentation of this method that states that:

Note: Will only be called if this interceptor's preHandle method has successfully completed and returned true!

So the trick is to also implement the preHandle and make it return true .

Now my interceptor looks like this:

@Component
public class MyInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // perform common logic here
    }
}

One thing to be aware of though is that if you have a chain of interceptors and an interceptor before this one throws an exception, this interceptor won't get a chance to execute. So if we reorder the interceptor chain so that MyInterceptor is right at the top, it will intercept all requests.

This is not really a Spring Boot concern. This is really a Spring MVC concern. One good approach is to implement the HandlerExceptionResolver or extend from something like ExceptionHandlerExceptionResolver . The implementation needs to be given a higher precedence than the default exception resolvers (which all run with the lowest precedence). And if you want to retain the existing behavior of the default resolvers but only trap the exception for something cross-cutting like logging or tracking, then just return null for the ModelAndView and Spring will ensure other default resolvers are invoked as before.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM