成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

Spring自定義注解玩法大全,從入門到…

開發 后端
在業務開發過程中我們會遇到形形色色的注解,但是框架自有的注解并不是總能滿足復雜的業務需求,我們可以自定義注解來滿足我們的需求。

[[354020]]

 在業務開發過程中我們會遇到形形色色的注解,但是框架自有的注解并不是總能滿足復雜的業務需求,我們可以自定義注解來滿足我們的需求。

根據注解使用的位置,文章將分成字段注解、方法、類注解來介紹自定義注解。

字段注解

字段注解一般是用于校驗字段是否滿足要求,hibernate-validate依賴就提供了很多校驗注解 ,如@NotNull、@Range等,但是這些注解并不是能夠滿足所有業務場景的。

比如我們希望傳入的參數在指定的String集合中,那么已有的注解就不能滿足需求了,需要自己實現。

自定義注解

定義一個@Check注解,通過@interface聲明一個注解 

  1. @Target({ ElementType.FIELD}) //只允許用在類的字段上  
  2. @Retention(RetentionPolicy.RUNTIME) //注解保留在程序運行期間,此時可以通過反射獲得定義在某個類上的所有注解  
  3. @Constraint(validatedBy = ParamConstraintValidated.class)  
  4. public @interface Check {  
  5.     /**  
  6.      * 合法的參數值  
  7.      * */  
  8.     String[] paramValues();  
  9.     /**  
  10.      * 提示信息  
  11.      * */  
  12.     String message() default "參數不為指定值";  
  13.     Class<?>[] groups() default {};  
  14.     Class<? extends Payload>[] payload() default {};  

@Target 定義注解的使用位置,用來說明該注解可以被聲明在那些元素之前。

ElementType.TYPE:說明該注解只能被聲明在一個類前。

ElementType.FIELD:說明該注解只能被聲明在一個類的字段前。

ElementType.METHOD:說明該注解只能被聲明在一個類的方法前。

ElementType.PARAMETER:說明該注解只能被聲明在一個方法參數前。

ElementType.CONSTRUCTOR:說明該注解只能聲明在一個類的構造方法前。

ElementType.LOCAL_VARIABLE:說明該注解只能聲明在一個局部變量前。

ElementType.ANNOTATION_TYPE:說明該注解只能聲明在一個注解類型前。

ElementType.PACKAGE:說明該注解只能聲明在一個包名前

@Constraint 通過使用validatedBy來指定與注解關聯的驗證器

@Retention 用來說明該注解類的生命周期。

RetentionPolicy.SOURCE: 注解只保留在源文件中 

RetentionPolicy.CLASS : 注解保留在class文件中,在加載到JVM虛擬機時丟棄

RetentionPolicy.RUNTIME: 注解保留在程序運行期間,此時可以通過反射獲得定義在某個類上的所有注解。

驗證器類

驗證器類需要實現ConstraintValidator泛型接口 

  1. public class ParamConstraintValidated implements ConstraintValidator<Check, Object> {  
  2.     /**  
  3.      * 合法的參數值,從注解中獲取  
  4.      * */  
  5.     private List<String> paramValues;  
  6.     @Override  
  7.     public void initialize(Check constraintAnnotation) {  
  8.         //初始化時獲取注解上的值  
  9.         paramValues = Arrays.asList(constraintAnnotation.paramValues());  
  10.     }  
  11.     public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {  
  12.         if (paramValues.contains(o)) {  
  13.             return true;  
  14.         }  
  15.         //不在指定的參數列表中  
  16.         return false;  
  17.     }  

第一個泛型參數類型Check:注解,第二個泛型參數Object:校驗字段類型。需要實現initialize和isValid方法,isValid方法為校驗邏輯,initialize方法初始化工作

使用方式

定義一個實體類 

  1. @Data  
  2. public class User {  
  3.     /**  
  4.      * 姓名  
  5.      * */  
  6.     private String name;  
  7.     /**  
  8.      * 性別 man or women  
  9.      * */  
  10.     @Check(paramValues = {"man", "woman"})  
  11.     private String sex;  

對sex字段加校驗,其值必須為woman或者man

測試 

  1. @RestController("/api/test")  
  2. public class TestController {  
  3.     @PostMapping  
  4.     public Object test(@Validated @RequestBody User user) {  
  5.         return "hello world";  
  6.     }  

注意需要在User對象上加上@Validated注解,這里也可以使用@Valid注解

方法、類注解

在開發過程中遇到過這樣的需求,如只有有權限的用戶的才能訪問這個類中的方法或某個具體的方法、查找數據的時候先不從數據庫查找,先從guava cache中查找,在從redis查找,最后查找mysql(多級緩存)。

這時候我們可以自定義注解去完成這個要求,第一個場景就是定義一個權限校驗的注解,第二個場景就是定義spring-data-redis包下類似@Cacheable的注解。

權限注解

自定義注解 

  1. @Target({ ElementType.METHOD, ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface PermissionCheck { 
  4.     /**  
  5.      * 資源key  
  6.      * */ 
  7.     String resourceKey();  

該注解的作用范圍為類或者方法上

攔截器類 

  1. public class PermissionCheckInterceptor extends HandlerInterceptorAdapter {  
  2.     /**  
  3.      * 處理器處理之前調用  
  4.      */  
  5.     @Override  
  6.     public boolean preHandle(HttpServletRequest request, HttpServletResponse response,  
  7.                              Object handler) throws Exception { 
  8.          HandlerMethod handlerMethod = (HandlerMethod)handler;  
  9.         PermissionCheck permission = findPermissionCheck(handlerMethod);  
  10.         //如果沒有添加權限注解則直接跳過允許訪問  
  11.         if (permission == null) {  
  12.             return true;  
  13.         }  
  14.         //獲取注解中的值  
  15.         String resourceKey = permission.resourceKey();  
  16.         //TODO 權限校驗一般需要獲取用戶信息,通過查詢數據庫進行權限校驗  
  17.         //TODO 這里只進行簡單演示,如果resourceKey為testKey則校驗通過,否則不通過  
  18.         if ("testKey".equals(resourceKey)) {  
  19.             return true;  
  20.         }  
  21.         return false;  
  22.     }  
  23.     /**  
  24.      * 根據handlerMethod返回注解信息  
  25.      *  
  26.      * @param handlerMethod 方法對象  
  27.      * @return PermissionCheck注解  
  28.      */  
  29.     private PermissionCheck findPermissionCheck(HandlerMethod handlerMethod) { 
  30.         //在方法上尋找注解  
  31.         PermissionCheck permission = handlerMethod.getMethodAnnotation(PermissionCheck.class);  
  32.         if (permission == null) {  
  33.             //在類上尋找注解  
  34.             permission = handlerMethod.getBeanType().getAnnotation(PermissionCheck.class);  
  35.         }  
  36.         return permission;  
  37.     }  

權限校驗的邏輯就是你有權限你就可以訪問,沒有就不允許訪問,本質其實就是一個攔截器。我們首先需要拿到注解,然后獲取注解上的字段進行校驗,校驗通過返回true,否則返回false

測試 

  1. @GetMapping("/api/test")  
  2.  @PermissionCheck(resourceKey = "test" 
  3.  public Object testPermissionCheck() {  
  4.      return "hello world";  
  5.  } 

該方法需要進行權限校驗所以添加了PermissionCheck注解。

緩存注解

自定義注解 

  1. @Target({ ElementType.METHOD, ElementType.TYPE})  
  2. @Retention(RetentionPolicy.RUNTIME)  
  3. public @interface CustomCache {  
  4.     /**  
  5.      * 緩存的key值  
  6.      * */  
  7.     String key();  

注解可以用在方法或類上,但是緩存注解一般是使用在方法上的。

切面 

  1. @Aspect  
  2. @Component  
  3. public class CustomCacheAspect {  
  4.     /**  
  5.      * 在方法執行之前對注解進行處理  
  6.      *  
  7.      * @param pjd  
  8.      * @param customCache 注解  
  9.      * @return 返回中的值  
  10.      * */  
  11.     @Around("@annotation(com.cqupt.annotation.CustomCache) && @annotation(customCache)")  
  12.     public Object dealProcess(ProceedingJoinPoint pjd, CustomCache customCache) {  
  13.         Object result = null 
  14.         if (customCache.key() == null) {  
  15.             //TODO throw error  
  16.         }  
  17.         //TODO 業務場景會比這個復雜的多,會涉及參數的解析如key可能是#{id}這些,數據查詢  
  18.         //TODO 這里做簡單演示,如果key為testKey則返回hello world  
  19.         if ("testKey".equals(customCache.key())) {  
  20.             return "hello word";  
  21.         }   
  22.         //執行目標方法  
  23.         try {  
  24.             result = pjd.proceed();  
  25.         } catch (Throwable throwable) {  
  26.             throwable.printStackTrace();  
  27.         }  
  28.         return result;  
  29.     }  

因為緩存注解需要在方法執行之前有返回值,所以沒有通過攔截器處理這個注解,而是通過使用切面在執行方法之前對注解進行處理。

如果注解沒有返回值,將會返回方法中的值

測試 

  1. @GetMapping("/api/cache")  
  2. @CustomCache(key = "test" 
  3. public Object testCustomCache() {  
  4.     return "don't hit cache";  
  5.  

 

責任編輯:龐桂玉 來源: 民工哥技術之路
相關推薦

2024-10-14 17:18:27

2017-08-03 17:00:54

Springmvc任務執行器

2020-11-12 08:41:35

Linux系統

2023-10-24 13:48:50

自定義注解舉值驗證

2023-10-11 07:57:23

springboot微服務

2011-12-26 10:11:08

JSP

2021-12-07 18:23:50

自定義進度條分段式

2023-10-23 08:18:50

掃描SpringBean

2024-12-27 15:37:23

2021-12-30 12:30:01

Java注解編譯器

2021-05-19 08:20:59

ViewGrouplayout作用

2022-11-10 07:53:54

Spring參數校驗

2023-10-09 07:37:01

2022-02-17 07:10:39

Nest自定義注解

2022-11-01 11:15:56

接口策略模式

2021-02-20 11:40:35

SpringBoot占位符開發技術

2024-10-09 10:46:41

springboot緩存redis

2024-07-02 11:42:53

SpringRedis自定義

2025-03-13 07:33:46

Spring項目開發

2009-08-05 17:03:37

C#自定義控件
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产一级大片 | 91成人在线视频 | 视频一区二区国产 | 日本一区二区高清不卡 | 成人在线播放网站 | 国产日韩欧美一区 | 亚洲在线一区 | 久久青草av | 成人网在线观看 | 中文字幕在线观看一区 | 国产成人精品久久 | 国产在线精品一区二区 | 亚洲精品一区二区网址 | 综合久久久 | 久久精品福利视频 | 男女下面一进一出网站 | 91九色在线观看 | 曰韩三级| 亚洲精品久久久一区二区三区 | 美女久久久久久久 | 99视频久| 日韩中文字幕一区 | 中文字幕在线三区 | 亚洲视频一区二区三区 | 在线中文视频 | 亚洲精品中文字幕在线观看 | 日韩毛片免费看 | 综合久久av | 亚洲精品在线视频 | 国产专区在线 | 免费激情网站 | 欧美精品一区三区 | 欧美日韩中文在线 | 欧美久久精品 | 精品国模一区二区三区欧美 | 久久午夜精品 | 中文字幕 欧美 日韩 | a久久 | 精品久久中文字幕 | 天堂一区二区三区 | 久久中文字幕电影 |