自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[354020]]

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

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

字段注解

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

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

自定義注解

定義一個(gè)@Check注解,通過@interface聲明一個(gè)注解 

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

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

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

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

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

ElementType.PARAMETER:說明該注解只能被聲明在一個(gè)方法參數(shù)前。

ElementType.CONSTRUCTOR:說明該注解只能聲明在一個(gè)類的構(gòu)造方法前。

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

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

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

@Constraint 通過使用validatedBy來指定與注解關(guān)聯(lián)的驗(yàn)證器

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

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

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

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

驗(yàn)證器類

驗(yàn)證器類需要實(shí)現(xiàn)ConstraintValidator泛型接口 

  1. public class ParamConstraintValidated implements ConstraintValidator<Check, Object> {  
  2.     /**  
  3.      * 合法的參數(shù)值,從注解中獲取  
  4.      * */  
  5.     private List<String> paramValues;  
  6.     @Override  
  7.     public void initialize(Check constraintAnnotation) {  
  8.         //初始化時(shí)獲取注解上的值  
  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.         //不在指定的參數(shù)列表中  
  16.         return false;  
  17.     }  

第一個(gè)泛型參數(shù)類型Check:注解,第二個(gè)泛型參數(shù)Object:校驗(yàn)字段類型。需要實(shí)現(xiàn)initialize和isValid方法,isValid方法為校驗(yàn)邏輯,initialize方法初始化工作

使用方式

定義一個(gè)實(shí)體類 

  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;  

對(duì)sex字段加校驗(yàn),其值必須為woman或者man

測(cè)試 

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

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

方法、類注解

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

這時(shí)候我們可以自定義注解去完成這個(gè)要求,第一個(gè)場(chǎng)景就是定義一個(gè)權(quán)限校驗(yàn)的注解,第二個(gè)場(chǎng)景就是定義spring-data-redis包下類似@Cacheable的注解。

權(quán)限注解

自定義注解 

  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.      * 處理器處理之前調(diào)用  
  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.         //如果沒有添加權(quán)限注解則直接跳過允許訪問  
  11.         if (permission == null) {  
  12.             return true;  
  13.         }  
  14.         //獲取注解中的值  
  15.         String resourceKey = permission.resourceKey();  
  16.         //TODO 權(quán)限校驗(yàn)一般需要獲取用戶信息,通過查詢數(shù)據(jù)庫(kù)進(jìn)行權(quán)限校驗(yàn)  
  17.         //TODO 這里只進(jìn)行簡(jiǎn)單演示,如果resourceKey為testKey則校驗(yàn)通過,否則不通過  
  18.         if ("testKey".equals(resourceKey)) {  
  19.             return true;  
  20.         }  
  21.         return false;  
  22.     }  
  23.     /**  
  24.      * 根據(jù)handlerMethod返回注解信息  
  25.      *  
  26.      * @param handlerMethod 方法對(duì)象  
  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.     }  

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

測(cè)試 

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

該方法需要進(jìn)行權(quán)限校驗(yàn)所以添加了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.      * 在方法執(zhí)行之前對(duì)注解進(jìn)行處理  
  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 業(yè)務(wù)場(chǎng)景會(huì)比這個(gè)復(fù)雜的多,會(huì)涉及參數(shù)的解析如key可能是#{id}這些,數(shù)據(jù)查詢  
  18.         //TODO 這里做簡(jiǎn)單演示,如果key為testKey則返回hello world  
  19.         if ("testKey".equals(customCache.key())) {  
  20.             return "hello word";  
  21.         }   
  22.         //執(zhí)行目標(biāo)方法  
  23.         try {  
  24.             result = pjd.proceed();  
  25.         } catch (Throwable throwable) {  
  26.             throwable.printStackTrace();  
  27.         }  
  28.         return result;  
  29.     }  

因?yàn)榫彺孀⒔庑枰诜椒▓?zhí)行之前有返回值,所以沒有通過攔截器處理這個(gè)注解,而是通過使用切面在執(zhí)行方法之前對(duì)注解進(jìn)行處理。

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

測(cè)試 

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

 

責(zé)任編輯:龐桂玉 來源: 民工哥技術(shù)之路
相關(guān)推薦

2024-10-14 17:18:27

2017-08-03 17:00:54

Springmvc任務(wù)執(zhí)行器

2023-10-11 07:57:23

springboot微服務(wù)

2023-10-24 13:48:50

自定義注解舉值驗(yàn)證

2011-12-26 10:11:08

JSP

2023-10-23 08:18:50

掃描SpringBean

2024-12-27 15:37:23

2021-12-07 18:23:50

自定義進(jìn)度條分段式

2020-11-12 08:41:35

Linux系統(tǒng)

2021-12-30 12:30:01

Java注解編譯器

2021-05-19 08:20:59

ViewGrouplayout作用

2022-11-10 07:53:54

Spring參數(shù)校驗(yàn)

2022-11-01 11:15:56

接口策略模式

2022-02-17 07:10:39

Nest自定義注解

2024-07-02 11:42:53

SpringRedis自定義

2024-10-09 10:46:41

springboot緩存redis

2021-02-20 11:40:35

SpringBoot占位符開發(fā)技術(shù)

2023-10-09 07:37:01

2025-03-13 07:33:46

Spring項(xiàng)目開發(fā)

2009-08-05 17:03:37

C#自定義控件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)