Bean Validation在JSF 2中的resourcebundle参数化可能性?

ber*_*tie 9 java jsf resourcebundle bean-validation jsf-2

在JSF 2中使用带有BV的resourcebundle看起来像这样:

public class UserBean {
    @Size(min=13, message="{creditcard.length}")
    public String getCreditCard() {
        return this.creditCard;
    }
}
Run Code Online (Sandbox Code Playgroud)

我必须在其中一个属性文件中定义ResourceBundle条目,该文件可以在 faces-config.xml

creditcard.length =信用卡长度必须至少为13个字符

我们可以看到creditcard.length的值是非参数化的.

我可以进行参数化的ResourceBundle条目,可以从BV或其他地方填充吗?


这是我想要实现的简单方案:

creditcard.length =信用卡长度必须至少为{0}个字符.感谢您选择{1}信用卡.

而我希望这样的事情:

public class UserBean {
    @Size(
        min=13, 
        message="{creditcard.length}", 
        messageParams={"13", "plantvszombie"})
    public String getCreditCard() {
        return this.creditCard;
    }
}
Run Code Online (Sandbox Code Playgroud)

当验证失败时,creditcard属性的错误消息将显示如下字符串:

信用卡长度必须至少为13个字符.感谢您选择plantvszombie信用卡.


这个ResourceBundle消息参数化是否可行?

请分享您对此事的经验.

谢谢 !

vic*_*era 32

也许您已经知道Bean验证的消息是在ValidationMessages.properties类的根中的资源包中定义的(即WEB-INF\classes\ValidationMessages.properties).

这些消息可以有参数,但它们不像JSF那样工作.有一个叫做的接口MessageInterpolator,它将消息模式转换为实际的消息.

默认插值器使用命名参数,如消息中所示:值必须介于{min}和{max}之间.{}之间的值首先在应用程序的资源包中解析; 稍后在提供程序的资源包中,最后在约束注释的属性中.(这或多或少是如何工作的,完整的算法在Bean Validation规范的4.3节中).

假设您将Size annotation的属性消息定义为{creditCard.message}

ValidationMessage.properties的内容可以是

creditCard.message=Credit card length must be at least {min} characters. \
                   Thank you for choosing the plantsvszombies credit card.
Run Code Online (Sandbox Code Playgroud)

你可以用一个属性替换plantsvszombies:

creditCard.message=Credit card length must be at least {min} characters. \
                   Thank you for choosing the {creditCard.type} credit card.
creditCard.type=plantsvszombies
Run Code Online (Sandbox Code Playgroud)

您甚至可以在约束的消息中使用两个参数

Size(min=13, message="{creditCard.message} {plantsvszombies.messages}")
Run Code Online (Sandbox Code Playgroud)

并将资源包定义为

creditCard.message=Credit card length must be at least {min} characters.
plantsvszombies.message=Thank you for choosing the plantsvszombies credit card.
Run Code Online (Sandbox Code Playgroud)

我认为这是一种简单而干净的方法.


但是如果你想要更多的东西,比如在约束声明中定义自定义参数,你可以使用自定义消息插补器.请注意,这可能是一个棘手的解决方案.

好吧,您可以定义一个语法来在消息字符串中引入您的参数.然后,让默认插值器解析消息.默认插补器不会理解自定义参数的语法,它们在解析后仍然存在.然后,自定义插补器可以替换替换自定义参数.

通过示例更容易理解.

首先,消息定义为{creditCard.message} [plantsvszombies].对于此语法,方括号之间的内容是以逗号分隔的索引参数(此处只有一个参数).

接下来,资源包的内容定义为:

 creditCard.message=Credit card length must be at least {min} characters. \
                    Thank you for choosing the {0} credit card.
Run Code Online (Sandbox Code Playgroud)

当默认插值器替换表达式的第一部分时,我们将:

信用卡长度必须至少为13个字符.\感谢您选择{0}信用卡.[plantsvszombies]

然后,自定义插值器将采用最后一个表达式并拆分内容以获取标记,并使用相应索引中的标记替换索引参数(参数[0] = plantsvzzombies).

所以消息将是:

信用卡长度必须至少为13个字符.\感谢您选择plantsvszombies信用卡.

这是此语法的自定义插值器的代码(未优化,如果第一个表达式或标记中有其他方括号,则正则表达式模式无法工作).

 package validation;

 import java.util.Locale;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import javax.validation.MessageInterpolator;
 import javax.validation.Validation;

 public class MyInterpolator implements MessageInterpolator{
    private MessageInterpolator interpolator;

    public MyInterpolator() {
        //we need to delegate to the default interpolator
        this.interpolator = Validation.byDefaultProvider().configure().getDefaultMessageInterpolator();
    }

    private static final Pattern parametersPattern=Pattern.compile("\\[(.+)\\]$");

    protected static String replaceParameters(String message){
        Matcher matcher = parametersPattern.matcher(message);
        String values[]={};
        if(matcher.find()){
            values=matcher.group(1).split("\\s*,\\s*");
            message=message.substring(0, matcher.start());
            for(int i=0; i < values.length; i++){
                message=message.replace("{"+i+"}", values[i]);
            }
        }
        return message;
    }

    @Override
    public String interpolate(String messageTemplate, Context context) {
        String message = interpolator.interpolate(messageTemplate, context);
        return replaceParameters(message);
    }

    @Override
    public String interpolate(String messageTemplate, Context context, Locale locale) {
        String message = interpolator.interpolate(messageTemplate, context);
        return replaceParameters(message);
    }

}
Run Code Online (Sandbox Code Playgroud)

内插器的注册位于名为META-INF/validation.xml(规范的4.4.6)的xml文件中.

<?xml version="1.0" encoding="UTF-8"?>
<validation-config
xmlns="http://jboss.org/xml/ns/javax/validation/configuration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jboss.org/xml/ns/javax/validation/configuration validation-configuration-1.0.xsd">
    <message-interpolator>validation.MyInterpolator</message-interpolator>
</validation-config>  
Run Code Online (Sandbox Code Playgroud)

这是一个有点复杂的解决方案,因为约束注释不接受消息的参数,因为在插值器中,我们无法获得正在验证的属性的许多信息.如果我找到一个更简单的解决方案,我会发布它.