Reputation: 231
I am using springmvc to create restful api for client, I have an interceptor for checking the 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 to handle 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 throwed in preHandle method is not caught by the exception handler defined in controller.
Can any one give me an solution of handling the exception? PS: My controller method produce both json and xml using code below:
@RequestMapping(value = "login", method = RequestMethod.POST, produces =
{
"application/xml", "application/json"
})
Upvotes: 15
Views: 28683
Reputation: 19
Add a default Controller such as FallbackController with an empty RequestMapping path 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 it helps.
Upvotes: 1
Reputation: 1
If you use @EnableWebMvc annotation anywhere through ur application, HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver)
will be applied. Since we know that HandlerExceptionResolver
will be invoked not only through the controller method execution cycle but also before/after controller (e.g. HandlerInterceptor. check here), HandlerExceptionResolverComposite
will be invoked.
Since by default, HandlerExceptionResolverComposite will register 3 resolvers, and one of them is: 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.HandlerMethod-java.lang.Exception-
it will try to find controller level @ExceptionHandler annotation and forward the exception to that exception handler. (see "doResolveHandlerMethodException" in above link)
So as long as you have @EnableWebMvc (why not?), your @ExceptionHandler should be able to catch exception thrown from spring interceptor.
Upvotes: 0
Reputation: 1012
Moving your @ExceptionHandler
methods into a @ControllerAdvice
annotated class can help here. See: ControllerAdvice
Rembo suggested it in comment already (marked as "not sure"), I confirm that works for me: in this case the thrown exceptions are caught correctly.
Upvotes: 6
Reputation: 231
Solved using other approach, catch 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;
}
Upvotes: 6
Reputation: 3748
You have invalid return type, that's why not caught by the exception handler
The following return types are supported for handler methods:
ModelAndView
object (Servlet MVC or Portlet MVC).Model
object, with the view name implicitly determined through a RequestToViewNameTranslator
.Map
object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator
.View
object.String
value which is interpreted as view name.void
if the method handles the response itself (by writing the response content directly, declaring an argument of type ServletResponse
/ HttpServletResponse
/ RenderResponse
for that purpose) or if the view name is supposed to be implicitly determined through a RequestToViewNameTranslator
(not declaring a response argument in the handler method signature; only applicable in a Servlet environment).Try by changing you return type, to get it work.
Refference: spring source
Upvotes: 0