Возможность параметризации ресурсного пакета валидации бина в JSF 2? - PullRequest
9 голосов
/ 21 марта 2011

Использование пакета ресурсов с BV в JSF 2 будет выглядеть примерно так:

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

И мне нужно определить запись 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;
    }
}

И сообщение об ошибке для свойства кредитной карты будет отображать строку, подобную этой, когда проверка не пройдена:

длина кредитной карты должна быть не менее 13 символов. Благодарим Вас за выбор кредитной карты plantvszombie .


Возможна ли эта параметризация сообщения ResourceBundle?

Пожалуйста, поделитесь своим опытом по этому вопросу.

Спасибо!

1 Ответ

32 голосов
/ 28 марта 2011

Возможно, вы уже знаете, что сообщения для проверки бинов определены в Resource Bundle ValidationMessages.properties в корне ваших классов (т. Е. WEB-INF\classes\ValidationMessages.properties).

Эти сообщения могут иметь параметры, но не имеютработать как в JSF.Существует интерфейс под названием MessageInterpolator, который преобразует шаблон сообщения в фактическое сообщение.

Интерполятор по умолчанию работает с именованными параметрами, как в сообщении: Значение должно быть между {min} и {max} .Значения между { и } разрешаются первыми в пакете ресурсов приложения;позже в пакете ресурсов провайдера и последним в свойствах аннотации ограничения.(Это более или менее работает, полный алгоритм приведен в разделе 4.3 спецификации проверки компонентов).

Предположим, вы определяете сообщение атрибута аннотации Size как {creditCard.message}

Содержимое файла ValidationMessage.properties может иметь значение

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

Вы можете заменить заводыvszombies свойством:

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

Вы можете даже использовать два параметра всообщение об ограничении

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

и определите пакет ресурсов как

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

Я думаю, что это простой и чистый подход.


Но если выхотите что-то большее, например, определение пользовательских параметров в объявлении ограничения, вы можете использовать пользовательский интерполятор сообщений. Обратите внимание, что это может быть более хитрым решением .

Что ж, вы можете определить синтаксис для представления ваших параметров в строке сообщения.Затем пусть интерполятор по умолчанию разрешит сообщение.Синтаксис пользовательских параметров не будет понят интерполятором по умолчанию, и он останется там после разрешения.Затем пользовательский интерполятор может заменить и заменить пользовательские параметры.

Это проще понять на примере.

Во-первых, сообщение определяется как {creditCard.message} [plantsvszombies] .Для этого синтаксиса содержимое в квадратных скобках - это индексированные параметры, разделенные запятыми (здесь только один параметр).

Далее содержимое пакета ресурсов определяется с помощью:

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

Когда интерполятор по умолчанию заменяет первую часть выражения, у нас будет:

Длина кредитной карты должна быть не менее 13 символов.\ Благодарим Вас за выбор кредитной карты {0}. [Plantvszombies]

Затем пользовательский интерполятор возьмет последнее выражение и разделит содержимое, чтобы получить токены, и заменит индексированные параметры токеном.в соответствующем индексе (параметр [0] = plantvzzombies).

Таким образом, сообщение будет:

Длина кредитной карты должна быть не менее 13 символов.\ Спасибо за выбор кредитной карты plantvszombies.

Это код пользовательского интерполятора для этого синтаксиса (не оптимизирован, и шаблон регулярного выражения не может работать, если в первом выражении есть другие квадратные скобки).или в токенах).

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

}

Регистрация интерполятора происходит в XML-файле с именем META-INF / validation.xml (4.4.6 спецификации).

<?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>  

Это немного сложное решение, потому что аннотации ограничений не принимают параметры для сообщений и потому что в интерполяторе мы не можем получить много информации о проверяемом свойстве.Если я найду более простое решение, я опубликую его.

...