Spring——自定义注解

分手后的思念是犯贱 2024-04-17 22:26 156阅读 0赞

1.参数注解

  • 注解

    /**

    • 字段参数注解
      *
    • @author A.keung
    • 2019/8/30 0030
    • @Constraint 通过使用validatedBy指定与注解关联的验证器
      */
      @Target(ElementType.FIELD)
      @Retention(RetentionPolicy.RUNTIME)
      @Constraint(validatedBy = ParamsCheckConstraintValidator.class)
      public @interface ParamsCheck {
      //参数
      String[] paramValues();

      //提示
      String message() default “params error”;

      Class<?>[] groups() default {};

      Class<? extends Payload>[] payload() default {};
      }

  • 验证器

    /**

    • 字段参数注解验证器
      *
    • @author A.keung
    • 2019/8/30 0030
      */
      public class ParamsCheckConstraintValidator implements ConstraintValidator {
      //注解参数
      private List paramValues;

      @Override
      public void initialize(ParamsCheck paramsCheck) {

      1. //初始化时获取注解上的值
      2. paramValues = Arrays.asList(paramsCheck.paramValues());

      }

      @Override
      public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {

      1. return paramValues.contains(o);

      }
      }

  • 测试

    @RequestMapping(value = “testParamsCheck”,method = RequestMethod.POST)

    1. public String testParamsCheck(@Validated @RequestBody User user) {
    2. log.info(JSON.toJSONString(user));
    3. return "OK";
    4. }

    @Data
    @EqualsAndHashCode(callSuper = true)
    @ToString(callSuper = true)
    @TableName(“t_user”)
    @NoArgsConstructor
    //@AllArgsConstructor
    public class User extends BaseEntity{

    1. /**
    2. * 密码
    3. */
    4. @TableField("password")
    5. private String password;
    6. /**
    7. * 手机
    8. */
    9. @TableField("phone_number")
    10. private String phoneNumber;
    11. /**
    12. * 邮箱
    13. */
    14. @TableField("email")
    15. private String email;
    16. /**
    17. * 昵称
    18. */
    19. @TableField("nickname")
    20. private String nickname;
    21. /**
    22. * 权限
    23. */
    24. @ParamsCheck(paramValues = {"ADMIN","USER"})
    25. @TableField("role")
    26. private String role;
    27. /**
    28. * qqOpenId
    29. */
    30. @TableField("qq_open_id")
    31. private String qqOpenId;
    32. /**
    33. * 头像地址
    34. */
    35. @TableField("figure_url")
    36. private String figureUrl;
    37. /**
    38. * 是否启用
    39. */
    40. @TableField("enable")
    41. private Boolean enable;
    42. private User(Builder builder) {
    43. setId(builder.id);
    44. setCreatedDatetime(builder.createdDatetime);
    45. setModifiedDatetime(builder.modifiedDatetime);
    46. setPassword(builder.password);
    47. setPhoneNumber(builder.phoneNumber);
    48. setEmail(builder.email);
    49. setNickname(builder.nickname);
    50. setRole(builder.role);
    51. setQqOpenId(builder.qqOpenId);
    52. setFigureUrl(builder.figureUrl);
    53. setEnable(builder.enable);
    54. }
  1. public static final class Builder {
  2. private Long id;
  3. private Date createdDatetime;
  4. private Date modifiedDatetime;
  5. private String password;
  6. private String phoneNumber;
  7. private String email;
  8. private String nickname;
  9. private String role;
  10. private String qqOpenId;
  11. private String figureUrl;
  12. private Boolean enable;
  13. public Builder() {
  14. }
  15. public Builder id(Long val) {
  16. id = val;
  17. return this;
  18. }
  19. public Builder createdDatetime(Date val) {
  20. createdDatetime = val;
  21. return this;
  22. }
  23. public Builder modifiedDatetime(Date val) {
  24. modifiedDatetime = val;
  25. return this;
  26. }
  27. public Builder password(String val) {
  28. password = val;
  29. return this;
  30. }
  31. public Builder phoneNumber(String val) {
  32. phoneNumber = val;
  33. return this;
  34. }
  35. public Builder email(String val) {
  36. email = val;
  37. return this;
  38. }
  39. public Builder nickname(String val) {
  40. nickname = val;
  41. return this;
  42. }
  43. public Builder role(String val) {
  44. role = val;
  45. return this;
  46. }
  47. public Builder qqOpenId(String val) {
  48. qqOpenId = val;
  49. return this;
  50. }
  51. public Builder figureUrl(String val) {
  52. figureUrl = val;
  53. return this;
  54. }
  55. public Builder enable(Boolean val) {
  56. enable = val;
  57. return this;
  58. }
  59. public User build() {
  60. return new User(this);
  61. }
  62. }
  63. }

