Reputation: 62613
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.
Upvotes: 17
Views: 23205
Reputation: 31
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.
Upvotes: 0
Reputation: 62613
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.
Upvotes: 8
Reputation: 5068
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.
Upvotes: 8