web-dev-qa-db-fra.com

Comment faire fonctionner UTF-8 dans Java webapps?

J'ai besoin que UTF-8 fonctionne dans mon Java webapp (servlets + JSP, sans framework) pour prendre en charge äöå etc. pour le texte finlandais et les alphabets cyrilliques tels que ЦжФ pour cas spéciaux.

Ma configuration est la suivante:

  • Environnement de développement: Windows XP
  • Environnement de production: Debian

Base de données utilisée: MySQL 5.x

Les utilisateurs utilisent principalement Firefox2 mais aussi Opera 9.x, FF3, IE7 et Google Chrome sont utilisés pour accéder au site.

Comment y parvenir?

362
kosoant

Je me réponds comme le FAQ de ce site l'encourage. Cela fonctionne pour moi:

Généralement, les caractères äåö ne posent pas de problème car le jeu de caractères par défaut utilisé par les navigateurs et Tomcat/Java pour les applications Web est latin1, à savoir. ISO-8859-1 qui "comprend" ces caractères.

Pour que UTF-8 fonctionne sous Java + Tomcat + Linux/Windows + Mysql, vous devez:

Configuration du fichier server.xml de Tomcat

Il est nécessaire de configurer le connecteur pour qu’il utilise UTF-8 pour coder les paramètres d’URL (requête GET):

<Connector port="8080" maxHttpHeaderSize="8192"
 maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
 enableLookups="false" redirectPort="8443" acceptCount="100"
 connectionTimeout="20000" disableUploadTimeout="true" 
 compression="on" 
 compressionMinSize="128" 
 noCompressionUserAgents="gozilla, traviata" 
 compressableMimeType="text/html,text/xml,text/plain,text/css,text/ javascript,application/x-javascript,application/javascript"
 URIEncoding="UTF-8"
/>

La partie clé étant URIEncoding = "UTF-8" dans l'exemple ci-dessus. Cela garantit que Tomcat gère tous les paramètres GET entrants au format UTF-8 codé. Par conséquent, lorsque l'utilisateur écrit les informations suivantes dans la barre d'adresse du navigateur:

 https://localhost:8443/ID/Users?action=search&name=*ж*

le caractère Ö est traité comme UTF-8 et est codé (généralement par le navigateur avant même d’arriver sur le serveur) comme % D0% B6.

Les requêtes POST ne sont pas concernées par cela.

CharsetFilter

Ensuite, il est temps de forcer l'application web Java à gérer toutes les demandes et réponses au format UTF-8. Cela nécessite que nous définissions un filtre de jeu de caractères comme suit:

package fi.foo.filters;

import javax.servlet.*;
import Java.io.IOException;

public class CharsetFilter implements Filter {

    private String encoding;

    public void init(FilterConfig config) throws ServletException {
        encoding = config.getInitParameter("requestEncoding");
        if (encoding == null) encoding = "UTF-8";
    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain next)
            throws IOException, ServletException {
        // Respect the client-specified character encoding
        // (see HTTP specification section 3.4.1)
        if (null == request.getCharacterEncoding()) {
            request.setCharacterEncoding(encoding);
        }

        // Set the default response content type and encoding
        response.setContentType("text/html; charset=UTF-8");
        response.setCharacterEncoding("UTF-8");

        next.doFilter(request, response);
    }

    public void destroy() {
    }
}

Ce filtre vérifie que, si le navigateur n'a pas défini le codage utilisé dans la demande, il est défini sur UTF-8.

Ce filtre permet également de définir le codage de la réponse par défaut, c'est-à-dire. l'encodage dans lequel le html retourné/quel que soit est. L'alternative consiste à définir le codage de la réponse, etc. dans chaque contrôleur de l'application.

