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é.
Guau, explicación tan detallada. ¡Gracias por tu esfuerzo y por compartir! Me gustaría probar estas soluciones pronto! – bertie
De nada. :) –
Acabas de ahorrarme muchas horas leyendo las especificaciones y pasando por el código, gracias por tu buena lectura. – devsnd