错误应用场
在Controller
中,我们自己定义了一个@Auth
注解来实现权限控制功能,如:
@Auth(verifyLogin=false,verifyURL=false)
@RequestMapping("/login")
public ModelAndView login(HttpServletRequest request,HttpServletResponse response) throws Exception{
Map<String,Object> context = getRootMap();
return forword("login", context);
}
表示该方法不须要登陆验证,也不须要URL权限验证。
- AOP. 通过Spring AOP拦截方法调用实现
- Interceptor. 注冊一个拦截器。在拦截器中通过反射得到被调用的控制器方法的
@Auth
注解,从而实现业务功能
显然使用拦截器更方便。代码量更少。看一下拦截器的preHandle()
方法的签名:
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception;
通过文档得知,第三个參数就是即将调用的控制器方法。
于是我们能够通过反射得到@Auth
注解:
HandlerMethod method = (HandlerMethod)handler;
Auth auth = method.getMethod().getAnnotation(Auth.class);
可是实际运行中发现非常严重的问题,那就是handler
的实际类型并不总是HandlerMethod
类型,因此第一行代码常常会扔ClassCastException
。
经过研究发现。仅仅有当GET请求是请求静态文件时(在spring配置文件中会配置静态文件的URI),handler
的实际类型会是DefaultServletHttpRequestHandler
,此时强制转换就会报错。
解决方法
在运行强制转换之前用instanceof
检查參数handler
的实际类型,假设不是HandlerMethod
类型,则拦截器不运行不论什么验证逻辑。直接放行。
为什么要记录一下?由于我发现老外给的Demo中都没有运行类型检查。误导了非常多人,让使用者以为handler
一定是HandlerMethod
类型。
这里也提醒我们养成良好的编程习惯。运行强制转换之前一定要做类型检查。