Spring 3 - 基于注解的 Bean 验证

Spring 3 - Annotation based Bean Validation

我正在构建 REST API。它由一个资源(@Controller)组成,即使其中一个必填字段不存在,它 returns 也会响应 204。

我正在使用 Spring 3.1,validation-api (1.1.0.Final) & Hibernate-validator(4.3.0)。不确定 Hibernate-validator 在这里是否起作用。

 <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.0.Final</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.validation</groupId>
                    <artifactId>validation-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

我有一个 spring 控制器 @Controller 和一个带 @Component 的 Bean

  @POST
        @Consumes(value = {MediaType.APPLICATION_JSON})
        @Produces(value = {MediaType.APPLICATION_JSON})
        @RequestMapping(method = RequestMethod.POST)
        public Response addUserData(@Valid @RequestBody UserData userDataRequest) throws ResourceException {
    ...
    }

我的 UserData bean 有

  @Component 
    public class UserData {

        @NotNull(message = "user ID should not be null")
        @Min(value = 1, message = "user ID should not be empty")
        @Max(value = 20, message = "user ID should have length of more than 20")
        @Pattern(regexp="[A-Z][a-z]+", message = "Only Alphanumeric characters allowed")
        private String userId;

    }

我的验证没有被执行。当我不通过 "userId" 时,不会抛出任何错误。我在这里错过了什么?

可能会向您的 "addUserData" 方法传递一个 bindingResult 对象,以便您可以测试和检索验证错误。 这是一个如何使用它的例子:Validation form input

您必须具备以下有关基础设施的信息

@EnableWebMvc
@Configuration
public class WebMvcConfig extends WebMvcConfigurerAdapter {

    ...

    @Autowired
    private ValidatorConfig validatorConfig;

    ...

    @Override
    public Validator getValidator() {
        return validatorConfig.localValidatorFactoryBean();
    }

    ...

}

validatorConfig 的来源

@Configuration
public class ValidatorConfig {

    @Autowired
    private ReloadableResourceBundleMessageSource rrbms;

    @Bean
    public LocalValidatorFactoryBean localValidatorFactoryBean(){
        LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
        localValidatorFactoryBean.setValidationMessageSource(rrbms);
        return localValidatorFactoryBean;
    }

}

最后(我建议您考虑将错误消息放在 .properties 文件中,例如 validation.properties 如下所示)

@Configuration
public class MessageSourceConfig {

    @Bean(name="messageSource")
    public ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource() {
        ReloadableResourceBundleMessageSource resource = new ReloadableResourceBundleMessageSource();
        resource.setBasenames("classpath:/com/manuel/jordan/somethinga",
                              "classpath:/com/manuel/jordan/validation/validation");
        resource.setDefaultEncoding("UTF-8");
        return resource;
    }

}

一些考虑或建议:

  • @Valid更改为@Validated@Validated见API)
  • 删除 UserData@Component(代表一种实体,对吗?)。请记住,对于 class 每个实例都是唯一的 由 Spring 管理的任何 beanSingleton.
  • 将错误消息放入 .properties 文件
  • @POST@Consumes@Produces 注释从何而来?。他们不在 Spring API

补充 01 关于您的评论:

  • 是的,你必须使用@EnableWebMVC。它指示 Spring 在内部为 Web 环境创建一些特殊的 bean。参见 @EnableWebMVC API。注释很重要。即使是休息,我也使用该注释。

  • 关于Rest注解,使用Spring注解。如@RequestMapping和新的'variations'如@GetMapping@PostMapping等。即注解包含producesconsumes属性。我从未见过您混合两组来自 Rest 的注释的方法。

加法02

WebMvcConfigurerAdapter class 表示有关所有 Spring MVC 基础设施的 XML 配置文件

因此 XML

  • @EnableWebMvc等价于<mvc:annotation-driven/>
  • 关于验证应该是:<mvc:annotation-driven validator="beanNameValidator" /> 其中 validator 属性符合 .xsd 说:

Attribute : validator The bean name of the Validator that is to be used to validate Controller model objects. This attribute is not
required, and only needs to be specified explicitly if a custom Validator needs to be configured. If not specified, JSR-303 validation will be installed if a JSR-303 provider is present on the classpath.

beanNameValidator按照我的@Bean好像应该是localValidatorFactoryBean

我最终使用了 Jersey Bean Validation,而不是 Spring。这是因为我的其余代码无论如何都在使用 Jersey。为了完成这项工作,我刚刚导入了 Jersey Bean Validation jar 并对 web.xml 添加了一个小改动。验证现在正在工作。

谢谢@Manual Jordan。我会赞成你的回答,因为它给了我正确的线索。

<!--  jersey beanValidation  -->
       <init-param>
           <param-name>jersey.config.beanValidation.enableOutputValidationErrorEntity.server</param-name>
           <param-value>true</param-value>
       </init-param>