我正在使用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"
})
答案 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环境)。尝试更改返回类型,以使其正常工作。
答案 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拦截器抛出的异常。