Ce filtre doit être ajouté à la web.xml ou le descripteur de déploiement de la webapp:

 <!--CharsetFilter start--> 

  <filter>
    <filter-name>CharsetFilter</filter-name>
    <filter-class>fi.foo.filters.CharsetFilter</filter-class>
      <init-param>
        <param-name>requestEncoding</param-name>
        <param-value>UTF-8</param-value>
      </init-param>
  </filter>

  <filter-mapping>
    <filter-name>CharsetFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>

Les instructions pour créer ce filtre se trouvent sur le Tomcat wiki (http://wiki.Apache.org/Tomcat/Tomcat/UTF-8 )

Encodage de page JSP

Dans votre web.xml , ajoutez les éléments suivants:

<jsp-config>
    <jsp-property-group>
        <url-pattern>*.jsp</url-pattern>
        <page-encoding>UTF-8</page-encoding>
    </jsp-property-group>
</jsp-config>

Autrement, toutes les pages JSP de la webapp devraient avoir les éléments suivants en haut:

 <%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>

Si un type de présentation avec différents fragments JSP est utilisé, cela est nécessaire dans tout d'eux.

Balises méta HTML

Le codage de page JSP indique à la machine virtuelle Java de gérer les caractères de la page JSP avec le codage correct. Ensuite, il est temps d'indiquer au navigateur dans quel encodage la page html est:

Ceci est fait avec ce qui suit en haut de chaque page xhtml produite par la webapp:

   <?xml version="1.0" encoding="UTF-8"?>
   <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
   <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="fi">
   <head>
   <meta http-equiv='Content-Type' content='text/html; charset=UTF-8' />
   ...

Connexion JDBC

Lorsque vous utilisez une base de données, vous devez définir que la connexion utilise le codage UTF-8. Ceci est fait dans context.xml ou partout où la connexion JDBC est configurée comme suit:

      <Resource name="jdbc/AppDB" 
        auth="Container"
        type="javax.sql.DataSource"
        maxActive="20" maxIdle="10" maxWait="10000"
        username="foo"
        password="bar"
        driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/      ID_development?useEncoding=true&amp;characterEncoding=UTF-8"
    />

Base de données et tables MySQL

La base de données utilisée doit utiliser le codage UTF-8. Ceci est réalisé en créant la base de données avec les éléments suivants:

   CREATE DATABASE `ID_development` 
   /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci */;

Ensuite, toutes les tables doivent être en UTF-8 également:

   CREATE TABLE  `Users` (
    `id` int(10) unsigned NOT NULL auto_increment,
    `name` varchar(30) collate utf8_swedish_ci default NULL
    PRIMARY KEY  (`id`)
   ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_swedish_ci ROW_FORMAT=DYNAMIC;

La partie clé étant CHARSET = utf8.

Configuration du serveur MySQL

Le serveur MySQL doit également être configuré. Cela se fait généralement sous Windows en modifiant my.ini -file et sous Linux en configurant mon.cnf -fichier. Dans ces fichiers, vous devez définir que tous les clients connectés au serveur utilisent utf8 comme jeu de caractères par défaut et que le jeu de caractères par défaut utilisé par le serveur est également utf8.

   [client]
   port=3306
   default-character-set=utf8

   [mysql]
   default-character-set=utf8

Procédures et fonctions Mysql

Ceux-ci doivent également avoir le jeu de caractères défini. Par exemple:

   DELIMITER $$

   DROP FUNCTION IF EXISTS `pathToNode` $$
   CREATE FUNCTION `pathToNode` (ryhma_id INT) RETURNS TEXT CHARACTER SET utf8
   READS SQL DATA
   BEGIN

    DECLARE path VARCHAR(255) CHARACTER SET utf8;

   SET path = NULL;

   ...

   RETURN path;

   END $$

   DELIMITER ;

Requêtes GET: latin1 et UTF-8

Si et quand il est défini dans le fichier server.xml de Tomcat que les paramètres de requête GET sont codés en UTF-8, les requêtes GET suivantes sont gérées correctement:

   https://localhost:8443/ID/Users?action=search&name=Petteri
   https://localhost:8443/ID/Users?action=search&name=ж

Comme les caractères ASCII sont codés de la même manière avec latin1 et UTF-8, la chaîne "Petteri" est gérée correctement.

Le caractère cyrillique n'est pas compris du tout en latin1. Étant donné que Tomcat est chargé de gérer les paramètres de requête en UTF-8, il code ce caractère correctement. % D0% B6.

Si et quand les navigateurs sont invités à lire les pages en codage UTF-8 (avec les en-têtes de requête et la méta-balise html), au moins Firefox 2/3 et les autres navigateurs de cette période codent tous le caractère % D0% B6.

Le résultat final est que tous les utilisateurs portant le nom "Petteri" sont trouvés, ainsi que tous les utilisateurs portant le nom "ж".

Mais qu'en est-il de äåö?

La spécification HTTP définit que, par défaut, les URL sont codées en tant que latin1. Ceci a pour résultat que firefox2, firefox3, etc.

    https://localhost:8443/ID/Users?action=search&name=*Päivi*

dans la version encodée

    https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*

En latin1 le personnage une est codé comme % E4. Même si la page/request/tout est défini pour utiliser UTF-8 . La version codée UTF-8 de ä est % C3% A4

En conséquence, il est pratiquement impossible pour l'application Web de gérer correctement les paramètres de requête provenant de requêtes GET, car certains caractères sont codés en latin1 et d'autres en UTF-8. Remarque: les requêtes POST fonctionnent comme les navigateurs encodent complètement tous les paramètres de requête des formulaires en UTF-8 si la page est définie comme étant en UTF-8.

Stuff à lire

Un très grand merci aux auteurs de ce qui suit pour avoir répondu à mon problème:

  • http://tagunov.tripod.com/i18n/i18n.html
  • http://wiki.Apache.org/Tomcat/Tomcat/UTF-8
  • http://Java.Sun.com/developer/technicalArticles/Intl/HTTPCharset/
  • http://dev.mysql.com/doc/refman/5.0/en/charset-syntax.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-Tomcat-jsp-etc.html
  • http://cagan327.blogspot.com/2006/05/utf-8-encoding-fix-for-mysql-Tomcat.html
  • http://jeppesn.dk/utf-8.html
  • http://www.nabble.com/request-parameters-mishandle-utf-8-encoding-td18720039.html
  • http://www.utoronto.ca/webdocs/HTMLdocs/NewHTML/iso_table.html
  • http://www.utf8-chartable.de/

Note importante

mysql supporte le plan multilingue de base utilisant des caractères UTF-8 à 3 octets. Si vous devez aller en dehors de cela (certains alphabets nécessitent plus de 3 octets de UTF-8), vous devez utiliser un type de colonne VARBINARY ou utiliser le type utf8mb4 jeu de caractères (qui requiert MySQL 5.5.3 ou une version ultérieure). Sachez simplement que l'utilisation du jeu de caractères utf8 dans MySQL ne fonctionnera pas à 100% du temps.

Tomcat avec Apache

Encore une chose Si vous utilisez le connecteur Apache + Tomcat + mod_JK, vous devez également apporter les modifications suivantes:

  1. Ajoutez URIEncoding = "UTF-8" dans le fichier server.xml de Tomcat pour le connecteur 8009; il est utilisé par le connecteur mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Allez dans votre dossier Apache, à savoir /etc/httpd/conf et ajoutez AddDefaultCharset utf-8 dans httpd.conf file. Remarque: Vérifiez d'abord qu'il existe ou non. S'il existe, vous pouvez le mettre à jour avec cette ligne. Vous pouvez aussi ajouter cette ligne en bas.
543
kosoant

Je pense que vous avez très bien résumé la situation dans votre propre réponse.

Dans le processus de UTF-8-ing (?) De bout en bout, vous pouvez également vous assurer que Java lui-même utilise UTF-8. Utilisez -Dfile.encoding = utf-8 en tant que paramètre de la machine virtuelle Java (peut être configuré dans catalina.bat).

12
stian

Pour ajouter à réponse de kosoant , si vous utilisez Spring, plutôt que d'écrire votre propre filtre Servlet, vous pouvez utiliser la classe org.springframework.web.filter.CharacterEncodingFilter fournie, en le configurant comme suit dans votre fichier web.xml. :

 <filter>
    <filter-name>encoding-filter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
       <param-name>encoding</param-name>
       <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
       <param-name>forceEncoding</param-name>
       <param-value>FALSE</param-value>
    </init-param>
 </filter>
 <filter-mapping>
    <filter-name>encoding-filter</filter-name>
    <url-pattern>/*</url-pattern>
 </filter-mapping>
11
Raedwald

Je veux aussi ajouter de ici cette partie a résolu mon problème avec utf:

runtime.encoding=<encoding>
2
John

Belle réponse détaillée. je voulais juste ajouter une chose qui aidera certainement les autres à voir l'encodage UTF-8 sur les URL en action.

Suivez les étapes ci-dessous pour activer le codage UTF-8 sur les URL dans Firefox.

  1. tapez "about: config" dans la barre d'adresse.

  2. Utilisez le type d'entrée de filtre pour rechercher la propriété "network.standard-url.encode-query-utf8".

  3. la propriété ci-dessus sera false par défaut, réglez-le sur TRUE.
  4. redémarrez le navigateur.

Le codage UTF-8 sur les URL fonctionne par défaut dans IE6/7/8 et chrome.

1
Jay

Ceci est pour le codage grec dans les tables MySql lorsque nous voulons y accéder en utilisant Java:

Utilisez la configuration de connexion suivante dans votre pool de connexions JBoss (mysql-ds.xml)

<connection-url>jdbc:mysql://192.168.10.123:3308/mydatabase</connection-url>
<driver-class>com.mysql.jdbc.Driver</driver-class>
<user-name>nts</user-name>
<password>xaxaxa!</password>
<connection-property name="useUnicode">true</connection-property>
<connection-property name="characterEncoding">greek</connection-property>

Si vous ne souhaitez pas placer ceci dans un pool de connexions JNDI, vous pouvez le configurer comme une url JDBC, comme l'illustre la ligne suivante:

jdbc:mysql://192.168.10.123:3308/mydatabase?characterEncoding=greek

Pour Nick et moi, nous ne l'oublions jamais et nous ne perdons plus de temps .....

1
Mike Mountrakis

Quelque temps, vous pouvez résoudre le problème avec l’assistant administrateur de MySQL. Dans

Variables de démarrage> Avancé>

et définissez Def. Jeu de caractères: utf8

Peut-être que cette configuration doit redémarrer MySQL.

0
user3600935

Les réponses précédentes ne fonctionnaient pas avec mon problème. Ce n'était qu'en production, avec Tomcat et Apache mod_proxy_ajp. Les corps non postés ont-ils été perdus? Le problème était finalement avec JVM defaultCharset (US-ASCII dans une installation par défaut: Charset dfset = Charset.defaultCharset ();), la solution a donc été exécutée sur le serveur Tomcat avec un modificateur pour exécuter la machine virtuelle avec UTF-8 comme jeu de caractères par défaut:

Java_OPTS="$Java_OPTS -Dfile.encoding=UTF-8" 

(ajoutez cette ligne à catalina.sh et au service Tomcat redémarrez)

Peut-être devriez-vous aussi changer la variable système linux (éditez les fichiers ~/.bashrc et ~/.profile pour un changement permanent, voir https://perlgeek.de/en/article/set-up-a-clean-utf8- environnement )

exportation LC_ALL = en_US.UTF-8
export LANG = en_US.UTF-8

export LANGUAGE = en_US.UTF-8

0
Rogelio

Face au même problème sur Spring MVC 5 + Tomcat 9 + JSP.
Après de longues recherches, une solution élégante (non besoin filtres et non besoin modifications = dans Tomcat server.xml (à partir de la version 8.0.0-RC3))

  1. Dans l'implémentation WebMvcConfigurer, définissez le codage par défaut pour messageSource (pour la lecture de données à partir de fichiers source de messages dans le codage UTF-8.

    @Configuration
    @EnableWebMvc
    @ComponentScan("{package.with.components}")
    public class WebApplicationContextConfig implements WebMvcConfigurer {
    
        @Bean
        public MessageSource messageSource() {
            final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    
            messageSource.setBasenames("messages");
            messageSource.setDefaultEncoding("UTF-8");
    
            return messageSource;
        }
    
        /* other beans and methods */
    
    }
    
  2. Dans l'implémentation DispatcherServletInitializer, @Override la méthode onStartup et définissez-y le codage des caractères de demande et de ressource.

    public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        public void onStartup(final ServletContext servletContext) throws ServletException {
    
            // https://wiki.Apache.org/Tomcat/FAQ/CharacterEncoding
            servletContext.setRequestCharacterEncoding("UTF-8");
            servletContext.setResponseCharacterEncoding("UTF-8");
    
            super.onStartup(servletContext);
        }
    
        /* servlet mappings, root and web application configs, other methods */
    
    }
    
  3. Enregistrez toutes les sources de message et affichez les fichiers au format UTF-8.

  4. Ajoutez <% @ page contentType = "text/html; charset = UTF-8"%> o <% @ page pageEncoding = "UTF-8"%> dans chaque fichier * .jsp o ajouter le descripteur jsp-config à web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://Java.Sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://Java.Sun.com/xml/ns/javaee http://Java.Sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
        <display-name>AppName</display-name>
    
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <page-encoding>UTF-8</page-encoding>
            </jsp-property-group>
        </jsp-config>
    </web-app>
    
