java註解
從 JDK 5開始,Java 增加了註解的新功能,註解其實是程式碼裡面的特殊標記,這些標記可以在編譯、類載入和執行時被讀取,在不改變程式碼原有邏輯下,給原始檔嵌入註解資訊。再通過返回獲取註解資訊,根據不同的註解資訊處理不同邏輯。其中 Java 有以下幾個元Annotation:
@Retention
@Retention修飾 Annotation 可以保留多長時間,只包含一個 RetentionPolicy 一個成員變數。
- RetentionPolicy.CLASS 預設值,編譯器把 Annotation 記錄在 class 檔案中。當執行 Java 程式時,JVM 不能獲取 Annotation 資訊。
- RetentionPolicy.RUNTIME 編譯器把 Annotation 記錄在 class 檔案中,當執行 Java 程式時,JVM 可以獲取 Annotation 資訊,可以通過反射獲取 Annotation 資訊,自定義註解使用此變數比較多。
- RetentionPolicy.SOURCE Annotation 只保留在原始碼(也就是 Java 檔案),編譯器直接拋棄 Annotation。
@Target
@Target 修飾一個 Annotation 定義,它表示 Annotation 可以修飾在哪些地方:
- ElementType.TYPE 類、介面以及列舉
- ElementType.FIELD 成員變數
- ElementType.METHOD 方法
- ElementType.PARAMETER 包定義
- ElementType.CONSTRUCTOR 構造器
- ElementType.ANNOTATION_TYPE Annotation
- ElementType.PARAMETER 引數
登入註解 @Logined
註解需求
以電商系統舉例,請求後端介面分成兩類:需要登入後才能訪問和不需要登入訪問,所以就需要根據不同的需求做不同的處理,不需要登入的訪問的介面不用做處理,而需要登入的介面需要在每次請求時驗證請求,而在 Spring 可以使用攔截器作一個登入資訊驗證,而是否需要登入驗證,這就需要用到註解了。
首先建立一個註解 @Logined,它要實現的功能:在需要登入才能訪問的介面上新增該註解,可以新增在類和方法上,如果新增在類上,類下面所以的請求方法都需要進行登入驗證。新增到方法上,只針對該方法需要驗證。@Logined 註解定義如下:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Logined {
/**
* 是否需要已經登入才允許訪問
*
* @return
*/
boolean isLogined() default true;
}
其中 @Target 設定 ElementType.METHOD 和 ElementType.TYPE 表示註解可以修飾在類和方法上,@Retention 設定 RetentionPolicy.RUNTIME 需要在執行時,JVM 可以獲取到註解資訊。isLogined 是註解的一個成員變數,這個在後面會講到。
首先定義一個 Controller 控制器:
@RestController
@Logined
public class TestController {
@GetMapping("/login")
public String login() {
return "need login";
}
}
在攔截器上獲取 @Logined 註解
每次傳送一個 http 請求後,都會進入到攔截器中。
public class MyInterceptor extends HandlerInterceptorAdapter{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (!(handler instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
boolean isLogin = this.isLogin(method);
if (!isLogin){
return true;
}
// 這裡對登入資訊驗證,比如token驗證,cookie驗證
return true;
}
private boolean isLogin(Method method) {
//獲取方法頭部值
Logined classLogined = method.getDeclaringClass().getAnnotation(Logined.class);
Logined methodLogined = method.getAnnotation(Logined.class);
// 如果方法上有註解返回 isLogined
if (classLogined != null && methodLogined == null) {
System.out.println(classLogined.isLogined());
return classLogined.isLogined();
}
// 方法沒有註解,再找類上註解
if ((classLogined != null && methodLogined != null) || (classLogined == null && methodLogined != null)) {
return methodLogined.isLogined();
}
return false;
}
}
攔截器流程:
- 獲取請求類對應的方法
- 通過反射找到方法上的 @Logined 註解,和類上的 @Logined 註解
- 如果類上有 @Logined 註解,方法上沒有 @Logined 註解,返回類 @Logined 註解的 isLogined
- 如果類和方法都有 @Logined 註解或者類沒有 @Logined 方法有註解,返回方法的 isLogined
經過上述判斷,如果返回是false,就不進行後續登入資訊驗證,否則需要登入資訊驗證。登入資訊驗證可以 token 驗證、cookie驗證。
總結
- 在需要請求的介面類或者方法上新增 @Logined,表明需要改請求介面需要登入後才能訪問。如果不需要就不新增,如果類新增了,而某個方法不需要登入才能訪問,新增 @Logined(isLogined = false) 即可。
- 在攔截器裡面獲取類或者方法的註解,如果有註解,則需要登入驗證,如果沒有,就直接通過。
如果覺得文章對你有幫助的話,請點個推薦吧!