【问题标题】:Spring 4 @Validation annotation with BindingResult is not working带有 BindingResult 的 Spring 4 @Validation 注释不起作用
【发布时间】:2017-08-08 17:42:06
【问题描述】:

当我在方法中使用 BindingResult@Validated 注释时,验证不起作用。如果我从方法参数中删除BindingResult,它工作正常。我用@ControllerAdvice

知道为什么它不起作用吗?

我的代码如下:

public ResponseEntity<?> dologin(
        @Validated({ Group.Login.class }) @RequestBody User user,
        BindingResult errors)
{
    // somecode
}

根据Validation, Data Binding, and Type Conversion documentation, 任何验证消息都会自动添加到活页夹的BindingResult

如果我删除它不会有影响,对吧?

【问题讨论】:

    标签: java spring spring-validator


    【解决方案1】:

    由于您只提供了控制器方法中的代码,因此我添加了一些额外信息,以便在 Spring 4 应用程序中进行验证,以便您了解可能存在的差异。我至少假设以下几点:

    1. 在您的类路径中包含bean-validation-api JAR。这将为您获取注释。
    2. 在您的类路径中包含一个 Bean 验证实现 JAR(例如,参考实现 hibernate-validator)。这将启用验证框架。
    3. 您的请求映射可以是以下形式之一:

    @RequestMapping(method = RequestMethod.POST)
    public String dologin(@Valid @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
    

    @RequestMapping(method = RequestMethod.POST)
    public String dologin(@Validated @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
    

    或者,如果使用validation groups


    @RequestMapping(method = RequestMethod.POST)
    public String dologin(@Validated({ User.Login.class }) @ModelAttribute("userForm") User user, final BindingResult bindingResult) throws Exception
    

    1. 您在 User 类中的注释应该与消息属性键内联:

    @NotBlank(message = "{firstName.required}")
    @Size(min = 2, max = 24, message = "{firstName.size}")
    @Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}")
    private String firstName;
    

    或者,如果使用validation groups


    public interface Login extends Default {}
    
    @NotBlank(message = "{firstName.required}", groups = {Login.class})
    @Size(min = 2, max = 24, message = "{firstName.size}", groups = {Login.class})
    @Pattern(regexp = "^[’' \\.\\-\\p{L}\\p{M}]*$", message = "{firstName.format}", groups = {Login.class})
    private String firstName;
    

    1. 你的消息属性应该在src/main/resources:

    firstName.required=First name is required.
    firstName.size=First name must be between {min} and {max} characters long.
    firstName.format=First name may contain only letters, apostrophes, spaces and hyphens.
    

    确保您的 Bean Validation specification 版本与您的实施版本相匹配。 Bean Validation API 2.0 于 2017 年 8 月发布。Bean Validation 2.0 参考实现为 Hibernate Validation Engine 6.0

    如果方法参数中存在BindingResult,则验证错误将被添加到其中。或者,您可以使用Errors 代替BindingResult - API 基本相同。在我上面的实现中,这两种方法都是等效的。

    但是,如果我将参数保留在我的控制器方法之外,我会看到(从日志记录)触发了验证并引发了相应的错误,并且我的消息键与其属性的映射成功,但我的服务器错误页面呈现而不是我的预期视图。有关此参数要求的更多信息,请参阅BindingResult/Errors parameter 上的相关问题。


    Aug 31, 2017 2:21:56 PM com.test.spring.controller.ErrorController handleException
    SEVERE: Server Error
    org.springframework.validation.BindException: org.springframework.validation.BeanPropertyBindingResult: 2 errors
    Field error in object 'userForm' on field 'firstName': rejected value []; codes [Size.userForm.firstName,Size.firstName,Size.java.lang.String,Size]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName],24,2]; default message [First name must be between 2 and 24 characters long.]
    Field error in object 'userForm' on field 'firstName': rejected value []; codes [NotBlank.userForm.firstName,NotBlank.firstName,NotBlank.java.lang.String,NotBlank]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userForm.firstName,firstName]; arguments []; default message [firstName]]; default message [First name is required.]
        at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:117)
    

    我发现上述所有组合的行为都非常一致。

    我注意到的一个区别是您在示例中使用了@ControllerAdvice。我的大多数控制器都使用@Controller 注释(本地控制器错误),而不是@ControllerAdvice(用于全局错误,例如用于呈现HTTP 404 或500 错误页面)。有关@ControllerAdvice 的使用,请参阅此相关问题/答案。

    在上面的错误日志中,如果我省略了BindingResult/Errors 参数,您会看到ErrorController 是报告验证错误的那个,实际上那是我使用@ControllerAdvice 注释的控制器类的@Controller。通过在您的登录控制器上使用@ControllerAdvice,您可能会干扰正常的错误处理。

    由于您使用的是 Hibernate-specific @Validated 组验证注释而不是 JSR-303/349/380 规范 @Valid 注释,因此您使用的实现之间可能存在一些差异(我猜是版本 5,它符合API 1.1)。我使用的是 6.0.2 版本,它符合新的(2017 年 8 月)Bean Validation Framework API 2.0

    【讨论】:

    • @Valid 没有提供使用“组”的方法,它使用“默认”组(无组)进行验证。我认为这不是他希望在他的代码中使用的
    • @MironBalcerzak 是的,我只是花了一段时间来建立一个反映他的用例的工作示例。除了不基于组的更简单版本(主要供我自己参考)之外,我在答案中添加了新信息以反映验证组。我看到这两种方法的结果一致。
    【解决方案2】:

    Hibernate Validator 6 不适用于 Spring 4,因为 Spring 4 的 LocalValidatorFactoryBean 尚未使用 Java 的 Service Provider 机制来发现 Validator 实现,因此您需要自己创建验证器来指定实现。

    使用@EnableWebMvc时:

    @Bean
    public javax.validation.Validator localValidatorFactoryBean() {
        LocalValidatorFactoryBean bean = new LocalValidatorFactoryBean();
        bean.setProviderClass("org.hibernate.validator.HibernateValidator");
        return bean;
    }
    

    或者在 XML 中:

    <mvc:annotation-driven validator="validator-adapter"/>
    
    <bean id="validator-adapter" 
      class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass"
                  value="org.hibernate.validator.HibernateValidator" />
    </bean>
    
    猜你喜欢
    • 1970-01-01
    • 2014-05-09
    • 2015-01-15
    • 2018-12-30
    • 2014-08-14
    • 2015-05-11
    • 2018-03-22
    • 2015-10-26
    • 2016-06-02
    相关资源
    最近更新 更多