关于自定义注释的Spring REST验证

时间:2016-05-28 14:41:32

标签: java spring validation spring-mvc jsr

我尝试使用注释在我的REST bean上添加一些额外的验证逻辑。这只是一个示例,但重点是注释将用于多个REST资源对象/ DTO。

我希望得到这样的解决方案:

public class Entity {

    @NotNull // JSR-303
    private String name;

    @Phone // Custom phonenumber that has to exist in a database
    private String phoneNumber;
}

@Component
public class PhoneNumberValidator implements Validator { // Spring Validator

    @Autowired
    private PhoneRepository repository;

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

    public void validate(Object target, Errors errors) {
        Phone annotation = // find fields with annotations by iterating over target.getClass().getFields().getAnnotation
        Object fieldValue = // how do i do this? I can easily get the annotation, but now I wish to do a call to repository checking if the field value exists.
    }
}

2 个答案:

答案 0 :(得分:0)

您是否尝试过像hibernate验证器这样的JSR 303 bean验证器实现 例如可在此处http://www.codejava.net/frameworks/spring/spring-mvc-form-validation-example-with-bean-validation-api

答案 1 :(得分:0)

Maven模块A:

public interface RestValidator<A extends Annotation, T> extends ConstraintValidator<A, T>
public interface PhoneValidator extends RestValidator<PhoneNumber, String>

@Target(FIELD)
@Retention(RUNTIME)
@Constraint(validatedBy = PhoneValidator.class) // This usually doesnt work since its a interface
public @interface PhoneNumber {
   // JSR-303 required fields (payload, message, group)
}


public class Person {

@PhoneNumber
    private String phoneNumber;
}

Maven模块B:

@Bean
LocalValidatorFactoryBean configurationPropertiesValidator(ApplicationContext context, AutowireCapableBeanFactory factory) {
    LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean();
    factoryBean.setConstraintValidatorFactory(factory(context, factory));
    return factoryBean;
}

private ConstraintValidatorFactory factory(final ApplicationContext context, final AutowireCapableBeanFactory factory) {
    return new ConstraintValidatorFactory() {
        @Override
        public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
            if (RestValidator.class.isAssignableFrom(key)) {
                return context.getBean(key);
            } else {
                return factory.createBean(key);
            }
        }

        @Override
        public void releaseInstance(ConstraintValidator<?, ?> instance) {
            if (!(instance instanceof RestValidator<?, ?>)) {
                factory.destroyBean(instance);
            }
        }
    };
}

@Bean
WebMvcConfigurerAdapter webMvcConfigurerAdapter(final LocalValidatorFactoryBean validatorFactoryBean) {
    return new WebMvcConfigurerAdapter() {  // Adds the validator to MVC
        @Override
        public Validator getValidator() {
            return validatorFactoryBean;
        }
    };
}

然后我有一个PhoneValidator的@Component实现,它有一个Scope = Prototype。

我讨厌这个解决方案,我认为Spring默认情况下应该查看Interface实现,但我确信有些比我聪明的人决定不这样做。