基于注释的春豆验证

2022-09-04 04:12:28

我正在研究一种基于注释的方法来验证使用弹簧模块的Spring Bean。在本教程中,使用以下 bean(省略 getters 和 setter)作为示例:

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.

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

  1. 如果重命名类,则还需要更改消息键
  2. 如果我有另一个类(例如Person)的电子邮件属性与 User.email 验证相同,我需要复制消息,例如

    Person.email[not.blank]=请输入您的电子邮件地址。
    Person.email[email]=请输入有效的电子邮件地址。
    Person.email[长度]=请输入不超过 {2} 个字符。

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

email=email address is invalid

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

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

badEmail=Email address is invalid

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

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

然而,我尝试了这个,一次又一次,它似乎不起作用。有没有人找到一种方法来避免在使用此验证框架时重复错误消息?


答案 1

我快速浏览了BeanValidator API,看起来您可能想尝试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 是在本教程中使用的配置 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
}

答案 2

弹簧验证确实有一个错误代码转换器可以做到这一点:

org.springmodules.validation.bean.converter.KeepAsIsErrorCodeConverter

使用此选项时,将检查资源包中是否存在以下代码:

[errorCode.commandBeanName.fieldName, errorCode.fieldName, errorCode.fieldClassName, errorCode]

  • 错误代码是实际的验证错误代码,例如。not.blank, email.
  • 命令 BeanName 与引用表单支持 Bean 的模型键名称相同。
  • 字段名称 是字段的名称。
  • 字段类名是字段类名,例如。java.lang.String, java.lang.Integer

例如,如果我有一个在模型中由键“formBean”引用的Bean,并且java.lang.String类型的字段emailAddress不包含电子邮件地址,这会导致错误Code电子邮件。验证框架将尝试解析以下消息代码:

[email.formBean.emailAddress, email.emailAddress, email.java.lang.String, email]

如果错误代码被错误代码“badEmail”替换,如下所示:

@Email(错误代码=“死信”)

框架将尝试解析的消息代码将是:

[badEmail.formBean.emailAddress, badEmail.emailAddress, badEmail.java.lang.String, badEmail]

我建议保持错误代码不变。因此,一条消息可用于具有与之关联的错误代码的所有字段。如果需要更具体地说明某个字段的消息,则可以使用代码 errorCode.commandBeanName.field 向资源包中添加一条消息。


推荐