0
Andrei Veshtard

À propos de CharsetFilter mentionné dans la réponse @kosoant ....

Il existe une construction dans Filter dans Tomcat web.xml (située à conf/web.xml). Le filtre s'appelle setCharacterEncodingFilter et est commenté par défaut. Vous pouvez décommenter ceci (n'oubliez pas de décommenter son filter-mapping aussi)

De plus, il n'est pas nécessaire de définir jsp-config dans votre web.xml (je l'ai testé pour Tomcat 7+).

0
Alireza Fattahi

Dans mon cas d'affichage de caractères Unicode à partir d'ensembles de messages, il n'est pas nécessaire d'appliquer la section "Codage de page JSP" pour afficher Unicode sur ma page jsp. Tout ce dont j'ai besoin, c'est de la section "CharsetFilter".

0
bnguyen82

Je suis avec un problème similaire, mais, dans les noms de fichier d'un fichier, je compresse avec Apache commons. Donc, je l'ai résolu avec cette commande:

convmv --notest -f cp1252 -t utf8 * -r

ça marche très bien pour moi. J'espère que ça aidera quelqu'un;)

0
caarlos0

Un autre point qui n'a pas été mentionné concerne Java Servlets fonctionnant avec Ajax. J'ai des situations où une page Web récupère le texte utf-8 de l'utilisateur l'envoyant dans un fichier JavaScript qui l'inclut dans un URI envoyé au Servlet. Le servlet interroge une base de données, capture le résultat et le renvoie sous forme XML au fichier JavaScript qui le formate et insère la réponse formatée dans la page Web d'origine.

Dans une application Web, je suivais les instructions d'un livre Ajax ancien pour intégrer le code JavaScript dans la construction de l'URI. L'exemple du livre utilise la méthode escape (), que j'ai découverte (à la dure) est fausse. Pour utf-8, vous devez utiliser encodeURIComponent ().

Peu de gens semblent avoir leur propre Ajax ces jours-ci, mais je pensais aussi bien pouvoir ajouter ceci.

0
David