本文介绍了带有额外信息的Bean验证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建UniqueName注释,作为用于创建项目api的定制bean验证注释:

I am trying to create a UniqueName annotation as a cutomize bean validation annotation for a create project api:

@PostMapping("/users/{userId}/projects")
public ResponseEntity createNewProject(@PathVariable("userId") String userId,
                                       @RequestBody @Valid ProjectParam projectParam) {
    User projectOwner = userRepository.ofId(userId).orElseThrow(ResourceNotFoundException::new);

    Project project = new Project(
        IdGenerator.nextId(),
        userId,
        projectParam.getName(),
        projectParam.getDescription()
    );
    ...
  }

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
class ProjectParam {

  @NotBlank
  @NameConstraint
  private String name;
  private String description;
}

@Constraint(validatedBy = UniqueProjectNameValidator.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD })
public @interface UniqueName {

    public String message() default "already existed";

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

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

public class UniqueProjectNameValidator implements ConstraintValidator<UniqueName, String> {
   @Autowired
   private ProjectQueryMapper mapper;

   public void initialize(UniqueName constraint) {
   }

   public boolean isValid(String value, ConstraintValidatorContext context) {
      // how can I get the userId info??
      return mapper.findByName(userId, value) == null;
   }
}

问题在于name字段仅需要用户级别的唯一性.因此,我需要从URL字段获取{userId}进行验证.但是如何将其添加到UniqueProjectNameValidator中?还是有一些更好的方法来处理此验证?这只是一个大对象的一小部分,实际对象在请求处理程序中还有许多其他复杂的验证,这些验证使代码很脏.

The problem is that name field just need uniqueness for user level. So I need to get the {userId} from the URL field for validation. But how can I add this into the UniqueProjectNameValidator? Or is there some better way to handle this validation? This is just a small part of a large object, the real object has many other complex validations in the request handler which make the code quite dirty.

推荐答案

如@Abhijeet所述,将userId属性动态传递到约束验证器是不可能的.至于如何更好地处理此验证案例,有干净的解决方案和肮脏的解决方案.

As @Abhijeet mentioned, dynamically passing the userId property to the constraint validator is impossible. As to how to handle this validation case better, there's the clean solution and the dirty solution.

干净的解决方案是将所有业务逻辑提取到服务方法中,并在服务级别上验证ProjectParam.这样,您可以在ProjectParam中添加userId属性,并在调用服务之前将其从@PathVariable映射到@RequestBody.然后,您调整UniqueProjectNameValidator以验证ProjectParam,而不是String.

The clean solution is to extract all the business logic to a service method, and validate the ProjectParam at the service level. This way, you can add a userId property to ProjectParam, and map it from the @PathVariable onto the @RequestBody before calling the service. You then adjust UniqueProjectNameValidator to validate ProjectParams rather than Strings.

肮脏的解决方案是使用Hibernate Validator的跨参数约束(另请参见此链接为例).实际上,您将这两个控制器方法参数都作为自定义验证器的输入.

The dirty solution is to use Hibernate Validator's cross-parameter constraints (see also this link for an example). You essentially treat both of your controller method parameters as the input for your custom validator.

这篇关于带有额外信息的Bean验证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 23:57