How to use @ExceptionHandler in Spring Interceptor?

I use springmvc to create a calm api for the client, I have an interceptor to check accesstoken.

public class AccessTokenInterceptor extends HandlerInterceptorAdapter { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; Authorize authorizeRequired = handlerMethod.getMethodAnnotation(Authorize.class); if (authorizeRequired != null) { String token = request.getHeader("accesstoken"); ValidateToken(token); } } return true; } protected long ValidateToken(String token) { AccessToken accessToken = TokenImpl.GetAccessToken(token); if (accessToken != null) { if (accessToken.getExpirationDate().compareTo(new Date()) > 0) { throw new TokenExpiredException(); } return accessToken.getUserId(); } else { throw new InvalidTokenException(); } } 

And in my controller I use @ExceptionHandler to handle exceptions, the code for handling InvalidTokenException looks like

 @ExceptionHandler(InvalidTokenException.class) public @ResponseBody Response handleInvalidTokenException(InvalidTokenException e) { Log.p.debug(e.getMessage()); Response rs = new Response(); rs.setErrorCode(ErrorCode.INVALID_TOKEN); return rs; } 

But, unfortunately, the exception thrown by the preHandle method does not get into the exception handler defined in the controller.

Can someone give me a solution to handling exception? PS: My controller method creates both json and xml using the following code:

 @RequestMapping(value = "login", method = RequestMethod.POST, produces = { "application/xml", "application/json" }) 
+6
source share
5 answers

Moving your @ExceptionHandler methods to the annotated @ControllerAdvice class can help here. See: ControllerAdvice

Rembo suggested it already in a comment (marked as β€œnot sure”), I confirm that this works for me: in this case, the thrown exceptions are caught correctly.

+5
source

Resolved using a different approach, throw an exception and forward to another controller.

 try { ValidateToken(token); } catch (InvalidTokenException ex) { request.getRequestDispatcher("/api/error/invalidtoken").forward(request, response); return false; } catch (TokenExpiredException ex) { request.getRequestDispatcher("/api/error/tokenexpired").forward(request, response); return false; } 
+4
source

Add a default controller, such as FallbackController, with an empty Path RequestMapping method to handle all exception requests:

 @Controller public class FallbackController { @RequestMapping(method = {RequestMethod.GET, RequestMethod.POST}) @ResponseBody public String fallback(HttpServletRequest request, HttpServletResponse response) { return "Anything you want"; } @ExceptionHandler(InvalidTokenException.class) public @ResponseBody Response handleInvalidTokenException(InvalidTokenException e) { Log.p.debug(e.getMessage()); Response rs = new Response(); rs.setErrorCode(ErrorCode.INVALID_TOKEN); return rs; } } 

Hope this helps.

+2
source

You have an invalid return type, so don't catch an exception handler

The following return types for handler methods are supported:

  • ModelAndView object (MVC servlet or MVC portlet).
  • A Model , with a view name implicitly defined using RequestToViewNameTranslator .
  • A Map object to display the model, with a view name implicitly defined using RequestToViewNameTranslator .
  • View object.
  • The value of A String , which is interpreted as the name of the view.
  • void if the method processes the response itself (by directly writing the contents of the response, declaring an argument of type ServletResponse / HttpServletResponse / RenderResponse for this) or if it is assumed that the view name is implicitly defined through RequestToViewNameTranslator (without declaring the response argument in the signature of the handler method, only applicable in the environment Servlet).

Try changing the type of the return value to make it work.

Refference: spring source

0
source

If you use the @EnableWebMvc annotation anywhere in the ur application, HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver) will be applied. Since we know that HandlerExceptionResolver will be called not only through the controller method loop, but also before / after the controller (for example, HandlerInterceptor. Check here ), HandlerExceptionResolverComposite will be HandlerExceptionResolverComposite . Since, by default, HandlerExceptionResolverComposite will register 3 recognizers, and one of them: ExceptionHandlerExceptionResolver based on https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/mvc method / annotation / ExceptionHandlerExceptionResolver.html # doResolveHandlerMethodException-javax.servlet.http.HttpServletRequest-javax.servlet.http.HttpServletResponse-org.springframework.web.method.Handleretheth

it will try to find the controller level @ExceptionHandler annotation and redirect the exception to this exception handler. (see the link "doResolveHandlerMethodException" in the link above)

So while you have @EnableWebMvc (why not?), Your @ExceptionHandler should be able to catch the exception thrown from the spring interceptor.

0
source

All Articles