" class="reference-link">watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MjAzMjE5OQ_size_16_color_FFFFFF_t_70

2.缓存注解

  • 注解

    /**

    • 部门缓存注解
      *
    • @author A.keung
    • 2019/8/30 0030
      */
      @Target({ElementType.METHOD, ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      public @interface DeptCache {
      //#user.name或jack
      String keyExpr();
      }
  • 切面

    /**

    • 部门缓存切面
      *
    • @author A.keung
    • 2019/8/30 0030
      */
      @Component
      @Aspect
      @Slf4j
      public class DeptCacheAspect {

      /**

      • 对含有注解的方法进行处理
        *
      • @param joinPoint
      • @return 返回值
        */
        @Around(“@annotation(com.ak.common.DeptCache)”)
        public Object process(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {
        Object result = null;
        // 获取切入的方法对象
        // 代理对象的,没有包含注解
        Method m = ((MethodSignature) joinPoint.getSignature()).getMethod();
        // 目标对象反射获取的method对象才包含注解
        Method methodWithAnnotations = joinPoint.getTarget().getClass().getDeclaredMethod(joinPoint.getSignature().getName(), m.getParameterTypes());
        // 根据目标方法对象获取注解对象
        DeptCache deptCache = methodWithAnnotations.getDeclaredAnnotation(DeptCache.class);
        // 解析key
        String keyExpr = deptCache.keyExpr();
        Object[] argValues = joinPoint.getArgs();
        String key = parseKey(methodWithAnnotations, argValues, keyExpr);
        //根据key查询缓存
        String cache = findCache(key);
        if (StringUtils.isNotBlank(cache)) {

        1. return cache;

        }
        //执行目标方法
        try {

        1. result = joinPoint.proceed();

        } catch (Throwable throwable) {

        1. throwable.printStackTrace();

        }
        return result;
        }

        /**

      • 解析key(只支持String)
        *
      • @param method
      • @param argValues 方法参数值
      • @param keyExpr 注解值或表达式(含#)
      • @return key
      • @throws IllegalAccessException
        */
        private String parseKey(Method method, Object[] argValues, String keyExpr) {
        if (keyExpr.startsWith(“#”)) {

        1. String[] exprParamNames = keyExpr.substring(keyExpr.indexOf('#') + 1).split("\\.");
        2. // 获取方法参数名列表
        3. LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
        4. String[] paramNames = discoverer.getParameterNames(method);
        5. Object argValue = null;
        6. for (int i = 0; i < paramNames.length; i++) {
        7. if (paramNames[i].equals(exprParamNames[0])) {
        8. argValue = argValues[i];
        9. break;
        10. }
        11. }
        12. try {
        13. for (int i = 1; i < exprParamNames.length; i++) {
        14. argValue = dealArg(argValue, exprParamNames[i]);
        15. }
        16. if (argValue instanceof String) {
        17. return (String) argValue;
        18. }
        19. } catch (IllegalAccessException e) {
        20. log.info("keyExpr:{}" + keyExpr);
        21. throw new RuntimeException("无法解析表达式:" + e.getMessage());
        22. }
        23. throw new RuntimeException("无法解析表达式");

        } else {

        1. return keyExpr;

        }
        }

        private Object dealArg(Object object, String fieldName) throws IllegalAccessException {
        if (object == null) {

        1. return null;

        }
        Class clazz = object.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {

        1. //属性可见
        2. field.setAccessible(true);
        3. if (fieldName.equals(field.getName())) {
        4. return field.get(object);
        5. }

        }
        return null;
        }

  1. private String findCache(String key) {
  2. double k = Math.random();
  3. log.info("k======"+k);
  4. if (k < 0.5) {
  5. return key + "_lt_0.5";
  6. }
  7. return null;
  8. }

20190902141617392.png

  • 测试

    @RequestMapping(value = “testDeptCache”,method = RequestMethod.GET)

    1. @DeptCache(keyExpr = "#user.nickname")
    2. public String testDeptCache(User user) {
    3. return "OK";
    4. }

" class="reference-link">20190902140953905.png

3.权限注解

  • 注解

    /**

    • 权限注解
      *
    • @author A.keung
    • 2019/8/30 0030
      */
      @Target({ ElementType.METHOD, ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      public @interface PermissionCheck {
      String[] values() default {};
      }
  • 拦截器

    /**

    • 权限注解拦截器
      *
    • @author A.keung
    • 2019/8/30 0030
      */
      public class PermissionCheckInterceptor extends HandlerInterceptorAdapter {
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

      1. if (!handler.getClass().isAssignableFrom(HandlerMethod.class)) {
      2. return true;
      3. }
      4. PermissionCheck permission = findPermissionCheck((HandlerMethod) handler);
      5. //无权限注解
      6. if (permission == null) {
      7. return true;
      8. }
      9. //获取注解中的值
      10. String[] values = permission.values();
      11. //获取用户权限
      12. Map<String, String> userPermission = findUserPermission();
      13. for (String value : values) {
      14. if (userPermission.containsKey(value)) {
      15. return true;
      16. }
      17. }
      18. throw new Exception("No Permission");

      }

      /**

      • 模拟获取权限集
        *
      • @return 权限集
        */
        private Map findUserPermission() {
        Map permissionMap = new HashMap<>();
        permissionMap.put(“SELECT”, “”);
        permissionMap.put(“UPDATE”, “”);
        permissionMap.put(“DELETE”, “”);
        return permissionMap;
        }

        /**

      • 获取注解信息
        *
      • @param handlerMethod 方法对象
      • @return PermissionCheck注解
        */
        private PermissionCheck findPermissionCheck(HandlerMethod handlerMethod) {
        //方法上注解
        PermissionCheck permission = handlerMethod.getMethodAnnotation(PermissionCheck.class);
        if (permission == null) {
        1. //类上注解
        2. permission = handlerMethod.getBeanType().getAnnotation(PermissionCheck.class);
        }
        return permission;
        }

    }

  • 配置

    /**

    • Mvc配置类
    • 在SpringBoot2.0之后的版本中WebMvcConfigurerAdapter过时了
    • 采用以下方式:
    • 1.继承WebMvcConfigurationSupport类
    • 静态资源的访问的问题,在静态资源的访问的过程中,
    • SpringBoot中的自动的配置会失效,不需要返回逻辑视图,可以选择继承此类
    • 继承WebMvcConfigurationSupport,若多个类继承该类,只会有一个类中的重写的方法执行
    • 2.实现WebMvcConfigurer接口
    • @author A.keung
    • 2019/8/30 0030
      */
      @Configuration
      public class WebMvcConfig implements WebMvcConfigurer {

      @Override
      public void addInterceptors(InterceptorRegistry interceptorRegistry) {

      1. interceptorRegistry.addInterceptor(new PermissionCheckInterceptor())
      2. .addPathPatterns("/**")
      3. .excludePathPatterns("/index/**","/api/login");

      }

      @Override
      public void configurePathMatch(PathMatchConfigurer pathMatchConfigurer) {

      }

      @Override
      public void configureContentNegotiation(ContentNegotiationConfigurer contentNegotiationConfigurer) {

      }

      @Override
      public void configureAsyncSupport(AsyncSupportConfigurer asyncSupportConfigurer) {

      }

      @Override
      public void configureDefaultServletHandling(DefaultServletHandlerConfigurer defaultServletHandlerConfigurer) {

      }

      @Override
      public void addFormatters(FormatterRegistry formatterRegistry) {

      }

      @Override
      public void addResourceHandlers(ResourceHandlerRegistry resourceHandlerRegistry) {

      }

      @Override
      public void addCorsMappings(CorsRegistry corsRegistry) {

      }

      @Override
      public void addViewControllers(ViewControllerRegistry viewControllerRegistry) {

      }

      @Override
      public void configureViewResolvers(ViewResolverRegistry viewResolverRegistry) {

      }

      @Override
      public void addArgumentResolvers(List list) {

      }

      @Override
      public void addReturnValueHandlers(List list) {

      }

      @Override
      public void configureMessageConverters(List> list) {

      }

      @Override
      public void extendMessageConverters(List> list) {

      }

      @Override
      public void configureHandlerExceptionResolvers(List list) {

      }

      @Override
      public void extendHandlerExceptionResolvers(List list) {

      }

      @Override
      public Validator getValidator() {

      1. return null;

      }

      @Override
      public MessageCodesResolver getMessageCodesResolver() {

      1. return null;

      }
      }

  • 测试

    @PermissionCheck(values = “SELECT”)

    1. @RequestMapping(value = "testPermissionCheck",method = RequestMethod.GET)
    2. public String testPermissionCheck() {
    3. return "OK";
    4. }

20190902141410893.png

发表评论

表情:
评论列表 (有 0 条评论,156人围观)

还没有评论,来说两句吧...

相关阅读

    相关 spring定义注解

    编程思想:垂直化编程,就是A—B---C—D…等执行下去,一个逻辑一个逻辑完了再执行下一个,但是spring 中AOP提供了一种思想,它的作用就是,当在业务不知情的情况下,对业

    相关 spring 定义注解

    在Java中创建自定义注解 创建自定义注解与编写接口很相似,除了它的接口关键字前有个@符号。我们可以在注解中定义方法,示例如下: package com.xxx.co