如何在Spring Interceptor中使用@ExceptionHandler?

时间:2014-02-27 07:53:40

标签: java spring exception-handling interceptor

我正在使用springmvc为客户端创建restful api,我有一个用于检查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();
    }
}

在我的控制器中,我使用@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"
})

5 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:4)

@ExceptionHandler方法移动到@ControllerAdvice带注释的类可以在这里提供帮助。请参阅:ControllerAdvice

Rembo已在评论中提出建议(标记为"不确定"),我确认这对我有效:在这种情况下,抛出的异常会被正确捕获。

答案 2 :(得分:2)

使用空的RequestMapping路径方法添加默认控制器(例如FallbackController)来处理所有异常请求:

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

希望有帮助。

答案 3 :(得分:0)

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

捕获的原因

处理程序方法支持以下返回类型:

  • 一个ModelAndView对象(Servlet MVC或Portlet MVC)。
  • Model个对象,其中视图名称通过RequestToViewNameTranslator隐式确定。
  • 用于公开模型的Map对象,其中视图名称通过RequestToViewNameTranslator隐式确定。
  • 一个View对象。
  • String值,将其解释为视图名称。
  • void如果方法处理响应本身(通过直接编写响应内容,为此目的声明类型为ServletResponse / HttpServletResponse / RenderResponse的参数)或如果视图名称应该通过RequestToViewNameTranslator隐式确定(不在处理程序方法签名中声明响应参数;仅适用于Servlet环境)。

尝试更改返回类型,以使其正常工作。

参考:spring source

答案 4 :(得分:0)

如果您通过应用程序在任何地方使用@EnableWebMvc注释,将应用HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver)。因为我们知道HandlerExceptionResolver不仅会通过控制器方法执行周期进行调用,而且还会在控制器之前/之后进行调用(例如HandlerInterceptor。检查here),HandlerExceptionResolverComposite将被调用。 由于默认情况下,HandlerExceptionResolverComposite将注册3个解析器,其中一个是:ExceptionHandlerExceptionResolver,基于 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-

它将尝试查找控制器级别的@ExceptionHandler批注并将异常转发到该异常处理程序。 (请参阅上面的链接中的“ doResolveHandlerMethodException”)

只要您拥有@EnableWebMvc(为什么不这样做),您的@ExceptionHandler就应该能够捕获从Spring拦截器抛出的异常。