FAQ StrutsConsultez toutes les FAQ
Nombre d'auteurs : 25, nombre de questions : 96, dernière mise à jour : 23 février 2015 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de http://www.developpez.com et de l'expérience personnelle des auteurs.
Nous tenons à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes. Les auteurs font leur maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez nous aider en devenant rédacteur, lisez ceci.
- Comment gérer l'internationalisation (I18N) et/ou la localisation avec Struts ? Le ResourceBundle
- Comment changer de langue à la demande avec Struts ?
- Comment formater une valeur d'un bean avec Struts ? Les attributs « format » et « formatkey »
- Comment charger plusieurs fichiers de ressources (bundles) sans avoir à utiliser les clés des bundles ?
- Comment définir les fichiers de localisation en dehors du classpath ?
- Comment encoder les données ?
Struts supporte nativement le mécanisme d'internationalisation et de localisation offert par la plateforme Java : le ResourceBundle et la Locale.
Pour obtenir un ResourceBundle foo.bar.MyResourceBundle, il suffit de créer un ou plusieurs fichiers dans le répertoire /foo/bar/ :
- MyResourceBundle.properties : ce fichier contient les messages de la langue par défaut pour votre application ;
- MyResourceBundle_XX.properties : ce fichier contient les mêmes messages dans la langue dont le code ISO est XX.
Exemple : si votre langue par défaut est l'anglais, vous aurez dans MyResourceBundle.properties une entrée du type :
Code : | Sélectionner tout |
default.welcome=hello
Code : | Sélectionner tout |
default.welcome=bonjour
Il vous faudra ensuite déclarer ces ressources dans le descripteur de configuration de votre application (struts-config.xml) :
Code xml : | Sélectionner tout |
<message-resources parameter="foo.bar.MyResourceBundle" />
Attention : il ne faut pas préciser l'extension du fichier (.properties) et ne pas spécifier les codes ISO.
Il faut aussi absolument veiller à ce que le fichier soit accessible dans le CLASSPATH.
Dans les pages JSP, il faut déclarer l'internationalisation avec l'attribut locale du tag <html:html> :
Code JSP : | Sélectionner tout |
1 2 3 4 | <%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html"%> <html:html locale="true"> .. page content ... </html:html > |
Pour changer la langue à la demande, il faut créer une action qui va mettre à jour la locale dans l'objet request. La locale fait partie des attributs d'une requête http et est donc conservée durant la navigation. De plus, la JVM charge tous les bundles au démarrage. Toutes les langues définies sont donc accessibles.
Imaginons trois liens :
Code JSP : | Sélectionner tout |
1 2 3 | <html:link page='/switch.do?lang=fr&cty=FR'>FR</html:link> <html:link page='/switch.do?lang=en&cty=EN'>EN</html:link> <html:link page='/switch.do?lang=en&cty=US'>US</html:link> |
Ces liens pointent sur une Action "SwitchAction" définie dans le mapping par l'alias "switch".
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class SwithLangAction extends Action { public ActionForward execute(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { //récupération des paramètres passés et de l'URL du referer String country = request.getParameter("cty"); String language = request.getParameter("lang"); String referer = request.getHeader("referer"); HttpSession session = request.getSession(); ActionForward forward = null; // définition de la locale setLocale( request, new Locale( language, country ) ); // redirection vers une page définie par défaut if( referer==null ) { forward = (mapping.findForward("success")); } // redirection vers l'URL du referrer. else { forward = new RedirectingActionForward(); forward.setPath( referer ); } return forward; } } |
Attention : certains serveurs ne transmettent pas le referer. Il faut donc explicitement le récupérer (dans un ActionForm par exemple).
Il faut utiliser l'attribut format du tag <bean:write>.
Code xml : | Sélectionner tout |
<bean:write name='mybean' property='number' format='#,##0.00' />
Ainsi, si la valeur numérique de la variable number de l'ActionForm référencée par « mybean » vaut 123456789, elle sera affichée 123,456,789.00, conformément au pattern #,##0.00 .
Vous pouvez aussi localiser les patterns de formatage, pour différencier ceux-ci en fonction de la langue. Pour ce faire, il faut les embarquer dans les bundles de ressources.
Exemple :
Code html : | Sélectionner tout |
number.format=#,##0.00
Il faut ensuite utiliser :
Code xml : | Sélectionner tout |
<bean:write name='mybean' property='number' formatkey='number.format'/>
Attention : le pattern utilisé doit être compatible avec la langue. Par exemple, '#,##0.00' ne fonctionnera pas avec la locale 'fr', puisque c'est un pattern anglais.
Le principe consiste à fusionner les resources-bundles au chargement.
Voici la classe qui se charge de le faire (l'API commons Logging est utilisée dans cet exemple pour la journalisation) :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | package bla.bla.bla.struts; import java.io.InputStream; import java.util.Enumeration; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.util.MessageResourcesFactory; import org.apache.struts.util.PropertyMessageResources; public class MultiPropertyMessageResources extends PropertyMessageResources { protected static final Log log; public MultiPropertyMessageResources(MessageResourcesFactory factory, String config) { super(factory, config); log.info("Initializing, config='" + config + "'"); } public MultiPropertyMessageResources(MessageResourcesFactory factory, String config, boolean returnNull) { super(factory, config, returnNull); log.info("Initializing, config='" + config + "', returnNull=" + returnNull); } protected void loadLocale(String localeKey) { label0: { if(log.isTraceEnabled()) log.trace("loadLocale(" + localeKey + ")"); synchronized(locales) { if(locales.get(localeKey) == null) break label0; } return; } locales.put(localeKey, localeKey); String configFiles[] = config.split(","); for(int i = 0; i < configFiles.length; i++) { String name = configFiles[i].trim().replace('.', '/'); if(localeKey.length() > 0) name = name + "_" + localeKey; name = name + ".properties"; InputStream is = null; Properties props = new Properties(); try { if(log.isTraceEnabled()) log.trace(" Loading resource '" + name + "'"); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if(classLoader == null) classLoader = getClass().getClassLoader(); is = classLoader.getResourceAsStream(name); if(is != null) { props.load(is); is.close(); } if(log.isTraceEnabled()) log.trace(" Loading resource completed"); } catch(Throwable t) { log.error("loadLocale()", t); if(is != null) try { is.close(); } catch(Throwable u) { } } if(props.size() < 1) return; synchronized(messages) { String key; for(Enumeration names = props.keys(); names.hasMoreElements(); messages.put(messageKey(localeKey, key), props.getProperty(key))) { key = (String)names.nextElement(); if(log.isTraceEnabled()) log.trace(" Saving message key '" + messageKey(localeKey, key)); } } } return; } static { log = LogFactory.getLog(MultiPropertyMessageResources.class); } } |
Il faut ensuite écrire un Factory pour Struts :
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | package bla.bla.bla.struts; import org.apache.struts.util.MessageResources; import org.apache.struts.util.PropertyMessageResourcesFactory; public class MultiPropertyMessageResourcesFactory extends PropertyMessageResourcesFactory { public MultiPropertyMessageResourcesFactory() { } public MessageResources createResources(String config) { return new MultiPropertyMessageResources(this, config, returnNull); } } |
Puis, il ne reste plus qu'à modifier le struts-config.xml :
Code xml : | Sélectionner tout |
1 2 3 4 | <message-resources parameter="fichier1,fichier2,fichier3" factory="bla.bla.bla.struts.MultiPropertyMessageResourcesFactory" /> |
Cette solution règle bien évidemment le problème pour toutes les ressources utilisées par Struts, en particulier le plugin Validator.
Pour pouvoir utiliser un ResourceBundle défini en dehors du classpath, il faut déclarer un module de chargement de ressources comme suit.
Remarque : cette classe est une version améliorée de celle proposée pour la question sur le chargement de plusieurs ResourceBundle (cf. lien).
Ses fonctionnalités sont les suivantes :
- support de fichier de ressources multiples recours aux clés de bundle ;
- accepte les ressources dans le classpath ;
- accepte les ressources de type URL.
Code java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 | package com.vvic.struts.utils; import java.io.InputStream; import java.net.URL; import java.util.Enumeration; import java.util.Properties; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.struts.util.MessageResourcesFactory; import org.apache.struts.util.PropertyMessageResources; public class MultiPropertyMessageResources extends PropertyMessageResources { protected static final Log log; public MultiPropertyMessageResources(MessageResourcesFactory factory, String config) { super(factory, config); log.info("Initializing, config='" + config + "'"); } public MultiPropertyMessageResources(MessageResourcesFactory factory, String config, boolean returnNull) { super(factory, config, returnNull); log.info("Initializing, config='" + config + "', returnNull=" + returnNull); } protected void loadLocale(String localeKey) { label0: { if (log.isTraceEnabled()) log.trace("loadLocale(" + localeKey + ")"); synchronized (locales) { if (locales.get(localeKey) == null) break label0; } return; } locales.put(localeKey, localeKey); String configFiles[] = config.split(","); for (int i = 0; i < configFiles.length; i++) { String name = configFiles[i].trim().replace('.', '/'); if (localeKey.length() > 0) name = name + "_" + localeKey; name = name + ".properties"; InputStream is = null; Properties props = new Properties(); try { if (log.isTraceEnabled()) log.trace(" Loading resource '" + name + "'"); ClassLoader classLoader = Thread.currentThread() .getContextClassLoader(); if (classLoader == null) classLoader = getClass().getClassLoader(); is = classLoader.getResourceAsStream(name); if (is != null) { props.load(is); is.close(); } if (log.isTraceEnabled()) log.trace(" Loading resource completed"); } catch (Throwable t) { log.error("loadLocale()", t); if (is != null) try { is.close(); } catch (Throwable u) { } } if (props.size() < 1) { try { is = new URL(name).openStream(); props.load(is); is.close(); } catch (Throwable t) { log.error("loadLocale()", t); } } if (props.size() < 1) { log.warn("Unable to load resource " + name); return; } synchronized (messages) { String key; for (Enumeration names = props.keys(); names.hasMoreElements(); messages .put(messageKey(localeKey, key), props.getProperty(key))) { key = (String) names.nextElement(); if (log.isTraceEnabled()) log.trace(" Saving message key '" + messageKey(localeKey, key)); } } } return; } static { log = LogFactory.getLog(MultiPropertyMessageResources.class); } } |
Exemple de configuration dans le fichier struts-config.xml :
Code xml : | Sélectionner tout |
1 2 3 4 | <message-resources parameter="resources.application,file:///workspace/globalResources/erreurs" factory="com.vvic.struts.utils.MultiPropertyMessageResourcesFactory" /> |
Pour gérer l'encodage des caractères à afficher, il peut être nécessaire de passer par ceci en Struts1.
Créer une classe qui implémente l'interface Filter et dans la méthode doFilter faire l'encodage en UTF8 :
Code Java : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | package chemin.filter import java.io.IOException; import javax.servlet.*; public class encodeUtf8 implements Filter{ public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { request.setCharacterEncoding("UTF-8"); chain.doFilter(request, response); response.setCharacterEncoding("UTF-8"); } public void init(FilterConfig filterConfig) throws ServletException {} public void destroy() {} } |
Ajouter dans le fichier web.xml :
Code XML : | Sélectionner tout |
1 2 3 4 5 6 7 8 | <filter> <filter-name>encodeUtf8</filter-name> <filter-class>chemin.filter.encodeUtf8</filter-class> </filter> <filter-mapping> <filter-name>encodeUtf8</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> |
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.