Comment faire fonctionner UTF-8 dans les webapps Java?

367

J'ai besoin de faire fonctionner UTF-8 dans ma webapp Java (servlets + JSP, aucun framework utilisé) pour prendre en charge äöåetc. pour le texte finlandais régulier et les alphabets cyrilliques comme ЦжФpour les 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?

kosoant
la source

Réponses:

552

Me répondre car la FAQ de ce site l'encourage. Cela fonctionne pour moi:

La plupart du temps, les caractères äåö ne sont pas problématiques car le jeu de caractères par défaut utilisé par les navigateurs et tomcat / java pour les applications Web est latin1, c'est-à-dire. ISO-8859-1 qui "comprend" ces caractères.

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

Configuration de server.xml de Tomcat

Il est nécessaire de configurer que le connecteur utilise UTF-8 pour coder les paramètres url (demande 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"
/>

L'élément 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. Par conséquent, lorsque l'utilisateur écrit ce qui suit 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 encodé en (généralement par le navigateur avant même d'arriver au serveur) en tant que % D0% B6 .

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

CharsetFilter

Il est alors temps de forcer la webapp 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 garantit que si le navigateur n'a pas défini l'encodage utilisé dans la demande, il est défini sur UTF-8.

L'autre chose effectuée par ce filtre est de définir l'encodage de réponse par défaut, c'est-à-dire. l'encodage dans lequel le code HTML renvoyé / quel qu'il soit. L'alternative consiste à définir le codage de réponse, etc. dans chaque contrôleur de l'application.

Ce filtre doit être ajouté au web.xml ou au 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 wiki tomcat ( 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>

Alternativement, 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 une sorte de mise en page avec différents fragments JSP est utilisée, cela est nécessaire dans chacun d'eux.

Balises HTML-méta

L'encodage de page JSP indique à la JVM de gérer les caractères de la page JSP dans l'encodage correct. Ensuite, il est temps de dire au navigateur dans lequel l'encodage de la page html est:

Cela se 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

Lors de l'utilisation d'une base de données, il faut définir que la connexion utilise le codage UTF-8. Cela se fait dans context.xml ou partout où la connexion JDBC est désactivé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 également être en UTF-8:

   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é. Généralement, cela se fait sous Windows en modifiant my.ini -file et sous Linux en configurant my.cnf -file. Dans ces fichiers, il convient de 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 ;

Demandes GET: latin1 et UTF-8

Si et quand il est défini dans server.xml de tomcat que les paramètres de requête GET sont encodés en UTF-8, les requêtes GET suivantes sont traitées correctement:

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

Étant donné que 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 du tout compris en latin1. Étant donné que Tomcat est chargé de gérer les paramètres de demande au format UTF-8, il code correctement ce caractère en tant que % D0% B6 .

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

Le résultat final est que tous les utilisateurs avec le nom "Petteri" sont trouvés et aussi tous les utilisateurs avec le nom "ж".

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

La spécification HTTP définit que, par défaut, les URL sont codées en latin1. Il en résulte que firefox2, firefox3 etc. codent les éléments suivants

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

dans la version codée

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

En latin1, le caractère ä est codé en % E4 . Même si la page / demande / tout est défini pour utiliser UTF-8 . La version codée UTF-8 de ä est % C3% A4

Le résultat de cela est qu'il est tout à fait impossible pour la webapp de gérer correctement les paramètres de requête des requêtes GET car certains caractères sont encodés en latin1 et d'autres en UTF-8. Remarque: les demandes POST fonctionnent comme les navigateurs codent tous les paramètres de demande des formulaires complètement en UTF-8 si la page est définie comme étant UTF-8

Des trucs à lire

Un très grand merci aux rédacteurs suivants pour avoir donné les réponses à 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

prend en charge le plan multilingue de base en utilisant des caractères UTF-8 à 3 octets. Si vous devez aller au-delà de cela (certains alphabets nécessitent plus de 3 octets de UTF-8), alors vous devez soit utiliser une saveur de VARBINARYtype colonne, soit utiliser le utf8mb4jeu de caractères (qui nécessite MySQL 5.5.3 ou une version ultérieure). Sachez simplement que l'utilisation du utf8jeu de caractères dans MySQL ne fonctionnera pas à 100%.

Tomcat avec Apache

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

  1. Ajoutez URIEncoding = "UTF-8" dans le fichier tomcat server.xml 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. Aller à votre dossier apache -à- dire /etc/httpd/confet ajouter AddDefaultCharset utf-8à httpd.conf file. Remarque: Vérifiez d'abord qu'elle existe ou non. S'il existe, vous pouvez le mettre à jour avec cette ligne. Vous pouvez également ajouter cette ligne en bas.
kosoant
la source
Ces étapes fonctionnent également avec Struts / tiles et une base de données postgres.
kosoant
17
Deux commentaires: 1) dans les balises HMTL-meta, vous avez inclus une déclaration xml. Supprimez-le, cela ne déclencherait que les navigateurs en mode excentrique, vous ne voulez pas avoir cela. En outre, les balises META HTML sont en fait déjà implicitement effectuées par JSP pageEncoding, vous pouvez même les laisser de côté. 2) dans la base de données MySQL et les tables que vous avez utilisées utf8_swedish_si, cela aurait dû l'être utf8_unicode_ci. Vous pouvez même laisser la collation de côté, c'est juste CHARACTER SET utf8assez.
BalusC
Aucun des documents que j'ai consultés concernant les balises META HTML et le mode excentrique (par exemple, ericmeyeroncss.com/bonus/render-mode.html , en.wikipedia.org/wiki/Quirks_mode ) n'indique que la présence de <meta http-equiv = 'Content -Type 'a un impact sur le mode de rendu.
Marcel Stör
Remarque intéressante, vous pouvez également savoir que si un écouteur accède à un paramètre de demande, vous devrez ajouter un écouteur qui définit le jeu de caractères au lieu d'un filtre car les écouteurs sont exécutés avant les filtres. J'ai suivi toutes les étapes et cela n'a toujours pas fonctionné à cause de cela. Je pensais juste que je transmettrais ces informations au cas où quelqu'un d'autre aurait un problème similaire.
testing123
3
## Tomcat avec Apache ## Encore une chose Si vous utilisez le connecteur Apache + Tomcat + mod_JK, vous devez également effectuer les modifications suivantes: 1. Ajoutez URIEncoding = "UTF-8" dans le fichier tomcat server.xml 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, c'est-à /etc/httpd/conf- dire et ajoutez AddDefaultCharset utf-8le fichier 'httpd.conf'. Remarque: vérifiez d'abord qu'elle existe ou non. S'il existe, vous pouvez le mettre à jour avec cette ligne. Vous pouvez également ajouter cette ligne en bas.
Vijay Shegokar
14

Je pense que vous l'avez assez bien résumé dans votre propre réponse.

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

stian
la source
Cela m'a aidé, j'ai fait tout ce qui était mentionné, mais l'encodage JVM était Windows-1250 dès que je suis passé en UTF-8, cela fonctionnait parfaitement.
coding_idiot
2
Où ajoutez-vous cela dans le fichier Catalina.bat, s'il vous plaît?
Noah
11

Pour ajouter à la réponse de kosoant , si vous utilisez Spring, plutôt que d'écrire votre propre filtre de servlet, vous pouvez utiliser la classe org.springframework.web.filter.CharacterEncodingFilterqu'ils fournissent, en la configurant comme suit dans votre 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>
Raedwald
la source
1
Ce filtre doit être le premier filtre dans web.xml
olyanren
2

Je veux aussi ajouter d' ici cette partie résolu mon problème utf:

runtime.encoding=<encoding>
John
la source
1

C'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 voulez pas mettre cela 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 moi et Nick, nous ne l'oublions jamais et perdons plus de temps .....

Mike Mountrakis
la source
5
Je préférerais toujours UTF-8 au-dessus du grec (et convertir vos données grecques actuelles en UTF-8) afin que votre application soit prête pour la domination du monde.
BalusC
1

Belle réponse détaillée. je voulais juste ajouter une chose qui aidera certainement les autres à voir le codage 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 fausse par défaut, réglez-la sur TRUE.
  4. redémarrez le navigateur.

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

Geai
la source
1

Les réponses précédentes ne fonctionnaient pas avec mon problème. C'était seulement en production, avec tomcat et apache mod_proxy_ajp. Le corps du message a perdu des caractères non ascii par? Le problème était finalement avec JVM defaultCharset (US-ASCII dans une installation par défaut: Charset dfset = Charset.defaultCharset ();) donc, la solution a été exécutée tomcat server avec un modificateur pour exécuter la JVM 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 redémarrez le service tomcat)

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

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

export LANGUAGE = en_US.UTF-8

Rogelio Triviño
la source
0

Je suis avec un problème similaire, mais, dans les noms de fichiers 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 cela aidera n'importe qui;)

caarlos0
la source
0

Pour mon cas d'affichage de caractère Unicode à partir de groupes de messages, je n'ai pas besoin d'appliquer la section "Encodage de page JSP" pour afficher Unicode sur ma page jsp. Tout ce dont j'ai besoin, c'est de la section "CharsetFilter".

bnguyen82
la source
0

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

Dans une application Web, je suivais les premières instructions d'un livre Ajax pour envelopper le 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 lancer leur propre Ajax ces jours-ci, mais j'ai pensé que je pourrais aussi bien ajouter cela.

David
la source
0

À propos CharsetFiltermentionné dans la réponse @kosoant ....

Il y a un build in Filterdans tomcat web.xml(situé à conf/web.xml). Le filtre est nommé setCharacterEncodingFilteret est commenté par défaut. Vous pouvez décommenter cela (n'oubliez pas de décommenter son filter-mappingaussi)

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

Alireza Fattahi
la source
0

Un certain temps, vous pouvez résoudre le problème via l'assistant administrateur 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.

user3600935
la source
0

Face au même problème sur Spring MVC 5 + Tomcat 9 + JSP.
Après de longues recherches, est arrivée une solution élégante ( pas besoin de filtres et pas de changements nécessaires dans le 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 lire les données des fichiers source des 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 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 messages et affichez les fichiers au format UTF-8.

  4. Ajoutez <% @ page contentType = "text / html; charset = UTF-8"%> ou <% @ page pageEncoding = "UTF-8"%> dans chaque fichier * .jsp ou ajoutez un 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>
Andrei Veshtard
la source
-1

Si vous avez spécifié dans le pool de connexions (mysql-ds.xml), dans votre code Java, vous pouvez ouvrir la connexion comme suit:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://192.168.1.12:3308/mydb?characterEncoding=greek",
    "Myuser", "mypass");
Mike Mountrakis
la source