輕松實現java攔截器+自定義注解


目錄和概述

概述

  • 內容:攔截器的使用很簡單,定義一個自己的攔截器,向配置中添加一下就可以使用。為了方便,之后又引入了注解。本文就將用簡潔的代碼構建一個springboot的攔截器。
  • 假設需求:訪問項目的controller是都要進行"token驗證",除了某些像登錄之類的方法。
  • 項目結構:
    • TokenInterceptor.java 自定義攔截器
    • InterceptorConfig.java 添加攔截器進入項目
    • NoNeedToken.java 自定義注解
    • TestController.java 測試接口

目錄

1、自定義攔截器

在 TokenInterceptor.java 中輸入以下代碼,以下的代碼將生成一個在請求到達controller前進行攔截的攔截器
import com.alibaba.fastjson.JSONObject;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.List;

@Component
public class TokenInterceptor implements HandlerInterceptor {
    // 假設現在的token有如下數據
    List<String> tokenList = Arrays.asList("111", "222", "333");
    // 這個方法是在訪問接口之前執行的,我們只需要在這里寫驗證登陸狀態的業務邏輯,就可以在用戶調用指定接口之前驗證登陸狀態了
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 設置返回為json格式,使用UTF-8
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        String token = request.getHeader("token");
        PrintWriter out;
        // 之后寫你的判斷邏輯:return true是通過攔截器,可以繼續訪問controller,return false是不通過
        if (token == null || !tokenList.contains(token)) {
            // 如果失敗了返回{state:"false", msg:"token is null or wrong"}
            JSONObject res = new JSONObject();
            res.put("state","false");
            res.put("msg","token is null or wrong");
            out = response.getWriter();
            out.append(res.toString());
            return false;
        }
        // 否則返回true 進入controller
        return true;
    }
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

2、載入攔截器

將以下代碼寫在InterceptorConfig.java中 ,使用addInterceptors方法將我們定義的攔截器添加進入項目中
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;

@Configuration
public class InterceptorConfig  implements WebMvcConfigurer {
    @Resource
    TokenInterceptor tokenInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 設置所有的路徑都要進行攔截,除了/test/login
        registry.addInterceptor(tokenInterceptor).addPathPatterns("/**")
                .excludePathPatterns("/test/login");
    }
}

3、測試成功

將如下代碼到TestController中,用於測試攔截器效果
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;

@RestController
// canload用於檢測攔截器是否正常工作
@RequestMapping("/test")
public class TestController {
    @RequestMapping(value = "/canload")
    public Map<String, Object> canLoad(){
        Map<String, Object> res = new HashMap<>();
        res.put("state", "ok");
        res.put("msg", "you can load");
        return res;
    }
    // login模擬登錄時token返回
    @RequestMapping(value = "/login")
    public String login(){
        return "111";
    }
}

可以看到如下結果
①直接登錄成功
直接登錄成功

②直接訪問canload失敗
直接訪問canload

③使用postman,帶上token進行訪問成功
帶上token進行訪問

4、使用注解(Annotation)進行選擇

你也可以使用注解來代替第三步配置中的excludePathPatterns(), 來實現對於指定方法和controller的免token訪問,新建一個NoNeedToken.java注解,在攔截器里判斷注解存在時,直接return true放行

NoNeedToken.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE}) //注解的范圍是類、接口、枚舉的方法上
@Retention(RetentionPolicy.RUNTIME)//被虛擬機保存,可用反射機制讀取
public @interface NoNeedToken {
}

響應的更改自定義攔截器的 preHandle方法,和攔截器配置

① 自定義攔截器

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    response.setCharacterEncoding("UTF-8");
    response.setContentType("application/json; charset=utf-8");
    String token = request.getHeader("token");
    PrintWriter out;
    // 對於注解的判斷---------------------------------------------------
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    if(handlerMethod.getMethodAnnotation(NoNeedToken.class)!=null || handlerMethod.getBeanType().isAnnotationPresent(NoNeedToken.class)){
        // 如果自己擁有NoNeedToken標注或者所屬的class擁有NoNeedToken 就直接放行
        return true;
    }
    //------------------------------------------------------------------
    if (token == null || !tokenList.contains(token)) {
        JSONObject res = new JSONObject();
        res.put("state","false");
        res.put("msg","token is null or wrong");
        out = response.getWriter();
        out.append(res.toString());
        return false;
    }
    return true;
}

② 去除攔截器配置中的去除項

public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
            // .excludePathPatterns("/test/login");
}

③ 在測試的login方法上添加注釋

@RequestMapping(value = "/login")
@NoNeedToken
public String login(){
    return "111";
}

修改完成之后效果和上面相同

5、常見問題

1.這個自定義注解的哪些@Target,@Retention,@Documented是什么意思

https://blog.csdn.net/zt15732625878/article/details/100061528,這篇文章寫的很詳細了

2.為什么我的注解加了,還是被攔截了

一般出現這種情況是類與方法的獲取注解方式不同,在本文中作者使用了下面的一句話來表述

handlerMethod.getMethodAnnotation(NoNeedToken.class)!=null || handlerMethod.getBeanType().isAnnotationPresent(NoNeedToken.class)

其中handlerMethod.getMethodAnnotation(NoNeedToken.class)!=null是對於方法的
handlerMethod.getBeanType().isAnnotationPresent(NoNeedToken.class)是對於類的

結語:希望對大家有幫助


免責聲明!

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



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