攔截器中獲取不到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 深層原理。。(僅記錄一下問題經驗)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM