Java 中 Spring 如何实现注解根据不同类分别处理属性过滤逻辑?

查看 60|回复 8
作者:tiRolin   
目前我有一个 Spring 项目,该项目有一个请求如下所示
  @ApiOperation("用户提交报告")
  @PostMapping
  public ResponseDTO[B] save(@RequestBody @Valid AacmReportInsertBo aacmReportInsertBo) {
    aacmReportUserInfoService.save(aacmReportInsertBo);
    return ResponseDTO.ok();
  }
传入的对象 AacmReportInsertBo 拥有如下属性
@Data
public class AacmReportInsertBo {
  /**
   * 所属文书类型 (QUERY——查询,COMPLAINT——意见,REPORT——报告)
   */
  private String type;
  /**
   * 性别
   */
  private String sex;
  
  // 省略
}
这个请求的处理逻辑是根据传入的 type 返回相应的处理器,调用处理器中的 handle 方法来处理请求
  public void save(AacmReportInsertBo aacmReportInsertBo) {
    IReportHandler handler = ReportHandlerFactory.getReportHandlerService(ReportType.getType(aacmReportInsertBo.getType()));
    ReportHandlerErrorEnum.HANDLER_NULL_ERROR.isNull(handler);
    handler.handle(aacmReportInsertBo);
  }
我想要实现一个注解,注解名是 NotNull ,只能在属性中使用,用于保证该属性不为 Null ,但是同时我希望这个注解可以接收一个 Class 数组,数组中传入相应的处理器的 Class ,只有当该请求的处理器存在于 class 数组中时,才执行参数过滤的逻辑,否则不执行
比方说假如我有三个处理器类分别是 QueryHandler 、SecurityHandler 、OpinionComplainHandler ,现在我在我的 AacmReportInsertBo 中这样使用 NotNull 注解
@Data
public class AacmReportInsertBo {
  /**
   * 所属文书类型 (QUERY——查询,COMPLAINT——意见,REPORT——报告)
   */
  private String type;
  /**
   * 性别
   */
  @NotNull(groups = {QueryHandler.class,SecurityHandler.class})
  private String sex;
  
  // 省略
}
也就意味着我希望只有当我的本次请求的返回的处理器为 QueryHandler 或 SecurityHandler 时,才执行这个保证 sex 不为 null 的过滤行为,否则不执行这个过滤行为
我最开始想到了通过实现 ConstraintValidator 的方式来实现我的需求,但是使用这个方法虽然可以实现保证字段不为 Null ,但是不可以实现根据不同的处理器来判断过滤逻辑要不要执行,所以这个实现方案就 pass 了
@Constraint(validatedBy = NotNullAspect.class)
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NotNull {
  String message() default "该字段不能为空";
  Class[] groups() default {};
  Class[] payload() default {};
}
@Aspect
@Component
@NoArgsConstructor
public class NotNullAspect implements ConstraintValidator {
  @Override
  public boolean isValid(Object value, ConstraintValidatorContext context) {
    if(value == null){
      return false;
    }
    if(value instanceof String){
      return !((String) value).isEmpty();
    }
    return true;
   
    // 由于没有实现根据不同的处理器类来判断是否进行过滤操作的方案,因此该方法弃用
  }
}
然后我想到使用注解+AOP 的方式来实现我的需求,但是 AOP 提取代码好像又仅仅适用于注解用于修饰方法的情况,我用注解修饰属性并且写入对应的处理逻辑得到的结果是根本就不执行我的代码
@Target(ElementType.FIELD)
@Retention(RUNTIME)
public @interface NotNull {
  Class[] groups() default {};
}
@Aspect
@Component
@NoArgsConstructor
public class NotNullAspect {
  @Pointcut("@annotation(com.org.example.verification.NotNull) && execution(* org.example..*(..))")
  public void fieldNotNullPointCut() {
  }
  @Before("fieldNotNullPointCut()")
  public void before(JoinPoint joinPoint) throws Exception {
    Object target = joinPoint.getTarget();
    Class targetClass = target.getClass();
    String className = joinPoint.getTarget().getClass().getName();
    Class processorClass = Class.forName(className);
    for (Field field : targetClass.getDeclaredFields()) {
      NotNull annotation = field.getAnnotation(NotNull.class);
      if (annotation != null) {
        for (Class procClass : annotation.message()) {
          if (procClass.equals(processorClass)) {
            field.setAccessible(true);
            Object value = field.get(target);
            if (value == null || value.toString().isEmpty()) {
              throw new Exception();
            }
          }
        }
      }
    }
  }
}
上面的代码别说逻辑对不对了,根本就不会执行,打断点会发现这个请求根本不会到断点上
想问下各位有没有什么办法能实现我的需求?就给我一个大概思路就可以了,我会照着这个思路去做,现在最大的问题是我感觉我的思路就有问题导致我不知道该怎么实现我的需求好
guozi1117   
```java
public void save(AacmReportInsertBo aacmReportInsertBo) {
    IReportHandler handler = ReportHandlerFactory.getReportHandlerService(ReportType.getType(aacmReportInsertBo.getType()));
    handler.checkNull(aacmReportInsertBo);
    handler.handle(aacmReportInsertBo);
}
void checkNull(AacmReportInsertBo aacmReportInsertBo) {
  if(StringUtils.isBlank(aacmReportInsertBo.getSex())) {
    //do something
  }
  // 或者基于注解实现
}
```
tiRolin
OP
  
@guozi1117 我知道可以通过非注解的方式来实现我的需求,但是我就想知道基于注解应该要怎么实现,能不能实现这样的
Dream95   
用 javax.validation 包可以满足你的需求
YoungAD   
validated group 可以满足这个需求吧
jinxjhin   
validated group  https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/annotation/Validated.html
leogt   
切面作用的位置错了,增加一个注解让切面在这个方法切入 save(AacmReportInsertBo aacmReportInsertBo)。
在切面中获取参数 aacmReportInsertBo ,通过反射获取 sex 字段上 NotNull 注解的 groups ,拿到 group 就可以随便处理了。
bbchannails   
害怕, 你是框架的入门指导都不看的啊
cobbage   
注解无感化大部分都是代理实现的
您需要登录后才可以回帖 登录 | 立即注册

返回顶部