拦截器中获取不到controller注解问题

摘要:
AnnotationclassLoginAnnotation=bean.getClass().getAnnotation(RequiredLogin.class);//类级别所需的登录标志System.out.println(“类:

  刚刚在测试接口的时候发现一个奇怪的问题:通过拦截器获取 controller 类注解,有些能获取到,有些又不能获取到,见鬼了。

  【环境】:

    1. springboot :2.2.0.RELEASE

  【场景】:

    1. 定义一个登陆拦截器,对请求的 token 进行校验;

    2. 定义两个注解:

      RequiredLogin :要求登录注解

      NoRequiredLogin :不要求登录注解

    3. 在要求登录的 controller 类上添加 RequiredLogin 注解,然后在拦截器中获取 controller 是否有该注解,如果有,则进行token校验;

  【问题】:

    两个不同的 controller ,都添加了 RequiredLogin 注解,在拦截器中使用同样的代码获取注解,期中一个 controller 能够获取到,一个不能。

  【代码】

    拦截器代码:

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
startMillis.set(System.currentTimeMillis());
if (handler instanceof HandlerMethod) {
HandlerMethod myHandlerMethod = (HandlerMethod) handler;
Object bean = myHandlerMethod.getBean();
Annotation classLoginAnnotation = bean.getClass().getAnnotation(RequiredLogin.class);// 类级别的要求登录标记
System.out.println("类:"+bean.getClass()+",类注解:"+classLoginAnnotation);
Method method = myHandlerMethod.getMethod();
Annotation methodLoginAnnotation = method.getAnnotation(RequiredLogin.class);// 方法级别的要求登录标记
Annotation methodNologinAnnotation = method.getAnnotation(NoRequiredLogin.class);// 方法级别的不要求登录标记

if ((classLoginAnnotation != null && methodNologinAnnotation == null)
|| (classLoginAnnotation == null && methodLoginAnnotation != null)) {
//验证登陆
if (isLogin(request))
return true;
else {
// 未登录
ApiResp apiResp=ApiRespBuilder.buildFailResp(ErrorCodeEnum.code_1001);
response.setHeader("content-type", "application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(JSONObject.fromObject(apiResp).toString());
return false;
}
}
}
return true;
}

    controller 代码:

@RequestMapping("/device")
@RestController
@RequiredLogin
public class DeviceController extends BaseController {
@RequestMapping("/hotel")
@RestController
@RequiredLogin
public class HotelController extends BaseController {

  【结果】

    分别对两个不同 controller 的接口进行请求,并且都不带token,发现 HotelController 返回要求登录,而 DeviceController 接口进入业务代码然后由于没有token报错

      HotelController:

        拦截器中获取不到controller注解问题第1张

      DeviceController:

        拦截器中获取不到controller注解问题第2张

     打印结果:

      HotelController:

        拦截器中获取不到controller注解问题第3张

       DeviceController:

        拦截器中获取不到controller注解问题第4张

      从打印结果看,两个类的打印信息确实有些不一样,但是我看不懂。。。我也仔细对比两个 Controller 类,但是好像没啥不同。

  【说明】

    这个拦截器我是从以前的代码拷贝来的,在很多项目中使用过了,一直没有这个问题。于是我对比之前代码的 springboot 版本。之前的版本的 2.2.1,现在的版本是 2.2.0,于是以为是版本问题,但是改成 2.2.1 后也没有用。

  【解决】

    拦截器代码改一下,直接使用 HandlerMethod 的 getBeanType 方法获取 controller 的 class 信息,而不是先 获取 bean,在 getClass():

@Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws IOException {
        startMillis.set(System.currentTimeMillis());
        if (handler instanceof HandlerMethod) {
            HandlerMethod myHandlerMethod = (HandlerMethod) handler;
            Annotation classLoginAnnotation = myHandlerMethod.getBeanType().getAnnotation(RequiredLogin.class);// 类级别的要求登录标记
            Method method = myHandlerMethod.getMethod();
            Annotation methodLoginAnnotation = method.getAnnotation(RequiredLogin.class);// 方法级别的要求登录标记
            Annotation methodNologinAnnotation = method.getAnnotation(NoRequiredLogin.class);// 方法级别的不要求登录标记

            if ((classLoginAnnotation != null && methodNologinAnnotation == null)
                    || (classLoginAnnotation == null && methodLoginAnnotation != null)) {
                //验证登陆
                if (isLogin(request))
                    return true;
                else {
                    // 未登录
                    ApiResp apiResp=ApiRespBuilder.buildFailResp(ErrorCodeEnum.code_1001);
                    response.setHeader("content-type", "application/json");
                    response.setCharacterEncoding("UTF-8");
                    response.getWriter().write(JSONObject.fromObject(apiResp).toString());
                    return false;
                }
            }
        }
        return true;
    }

  【原因】

    还不知道,不太懂 spring 深层原理。。(仅记录一下问题经验)

免责声明:文章转载自《拦截器中获取不到controller注解问题》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇zookeeper日志级别使用 video.js 开发 HTML5 视频页面下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

MFC入门(三)

1 新建项目 1.1 根据向导创建项目 1.2 添加预处理指令 由于微软在VS2013中不建议再使用C/C++的传统库函数scanf,strcpy,sprintf等,所以直接使用这些库函数会提示C4996错误。 VS建议采用带_s的函数,如scanf_s、strcpy_s,但这些并不是标准C/C++函数。要想继续使用此函数,需要添加 _CRT_SECURE...

WebAPI 实现前后端分离的示例

转自:http://www.aspku.com/kaifa/net/298780.html 随着Web技术的发展,现在各种框架,前端的,后端的,数不胜数。全栈工程师的压力越来越大。 现在的前端的框架,既可以做各种Web,又可以做各种APP,前端框架更新换代越来越快,越来越多。 传统的模式 前端和后端进行调试,修改都非常麻烦。往往前端配合后端很痛苦,后...

关于常用 软件授权 Licence说明

BSD开源协议 BSD开源协议是一个给于使用者很大自由的协议。基本上使用者可以”为所欲为”,可以自由的使用,修改源代码,也可以将修改后的代码作为开源或者专有软件再发布。 但”为所欲为”的前提当你发布使用了BSD协议的代码,或则以BSD协议代码为基础做二次开发自己的产品时,需要满足三个条件: 如果再发布的产品中包含源代码,则在源代码中必须带有原来代码中的B...

游戏组件——总结

总结 你的小游戏引擎现在有了三个新命名空间,也有许多辅助类可以用在未来的项目中。新的TextureFont 类在下面几章尤其有用。它不仅仅在显示诸如记分板这样的游戏数据上有用,也在单元测试中被使用;为了告诉用户所有可用的热键,在单元测试中显示帮助文本非常有用;万一你遇到问题,显示测试数据或者Debug数据尤其有用。例如,一个camera类的单元测试能输...

Object-C与Swift混合开发

Object-C作为Apple的iOS App开发语言服务了很多个年头,2014年Apple推出了新的编程语言Swift。更高效更安全的口号再次吸引了一大批非iOS开发程序猿进入,小编觉得Swift代替Object-C仅仅是时间问题,在神州这片土地上,毕竟技术普及有些落后。但再有两年左右时间Swift产品链将形成。第三方支持框架逐步完好。Swift必将成...

防止表单重复提交的方法

1、在jsp页面的button添加相关js代码: <input type="button" value="提交" onclick="this.disabled=true;this.form.submit()"> 此方法缺点是用户可能禁用js,此方法就可能失效。 2、session的token机制...