java JSF 2 中 Bean 验证的资源包参数化可能性?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5380786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 10:51:45  来源:igfitidea点击:

Bean Validation's resourcebundle parameterization possibility in JSF 2?

javajsfjsf-2resourcebundlebean-validation

提问by bertie

Using the resourcebundle with BV in JSF 2 would look something like this :

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

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

And i have to define the ResourceBundle entry in one of the properties file that can be registered in the faces-config.xml

我必须在可以注册的属性文件之一中定义 ResourceBundle 条目 faces-config.xml

creditcard.length=credit card length must be at least 13 characters

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

We can see that the value of the creditcard.length is non parameterized.

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

Can I do parameterized ResourceBundle entry that can be populated from BV or perhaps somewhere else?

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



This is a simple scenario that I would like to achieve :

这是我想要实现的简单场景:

creditcard.length=credit card length must be at least {0} characters. thank you for choosing the {1} credit card.

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

And I was hoping for something like this :

我希望有这样的事情:

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

And the error message for the creditcard property will display a string like this when the validation fails :

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

credit card length must be at least 13characters. thank you for choosing the plantvszombiecredit card.

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



Is this ResourceBundle message parameterization possible?

这个 ResourceBundle 消息参数化可能吗?

Please share your experience on this matter.

请分享您在这个问题上的经验。

Thank you !

谢谢 !

回答by victor herrera

Maybe you already know that messages for Bean Validation are defined in the Resource Bundle ValidationMessages.propertiesin the root of your classes (i.e WEB-INF\classes\ValidationMessages.properties).

也许您已经知道 Bean 验证的消息是在ValidationMessages.properties您的类(即WEB-INF\classes\ValidationMessages.properties)的根目录中的 Resource Bundle中定义的。

These messages can have parameters but they don't work as in JSF. There is a interface called MessageInterpolatorthat transform the message pattern into the actual message.

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

Default interpolator works with named parameters like in the message: Value must be between {min} and {max}. The values between {and }are resolved first in resource bundle of the application; later in the resource bundle of the provider, and last in properties of the constraint annotation. (This is more or less how it works, the complete algorithm is in section 4.3 of the Bean Validation specification).

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

Suppose you define the attribute message of the Size annotation as {creditCard.message}

假设你将Size注解的属性消息定义为{creditCard.message}

The content of ValidationMessage.properties could be

ValidationMessage.properties 的内容可以是

creditCard.message=Credit card length must be at least {min} characters. \
                   Thank you for choosing the plantsvszombies credit card.

You could replace plantsvszombies with a property:

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

creditCard.message=Credit card length must be at least {min} characters. \
                   Thank you for choosing the {creditCard.type} credit card.
creditCard.type=plantsvszombies

You could even use two parameters in the message of the constraint

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

Size(min=13, message="{creditCard.message} {plantsvszombies.messages}")

and define the resource bundle as

并将资源包定义为

creditCard.message=Credit card length must be at least {min} characters.
plantsvszombies.message=Thank you for choosing the plantsvszombies credit card.

I think this is a simple and clean approach.

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



But if you want something more like defining custom parameters in the declaration of the constraint you could use a custom message interpolator. Please notice that this could be a trickier solution.

但是,如果您想要更像是在约束声明中定义自定义参数,您可以使用自定义消息插值器。请注意,这可能是一个更棘手的解决方案

Well, you could define a syntax to introduce your parameters in the message string. Then, let the default interpolator resolve the message. The syntax for custom parameters won't be understood by the default interpolator and they will still be there after resolving. Then, the custom interpolator can replace replace the custom parameters.

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

This is more easy to understand with an example.

这通过一个例子更容易理解。

First, a message is defined like {creditCard.message}[plantsvszombies]. For this syntax, the content between the square brackets are the indexed parameters separated by commas (here is only one parameter).

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

Next, the content of the resource bundle is defined with:

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

 creditCard.message=Credit card length must be at least {min} characters. \
                    Thank you for choosing the {0} credit card.

When the default interpolator replaces the first part of the expression, we'll have:

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

Credit card length must be at least 13 characters. \ Thank you for choosing the {0} credit card.[plantsvszombies]

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

Then, the custom interpolator will take the last expression and split the content to get the tokens and replace the indexed parameters with the token in the corresponding index (parameter[0]=plantsvzzombies).

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

So the message will be:

所以消息将是:

Credit card length must be at least 13 characters. \ Thank you for choosing the plantsvszombies credit card.

信用卡长度必须至少为 13 个字符。\ 感谢您选择植物大战僵尸信用卡。

This is the code of the custom interpolator for this syntax (not optimized and the regex pattern could not work if there are other square brackets in the first expression or in the tokens).

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

 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);
    }

}

The registering of the interpolator goes in the xml file called META-INF/validation.xml (4.4.6 of the spec).

内插器的注册在名为 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>  

This is a bit complicated solution because the constraint annotations doesn't accept parameters for the messages and because in the interpolator, we can not get many information of the property that is being validated. If I find an easier solution, I will post it.

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