2014-02-27 38 views
6

我使用springmvc为客户端创建了restful api,我有一个用于检查accesstoken的拦截器。如何在Spring Interceptor中使用@ExceptionHandler?

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(); 
    } 
} 

而在我的控制,我用@ExceptionHandler来处理异常,处理InvalidTokenException代码看起来像

@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; 
} 

但不幸的是在preHandle方法扔的异常没有被定义的异常处理程序捕获在控制器中。

任何一个可以给我一个处理异常的解决方案吗? PS:我的控制器方法使用下面的代码产生既JSON和XML

@RequestMapping(value = "login", method = RequestMethod.POST, produces = 
{ 
    "application/xml", "application/json" 
}) 
+1

你不能。 “@ ExceptionHandler”方法只适用于特定的控制器。拦截器在控制器之前执行,所以在那个时候无法知道应用哪个'@ ExceptionHandler'方法。不确定一个'@ ControllerAdvice' bean是否会在这里起作用,注册全局错误处理方法,否则实现你自己的'HandlerExceptionResolver'来以通用的方式而不是你的控制器来实现它。 –

+0

什么类型的异常抛出preHandle方法? – Rembo

+0

与其他方法一样,ValidateToken方法应该是小写的。 我面临同样的问题,但它似乎确实从preHandle方法抛出一个异常时,从来没有触及过Controller方法,所以@ControllerAdvice不会赶上并处理这个异常。 – klausch

回答

0

您有无效的返回类型,这就是为什么没有异常处理程序

下面的返回类型都支持抓处理器方法:

  • A ModelAndView object(Servlet MVC或Portlet MVC)。
  • A Model对象,其视图名称通过RequestToViewNameTranslator隐式确定。
  • A Map暴露模型的对象,其视图名称通过RequestToViewNameTranslator隐式确定。
  • A View对象。
  • A String值被解释为视图名称。
  • void如果该方法处理反应本身(通过直接写入的响应内容,声明类型ServletResponse/HttpServletResponse/RenderResponse的用于该目的的参数),或者如果视图名称应该被隐式地确定通过RequestToViewNameTranslator(未声明处理程序方法签名中的响应参数;仅适用于Servlet环境)。

试着改变你的返回类型,让它工作。

REFFERENCE:spring source

3

使用其他方法,捕获异常,并转发到另一个控制器解决。

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; 
} 
+0

无需抛出异常。抛出异常会导致性能问题。根据条件返回一个值并设置response.setStatus()或根据需要修改响应对象。最后,'return false'将确保响应被发送回客户端。 – jaks

2

移动你@ExceptionHandler方法为@ControllerAdvice注释类可以帮助在这里。请参阅:ControllerAdvice

Rembo已在评论中建议它(标记为“不确定”),我确认这适用于我:在这种情况下,抛出的异常被正确捕获。

相关问题