简体   繁体   English

如何在Spring Interceptor中使用@ExceptionHandler?

[英]How to use @ExceptionHandler in Spring Interceptor?

I am using springmvc to create restful api for client, I have an interceptor for checking the accesstoken. 我正在使用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();
    }
}

And in my controller, I use @ExceptionHandler to handle exceptions, the code to handle InvalidTokenException looks like 在我的控制器中,我使用@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;
}

But unfortunately the exception throwed in preHandle method is not caught by the exception handler defined in controller. 但不幸的是,preHandle方法抛出的异常并未被控制器中定义的异常处理程序捕获。

Can any one give me an solution of handling the exception? 任何人都可以给我一个处理异常的解决方案吗? PS: My controller method produce both json and xml using code below: PS:我的控制器方法使用以下代码生成json和xml

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

Moving your @ExceptionHandler methods into a @ControllerAdvice annotated class can help here. @ExceptionHandler方法移动到@ControllerAdvice注释类可以在这里提供帮助。 See: ControllerAdvice 请参阅: 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. Rembo已经在评论中建议它(标记为“不确定”),我确认这对我有用 :在这种情况下,抛出的异常被正确捕获。

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

Add a default Controller such as FallbackController with an empty RequestMapping path method to handle all Exception requests: 添加一个默认的控制器,如FallbackController,使用一个空的RequestMapping路径方法来处理所有异常请求:

@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. 希望能帮助到你。

You have invalid return type, that's why not caught by the exception handler 你有无效的返回类型,这就是为什么不被异常处理程序捕获

The following return types are supported for handler methods: 处理程序方法支持以下返回类型:

  • A ModelAndView object (Servlet MVC or Portlet MVC). 一个ModelAndView对象(Servlet MVC或Portlet MVC)。
  • A Model object, with the view name implicitly determined through a RequestToViewNameTranslator . 一个Model对象,通过RequestToViewNameTranslator隐式确定视图名称。
  • A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator . 用于公开模型的Map对象,其中视图名称通过RequestToViewNameTranslator隐式确定。
  • A View object. 一个View对象。
  • A String value which is interpreted as view name. 一个String值,它被解释为视图名称。
  • 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). 如果方法处理响应本身(通过直接编写响应内容,为此目的声明类型为ServletResponse / HttpServletResponse / RenderResponse的参数)或者视图名称应该通过RequestToViewNameTranslator隐式确定(不声明响应参数),则返回void在处理程序方法签名中;仅适用于Servlet环境)。

Try by changing you return type, to get it work. 尝试更改您的返回类型,以使其工作。

Refference: spring source 参考: 泉源

If you use @EnableWebMvc annotation anywhere through ur application, HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver) will be applied. 如果您通过ur应用程序在任何地方使用@EnableWebMvc注释,将应用HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver) Since we know that HandlerExceptionResolver will be invoked not only through the controller method execution cycle but also before/after controller (eg HandlerInterceptor. check here ), HandlerExceptionResolverComposite will be invoked. 因为我们知道HandlerExceptionResolver不仅会通过控制器方法执行周期调用, 而且还会在控制器之前/之后调用(例如HandlerInterceptor。 在这里检查), HandlerExceptionResolverComposite将调用HandlerExceptionResolverComposite 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- 因为默认情况下,HandlerExceptionResolverComposite将注册3个解析器,其中一个是: ExceptionHandlerExceptionResolver ,基于https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/servlet/ MVC /方法/注解/ 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. 它将尝试查找控制器级别@ExceptionHandler注释并将异常转发给该异常处理程序。 (see "doResolveHandlerMethodException" in above link) (参见上面链接中的“doResolveHandlerMethodException”)

So as long as you have @EnableWebMvc (why not?), your @ExceptionHandler should be able to catch exception thrown from spring interceptor. 所以只要你有@EnableWebMvc(为什么不呢?),你的@ExceptionHandler应该能够捕获从spring拦截器抛出的异常。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM