JSF 2 Localización (frijol administrado)
-
28-09-2019 - |
Pregunta
Tengo un archivo de propiedades para la localización:
foo=Bar
title=Widget Application
Esto está atado como un resource-bundle
En las caras-config:
<resource-bundle>
<base-name>com.example.messages.messages</base-name>
<var>msgs</var>
</resource-bundle>
Puedo acceder a esto muy bien en la vista de facelets usando El:
<title>#{msgs.title}</title>
Sin embargo, si hay cosas como SQLExcepciones, necesito poder escribir mensajes desde el frijol administrado. Todo esto también funciona:
FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);
Aquí está el problema: quiero que esos mensajes provengan del archivo de propiedades para que ellos también puedan cambiarse en función de la ubicación. ¿Existe una manera fácil de acceder al archivo de propiedades usando inyección?
Solución
Hice una pregunta bastante relacionada en Entonces:Cómo inyectar una clase no serializable (como java.util.resourceBundle) con soldadura
Y dentro del foro de costura:http://seamframework.org/community/howtocreateanInjectableSourceBundlewithweld
Para resumir: me di cuenta de un recurso inyectable con 3 productores. Primero necesita un FacescontextProducer. Tomé el de las fuentes Alpha Seam 3.
public class FacesContextProducer {
@Produces @RequestScoped
public FacesContext getFacesContext() {
FacesContext ctx = FacesContext.getCurrentInstance();
if (ctx == null)
throw new ContextNotActiveException("FacesContext is not active");
return ctx;
}
}
Luego necesita un LocalProDucer, que utiliza el FacescontextProducer. También lo tomé de Seam 3 Alpha.
public class FacesLocaleResolver {
@Inject
FacesContext facesContext;
public boolean isActive() {
return (facesContext != null) && (facesContext.getCurrentPhaseId() != null);
}
@Produces @Faces
public Locale getLocale() {
if (facesContext.getViewRoot() != null)
return facesContext.getViewRoot().getLocale();
else
return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
}
}
Ahora tiene todo para crear un ResourceBundleProducer, que puede verse así:
public class ResourceBundleProducer {
@Inject
public Locale locale;
@Inject
public FacesContext facesContext;
@Produces
public ResourceBundle getResourceBundle() {
return ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() );
}
}
Ahora puede @Inyect The ResourCebundle en sus frijoles. Preste atención a que debe inyectarse en un atributo transitorio, de lo contrario, obtendrá una excepción quejándose de que ResourceBundle no es serializable.
@Named
public class MyBean {
@Inject
private transient ResourceBundle bundle;
public void testMethod() {
bundle.getString("SPECIFIC_BUNDLE_KEY");
}
}
Otros consejos
Es más fácil usar, por ejemplo, el módulo de mensaje de Myfaces codi!
Puedes hacer esto solo con JSF.
Comience definiendo una propiedad administrada en su frijol de respaldo. En la configuración de JSF, puede establecer el valor de la propiedad administrada en una expresión EL que hace referencia a su paquete de recursos.
He hecho algo como lo siguiente usando Tomcat 6. La única advertencia es que no puede acceder a este valor desde el constructor de su bean de respaldo, ya que JSF aún no lo habrá inicializado. Usar @PostConstruct
en un método de inicialización si el valor se necesita temprano en el ciclo de vida del bean.
<managed-bean>
...
<managed-property>
<property-name>messages</property-name>
<property-class>java.util.ResourceBundle</property-class>
<value>#{msgs}</value>
</managed-property>
...
</managed-bean>
<application>
...
<resource-bundle>
<base-name>com.example.messages.messages</base-name>
<var>msgs</var>
</resource-bundle>
...
</application>
Esto tiene la ventaja de hacer que sus métodos de bean de respaldo dependan menos de la tecnología de presentación, por lo que debería ser más fácil de probar. También desacopla su código de detalles como el nombre dado al paquete.
Algunas pruebas con Mojarra 2.0.4-B09 muestran una pequeña inconsistencia cuando un usuario cambia la sesión local. Expresiones en la página EL usa la nueva ubicación pero el bean de respaldo no se le da la nueva referencia de ResourceBundle. Para que sea consistente, puede usar el valor de la propiedad Bean en las expresiones EL, como usar #{backingBean.messages.greeting}
en lugar de #{msgs.greeting}
. Luego, la página EL y el frijol de respaldo siempre usarían el lugar que estaba activo cuando comenzó la sesión. Si los usuarios tenido Para cambiar los locales a mitad de sesión y obtener los nuevos mensajes, puede intentar hacer un frijol scoped y dar referencias tanto al paquete de recursos y frijoles de sesión.
Aquí hay un ejemplo sobre cómo hacer esto:http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html
Quieres echar un vistazo al ResourceBundle.getBundle()
parte.
Saludos, Lars
Esta es una vieja pregunta, pero estoy agregando otra forma de hacer esto. Estaba buscando algo más y me encontré con esto. Todos los métodos aquí parecían complicados por algo que no me pareció difícil. Jugando con brillo porque es bonito si me preguntas.
Dado un archivo:
/com/full/package/path/to/messages/errormessages.properties
Dentro del archivo:
SOME_ERROR_STRING=Your App Just Cratered
Creo un método "getBundle ()" ya que me gusta detectar el tiempo de ejecución y agregar un mensaje significativo para que entienda de dónde viene. No es difícil y puede ayudar si obtiene el capricho para que juegue con los archivos de propiedades por alguna razón y no actualice todo correctamente. A veces hago esto privado, ya que a veces es un método de ayuda dentro de una clase (para mí). Esto mantiene el trycle el desorden del código significativo.
El uso de la ruta completa del archivo le permite colocarlo en otro lugar que no sea la ubicación/directorio predeterminado si tiene otras ideas sobre la organización.
public/private ResourceBundle getMessageResourceBundle(){
String messageBundle = "com.full.package.path.to.messages.errormessages";
ResourceBundle bundle = null;
try{
bundle = ResourceBundle.getBundle(messageBundle);
}catch(MissingResourceException ex){
Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
"Unable to find message bundle in XYZ Class", ex);
throw ex;
}
}
public void doSomethingWithBundle(){
ResourceBundle bundle = getMessageResourceBundle();
String someString = bundle.getString("SOME_ERROR_STRING");
...
}