基于注解的Spring bean验证

时间:2020-03-06 14:53:01  来源:igfitidea点击:

我正在研究一种基于注释的方法,用于使用spring模块验证Spring bean。在本教程中,以以下bean(省略了getter和setters)为例:

public final class User {  

  @NotBlank  
  @Length(max = 80)  
  private String name;  

  @NotBlank  
  @Email  
  @Length(max = 80)  
  private String email;  

  @NotBlank  
  @Length(max = 4000)  
  private String text;  
}

如果不遵守特定的验证规则,则使用的错误消息应遵循以下格式:

bean-class.bean-propery[validation-rule]=Validation Error message

上面显示的类的示例包括:

User.email[not.blank]=Please enter your e-mail address.  
User.email[email]=Please enter a valid e-mail address.  
User.email[length]=Please enter no more than {2} characters.

消息键包含类名的事实带来了两个问题:

  • 如果重命名了类,则还需要更改消息键
  • 如果我有另一个类(例如,人),其电子邮件属性已与User.email进行了相同的验证,则需要复制消息,例如Person.email [not.blank] =请输入电子邮件地址。 Person.email [email] =请输入有效的电子邮件地址。 Person.email [length] =请输入不超过{2}个字符。

实际上,文档声称可以为特定规则(例如@Email)配置默认消息,如下所示:

email=email address is invalid

如果找不到针对该规则的特定于Bean的消息,则应使用此默认消息。但是,我的经验是,这根本行不通。

避免重复消息的另一种机制是将错误消息的密钥传递给规则注释。例如,假设我为@Email规则定义了以下默认错误消息

badEmail=Email address is invalid

如果我这样注释相关属性,则应使用此消息:

@Email(errorCode="badEmail")
private String email;

但是我一遍又一遍地尝试了一下,但它似乎没有用。有没有人找到使用此验证框架时避免重复出现错误消息的方法?

解决方案

我快速浏览了BeanValidator API,看来我们可能想尝试使用errorCodeConverter属性。

我们是否需要实现自己的ErrorCodeConverter或者使用提供的实现之一?

....
<bean id="validator" class="org.springmodules.validation.bean.BeanValidator"
    p:configurationLoader-ref="configurationLoader"
    p:errorCodeConverter-ref="errorCodeConverter" />

<bean id="errorCodeConverter" class="contact.MyErrorCodeConverter" />
....

注意:configurationLoader是在本教程中使用的config XML中定义的另一个bean

转换器示例:

package contact;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springmodules.validation.bean.converter.ErrorCodeConverter;

public class MyErrorCodeConverter implements ErrorCodeConverter {

    private Log log = LogFactory.getLog(MyErrorCodeConverter.class);

    @Override
    public String convertPropertyErrorCode(String errorCode, Class clazz, String property) {
        log.error(String.format("Property %s %s %s", errorCode, clazz.getClass().getName(), property));
        return errorCode;  // <------ use the errorCode only
    }

    @Override
    public String convertGlobalErrorCode(String errorCode, Class clazz) {
        log.error(String.format("Global %s %s", errorCode, clazz.getClass().getName()));
        return errorCode;
    }
}

现在,这些属性应该可以正常工作:

MyEmailErrorCode=Bad email

class Foo {
    @Email(errorCode="MyEmailErrorCode")
    String email
}