Java 如何在 Spring Interceptor 中使用@ExceptionHandler?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22062311/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to use @ExceptionHandler in Spring Interceptor?
提问by Wp7Beginner
I am using springmvc to create restful api for client, I have an interceptor for checking the accesstoken.
我正在使用 springmvc 为客户端创建restful api,我有一个用于检查访问令牌的拦截器。
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 xmlusing code below:
谁能给我一个处理异常的解决方案?PS:我的控制器方法使用以下代码生成json 和 xml:
@RequestMapping(value = "login", method = RequestMethod.POST, produces =
{
"application/xml", "application/json"
})
回答by Abhishek Nayak
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). - A
Model
object, with the view name implicitly determined through aRequestToViewNameTranslator
. - A
Map
object for exposing a model, with the view name implicitly determined through aRequestToViewNameTranslator
. - A
View
object. - A
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 typeServletResponse
/HttpServletResponse
/RenderResponse
for that purpose) or if the view name is supposed to be implicitly determined through aRequestToViewNameTranslator
(not declaring a response argument in the handler method signature; only applicable in a Servlet environment).
- 一个
ModelAndView
对象(Servlet MVC 或 Portlet MVC)。 - 一个
Model
对象,其视图名称通过RequestToViewNameTranslator
. - 甲
Map
用于曝光模式,与视图名称对象隐含地通过确定RequestToViewNameTranslator
。 - 一个
View
对象。 - 一个
String
被解释为视图名称的值。 void
如果该方法处理反应本身(通过直接写入的响应内容,声明类型的参数ServletResponse
/HttpServletResponse
/RenderResponse
为此目的),或者如果视图名称应该通过一个被隐式地确定RequestToViewNameTranslator
(未声明的处理程序方法签名的响应参数; 仅适用于 Servlet 环境)。
Try by changing you return type, to get it work.
尝试改变你的返回类型,让它工作。
Refference: spring source
参考:弹簧源
回答by Wp7Beginner
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;
}
回答by istibekesi
Moving your @ExceptionHandler
methods into a @ControllerAdvice
annotated class can help here. See: ControllerAdvice
将你的@ExceptionHandler
方法移动到一个带@ControllerAdvice
注释的类中可以在这里有所帮助。请参阅:控制器建议
Rembosuggested it in comment already (marked as "not sure"), I confirm that works for me: in this case the thrown exceptions are caught correctly.
回答by user3386184
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 alsobefore/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-
如果您通过您的应用程序在任何地方使用 @EnableWebMvc 注释,HandlerExceptionResolverComposite (subclass of HandlerExceptionResolver)
将被应用。因为我们知道,HandlerExceptionResolver
不仅将通过控制器方法执行周期被调用,而且前/控制器(例如HandlerInterceptor接口。检查后在这里),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-
it will try to find controller level @ExceptionHandler annotation and forward the exception to that exception handler. (see "doResolveHandlerMethodException" in above link)
它将尝试找到控制器级别的 @ExceptionHandler 注释并将异常转发到该异常处理程序。(请参阅上面链接中的“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 拦截器抛出的异常。
回答by Lion
Add a default Controller such as FallbackController with an empty RequestMapping path method to handle all Exception requests:
添加一个默认的Controller,比如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.
希望能帮助到你。