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


      刚刚在测试接口的时候发现一个奇怪的问题:通过拦截器获取 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 深层原理。。(仅记录一下问题经验)

  • 相关阅读:
    python学习笔记(十一)处理json
    python学习笔记(十)常用模块
    python学习笔记(九)内置函数
    python学习笔记(八)函数return多个值,列表推导式和交换两个变量的值
    BZOJ 3675 [Apio2014]序列分割 (斜率优化DP)
    BZOJ 3126 [USACO2013 Open]Photo (单调队列优化DP)
    POJ 1821 Fence (单调队列优化DP)
    BZOJ 3326 [SCOI2013]数数 (数位DP)
    HDU 6148 Valley Numer (数位DP)
    BZOJ 2741 L (可持久化01Trie+分块)
  • 原文地址:https://www.cnblogs.com/coding-one/p/11890945.html
Copyright © 2020-2023  润新知