Spring Boot Rest端点中的JSR 303 Bean验证自定义约束

时间:2016-04-15 17:10:14

标签: java spring-boot bean-validation

我有一个Spring启动应用程序服务一些REST端点。我正在尝试围绕过滤器,分页,排序等创建一些可重用的逻辑。

对于PagingInfoDto对象,我正在包装限制和偏移请求参数。

我正在做一些bean验证,以确保限制和偏移满足一些cusomt规则。

当我像这样实现它时,一切正常:

控制器:

 @RequestMapping(value = "/somevalue", method = RequestMethod.GET)
 public ResponseEntity<Object> list (
        @Valid PagingInfoDto pagingInfoDto){

PagingInfoDto:

@Paging(limitDefault = 2)
public class PagingInfoDto
{
   private boolean hasMore;

   private Integer offset;

   private Integer limit;

   public Integer getOffset() {
    return offset;
   }

   public void setOffset(Integer offset) {
    this.offset = offset;
   }

   public Integer getLimit() {
    return limit;
   }

   public void setLimit(Integer limit) {
    this.limit = limit;
   }

    public boolean isHasMore()
    {
        return hasMore;
    }

    public void setHasMore(boolean hasMore)
    {
        this.hasMore = hasMore;
    }

}

PagingRequestFiltervalidator:

public class PagingRequestFilterValidator implements ConstraintValidator<Paging, PagingRequestFilterDto> {

    private static final String MISSING_OFFSET = "offset cannot appear without limit";
    private static final String ZERO_LIMIT = "limit cannot be 0";
    private static final String MISSING_LIMIT = "limit cannot appear without offset";


    private int limit = 0;
    @Override
    public void initialize(Paging paging) {
        this.limit = paging.limitDefault();
    }

    @Override
    public boolean isValid(PagingRequestFilterDto pagingRequestFilterDto, ConstraintValidatorContext constraintValidatorContext) {
        boolean validity = true;
        constraintValidatorContext.disableDefaultConstraintViolation();
        /**
         * Offset has to be greater than or equal to Zero
         */
        if(pagingRequestFilterDto.getOffset() == null) {
            pagingRequestFilterDto.setOffset(0);
        }

        /**
         * Set undefined or invalid limit to default to value from the annotation
         */
        if(pagingRequestFilterDto.getLimit() == null
            || pagingRequestFilterDto.getLimit() > limit) {

            pagingRequestFilterDto.setLimit(limit);
        }

分页注释:

@Constraint(validatedBy = {PagingRequestFilterValidator.class})
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.TYPE, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Paging {
    String message() default "Invalid Paging Details";

    int limitDefault() default 20;

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

我希望能够做的是使用@Paging Custom Constraint注释参数PagingInfoDto参数,以便每个端点都可以设置它自己的limitDefault。

像这样:

 @RequestMapping(value = "/somevalue", method = RequestMethod.GET)
     public ResponseEntity<Object> list (

            **@Paging(limitDefault = 2)** PagingInfoDto pagingInfoDto){ ...


 @RequestMapping(value = "/someothervalue", method = RequestMethod.GET)
     public ResponseEntity<Object> otherlist (

            **@Paging(limitDefault = 5)** PagingInfoDto pagingInfoDto){...

以上内容不会激活对象的验证。我觉得这很简单,因为我错过了一些非常明显的东西......

我发现了一篇博文,似乎表明您需要实现自定义Bean验证器:

http://blog.trifork.com/2009/08/04/bean-validation-integrating-jsr-303-with-spring/

我的实施

@Component
public class BeanValidator implements org.springframework.validation.Validator, InitializingBean {

    private Validator validator;

    public void afterPropertiesSet() throws Exception {
        ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
        validator = validatorFactory.usingContext().getValidator();
    }

    public boolean supports(Class clazz) {
        return true;
    }

    public void validate(Object target, Errors errors) {
        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(target);
        for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
            String propertyPath = constraintViolation.getPropertyPath().toString();
            String message = constraintViolation.getMessage();
            errors.rejectValue(propertyPath, "", message);
        }
    }
}

仍然没有运气。

0 个答案:

没有答案