2011-03-21 22 views
9

Utilizando el ResourceBundle con BV en JSF 2 sería algo como esto:Posibilidad de parametrización del paquete de recursos de Validación de frijol en JSF 2?

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

y tengo que definir la entrada ResourceBundle en uno de los archivo de propiedades que se pueden registrar en el faces-config.xml

creditcard.length = la longitud de la tarjeta de crédito debe tener al menos 13 caracteres

Vemos que el valor de la tarjeta de crédito.length no está parametrizado.

¿Puedo hacer una entrada parametrizada de ResourceBundle que se puede completar desde BV o quizás en otro lugar?


Este es un escenario simple que me gustaría lograr:

creditcard.length = longitud de tarjeta de crédito debe ser de al menos {0} caracteres. gracias por elegir la {1} tarjeta de crédito.

Y yo estaba esperando algo como esto:

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

Y el mensaje de error para la propiedad tarjeta de crédito mostrará una cadena como esta, cuando falla la validación:

longitud tarjeta de crédito debe ser de al menos caracteres. gracias por elegir la tarjeta de crédito plantvszombie.


¿Es posible esta parametrización del mensaje ResourceBundle?

Por favor, comparta su experiencia en este asunto.

¡Gracias!

Respuesta

32

Quizás ya sepa que los mensajes para la validación de frijoles se definen en el paquete de recursos ValidationMessages.properties en la raíz de sus clases (es decir, WEB-INF\classes\ValidationMessages.properties).

Estos mensajes pueden tener parámetros pero no funcionan como en JSF. Hay una interfaz llamada MessageInterpolator que transforma el patrón de mensaje en el mensaje real.

El interpolador predeterminado funciona con parámetros con nombre como en el mensaje: El valor debe estar entre {min} y {max}. Los valores entre { y } se resuelven primero en el paquete de recursos de la aplicación; más adelante en el paquete de recursos del proveedor, y el último en propiedades de la anotación de restricción. (Esto es más o menos como funciona, el algoritmo completo se encuentra en la sección 4.3 de la especificación de Validación de frijol).

suponga que define el mensaje atributo de la anotación tamaño que {} creditCard.message

El contenido de ValidationMessage.propiedades podrían ser

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

Se podría sustituir plantsvszombies con una propiedad:

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

incluso se podría utilizar dos parámetros en el mensaje de la restricción

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

y definir el paquete de recursos como

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

Creo que este es un enfoque simple y limpio.


Pero si quieres algo más parecido a la definición de parámetros personalizados en la declaración de la restricción se puede utilizar un interpolador de mensaje personalizado. Tenga en cuenta que esta podría ser una solución más complicada.

Bueno, podría definir una sintaxis para introducir sus parámetros en la cadena del mensaje. Luego, deje que el interpolador predeterminado resuelva el mensaje. La sintaxis de los parámetros personalizados no será entendida por el interpolador predeterminado y seguirán allí después de la resolución. Entonces, el interpolador personalizado puede reemplazar reemplazar los parámetros personalizados.

Esto es más fácil de entender con un ejemplo.

Primero, se define un mensaje como {creditCard.message} [plantsvszombies]. Para esta sintaxis, el contenido entre corchetes son los parámetros indexados separados por comas (aquí hay solo un parámetro).

A continuación, el contenido del paquete de recursos está definido con:

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

Cuando el interpolador predeterminado sustituye a la primera parte de la expresión, tendremos:

longitud de tarjeta de crédito debe estar al menos 13 caracteres. \ Gracias por elegir la {0} tarjeta de crédito. [Plantsvszombies]

Luego, el interpolador personalizado tomará la última expresión y dividirá el contenido para obtener los tokens y reemplazará los parámetros indexados con el token en el índice correspondiente (parámetro [0] = plantasvzzombies).

Así que el mensaje será:

crédito longitud de la tarjeta debe ser de al menos 13 caracteres. \ Gracias por elegir la tarjeta de crédito plantsvszombies.

Este es el código del interpolador personalizado para esta sintaxis (no optimizado y el patrón de expresiones regulares no podría funcionar si hay otros corchetes en la primera expresión o en los 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); 
    } 

} 

El registro del interpolador va en el archivo XML denominado META-INF/validation.xml (4.4.6 de la especificación).

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

Esta es una solución poco complicada debido a las anotaciones de restricción no acepta parámetros de los mensajes y porque en el interpolador, que no pueden obtener mucha información de la propiedad que está siendo validada. Si encuentro una solución más fácil, la publicaré.

+0

Guau, explicación tan detallada. ¡Gracias por tu esfuerzo y por compartir! Me gustaría probar estas soluciones pronto! – bertie

+0

De nada. :) –

+0

Acabas de ahorrarme muchas horas leyendo las especificaciones y pasando por el código, gracias por tu buena lectura. – devsnd

Cuestiones relacionadas