刚刚在测试接口的时候发现一个奇怪的问题:通过拦截器获取 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:

        

      DeviceController:

        

    打印结果:

      HotelController:

        

      DeviceController:

        

      从打印结果看,两个类的打印信息确实有些不一样,但是我看不懂。。。我也仔细对比两个 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注解问题的更多相关文章

  1. spring boot拦截器中获取request post请求中的参数

    最近有一个需要从拦截器中获取post请求的参数的需求,这里记录一下处理过程中出现的问题. 首先想到的就是request.getParameter(String )方法,但是这个方法只能在get请求中取 ...

  2. [技巧篇]08.Struts2拦截器中获取Servlet API方法

    讲课中遇到的解决Session拦截器的后腿问题,还有如何在拦截器中获取Servlet API,这里留一个备注,方便学生查找

  3. MVC 在action拦截器中获取当前进入的控制器和aciton名

    我们在实现了action拦截器以后(继承至System.Web.Mvc.IActionFilter),需要在重写的方法OnActionExecuting中去获得当前进入的控制器和action名称,如何 ...

  4. springboot拦截器中获取配置文件值

    package com.zhx.web.interceptor; import com.zhx.util.other.IpUtil; import org.slf4j.Logger; import o ...

  5. spring boot拦截器中获取request post请求中的参数(转)

    文章转自 https://www.jianshu.com/p/69c6fba08c92

  6. 【spring boot】在自定义拦截器中从request中获取json字符串

    又这样的需求,需要在自定义的拦截器中获取request中的数据,想获取到的是JSON字符串 那需要在拦截器中写这样一个方法 public static String getOpenApiRequest ...

  7. 解决SpringMVC拦截器中Request数据只能读取一次的问题

    解决SpringMVC拦截器中Request数据只能读取一次的问题 开发项目中,经常会直接在request中取数据,如Json数据,也经常用到@RequestBody注解,也可以直接通过request ...

  8. Spring拦截器中通过request获取到该请求对应Controller中的method对象

    背景:项目使用Spring 3.1.0.RELEASE,从dao到Controller层全部是基于注解配置.我的需求是想在自定义的Spring拦截器中通过request获取到该请求对应于Control ...

  9. java自定义注解知识实例及SSH框架下,拦截器中无法获得java注解属性值的问题

    一.java自定义注解相关知识 注解这东西是java语言本身就带有的功能特点,于struts,hibernate,spring这三个框架无关.使用得当特别方便.基于注解的xml文件配置方式也受到人们的 ...

随机推荐

  1. sublime 删除重复行

    sublime 删除重复行 - 国内版 Binghttps://cn.bing.com/search?q=sublime+%E5%88%A0%E9%99%A4%E9%87%8D%E5%A4%8D%E8 ...

  2. 表单在ios下输入框必须重压或长按才能唤起软键盘

    解决方案: 一.在node_module里找到fastClick文件,然后找到focus方法,加一句focus方法即可解决:FastClick.prototype.focus = function(t ...

  3. Andorid SQLite数据库开发基础教程(2)

    Andorid SQLite数据库开发基础教程(2) 数据库生成方式 数据库的生成有两种方式,一种是使用数据库管理工具生成的数据库,我们将此类数据库称为预设数据库,另一种是使用代码生成的数据库.

  4. Docs-.NET-C#-指南-语言参考-关键字-值类型:bool

    ylbtech-Docs-.NET-C#-指南-语言参考-关键字-值类型:bool 1.返回顶部 1. bool(C# 参考) 2015/07/20 bool 关键字是 System.Boolean  ...

  5. 005-guava 集合-集合工具类-java.util.Collections中未包含的集合工具[Maps,Lists,Sets],Iterables、Multisets、Multimaps、Tables

    一.概述 工具类与特定集合接口的对应关系归纳如下: 集合接口 属于JDK还是Guava 对应的Guava工具类 Collection JDK Collections2:不要和java.util.Col ...

  6. 008-SpringBoot发布WAR启动报错:Error assembling WAR: webxml attribute is required

    一.Spring Boot发布war包流程: 1.修改web model的pom.xml <packaging>war</packaging> SpringBoot默认发布的都 ...

  7. Siamese Net

    参考博客:https://blog.csdn.net/ybdesire/article/details/84072339

  8. while死循环

    while死循环放入主线程要注意,如果处理不当可能引起界面假死,如果界面假死,可以放入子线程中(如果每个循环处理时间现对于CPU很短,则建议在本次循环结束的尾部加入Sleep以释放对CPU的占用) C ...

  9. CSS3 Filter特效

    CSS3 filter和IE的filter完全是两样东东. Filters主要是运用在图片上,以实现一些特效.(尽管他们也能运用于video上),不过我们在些只来讨论图片上的运用. 语法 elm { ...

  10. nodemon运行 提示错误:无法加载文件 C:\Users\gxf\AppData\Roaming\npm\nodemon.ps1,因为在此系统上禁止运行脚本。

    nodemon运行 提示错误:无法加载文件 C:\Users\gxf\AppData\Roaming\npm\nodemon.ps1,因为在此系统上禁止运行脚本. 这是你笔记本禁止运行脚本,解决办法 ...