Cómo hacer que UTF-8 funcione en Java webapps?


Necesito que UTF-8 funcione en mi aplicación web Java (servlets + JSP, no se usa framework) para soportar äöå, etc. para texto finlandés regular y alfabetos cirílicos como ЦжФ para casos especiales.

Mi configuración es la siguiente:

  • Entorno de desarrollo: Windows XP
  • Entorno de producción: Debian

Base de datos utilizada: MySQL 5.x

Los usuarios utilizan principalmente Firefox2 pero también Opera 9.x, FF3, IE7 y Google Chrome se utilizan para acceder al sitio.

Cómo lograr esto?

Author: informatik01, 2008-09-26

13 answers

Responderme a mí mismo como las preguntas frecuentes de este sitio lo alienta. Esto funciona para mí:

La mayoría de los caracteres äåö no son un problema, ya que el conjunto de caracteres predeterminado utilizado por los navegadores y tomcat/java para aplicaciones web es latin1 ie. ISO-8859-1 que "entiende" esos caracteres.

Para que UTF-8 funcione en Java + Tomcat + Linux / Windows + Mysql se requiere lo siguiente:

Configurando el servidor de Tomcat.xml

Es necesario configurar que el conector utiliza UTF-8 para codificar parámetros de url (solicitud 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 parte clave es URIEncoding="UTF-8" en el ejemplo anterior. Esto garantiza que Tomcat maneje todos los parámetros GET entrantes codificados en UTF-8. Como resultado, cuando el usuario escribe lo siguiente en la barra de direcciones del navegador:

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

El carácter ж se maneja como UTF-8 y se codifica (generalmente por el navegador incluso antes de llegar al servidor) como %D0%B6.

POST solicitud son no se ve afectado por esto.

CharsetFilter

Entonces es el momento de forzar la aplicación web java para manejar todas las solicitudes y respuestas como UTF-8 codificado. Esto requiere que definamos un filtro de conjunto de caracteres como el siguiente:

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() {
    }
}

Este filtro se asegura de que si el navegador no ha establecido la codificación utilizada en la solicitud, que se establece en UTF-8.

La otra cosa que hace este filtro es establecer la codificación de respuesta predeterminada, es decir. la codificación en la que se devuelve html/lo que sea. La alternativa es establecer la codificación de la respuesta, etc. en cada controlador de la aplicación.

Este filtro debe añadirse a la web .xml o el descriptor de implementación 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>

Las instrucciones para hacer este filtro se encuentra en el tomcat wiki (http://wiki.apache.org/tomcat/Tomcat/UTF-8)

JSP page encoding

En su web.xml , añadir la siguiente:

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

Alternativamente, todas las páginas JSP de la aplicación web tendrían que tener lo siguiente en la parte superior de ellos:

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

Si se usa algún tipo de maquetación con fragmentos JSP diferentes, entonces esto es necesario en todos de ellos.

HTML-meta tags

JSP page encoding le dice a la JVM que maneje los caracteres en la página JSP con la codificación correcta. Entonces es el momento de decirle al navegador en qué codificación está la página html:

Esto está hecho con lo siguiente en la parte superior de cada página xhtml producida por 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' />
   ...

JDBC-conexión

Cuando se utiliza una bd, se debe definir que la conexión utiliza codificación UTF-8. Esto se hace en el contexto .xml o donde se defiend la conexión JDBC de la siguiente manera:

      <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 datos MySQL y tablas

La base de datos utilizada debe utilizar la codificación UTF-8. Esto se logra creando la base de datos con lo siguiente:

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

Entonces, todos los las tablas también deben estar 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 parte clave es CHARSET=utf8.

Configuración del servidor MySQL

MySQL serveri también tiene que ser configurado. Normalmente esto se hace en Windows modificando my.ini - archivo y en Linux configurando mi.cnf - archivo. En esos archivos se debe definir que todos los clientes conectados al servidor usen utf8 como el conjunto de caracteres predeterminado y que el conjunto de caracteres predeterminado utilizado por el servidor también utf8.

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

   [mysql]
   default-character-set=utf8

Procedimientos y funciones de Mysql

Estos también necesitan tener el conjunto de caracteres definido. Por ejemplo:

   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 ;

Peticiones GET: latin1 y UTF-8

Si y cuando se define en el servidor de tomcat.xml que los parámetros de la solicitud GET están codificados en UTF-8, las siguientes solicitudes GET se manejan correctamente:

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

Debido a que los caracteres ASCII se codifican de la misma manera tanto con latin1 como con UTF-8, la cadena "Petteri" se maneja correctamente.

El carácter cirílico ж no se entiende en absoluto en latin1. Debido a que Tomcat tiene instrucciones de manejar los parámetros de solicitud como UTF-8, codifica ese carácter correctamente como %D0%B6.

Si los navegadores tienen instrucciones de leer las páginas en codificación UTF-8 (con encabezados de solicitud y meta-etiqueta html), al menos Firefox 2/3 y otros navegadores de este período codifican el carácter como %D0%B6.

El resultado final es que todos se encuentran usuarios con el nombre "Petteri "y también se encuentran todos los usuarios con el nombre" ж".

Pero ¿qué pasa con äåö?

HTTP-specification define que por defecto las URL están codificadas como latin1. Esto resulta en firefox2, firefox3, etc. codificando lo siguiente

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

En la versión codificada

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

En latin1 el carácter ä está codificado como %E4. Aunque la página/request/everything está definida para usar UTF-8. El UTF-8 codificado la versión de ä es % C3 % A4

El resultado de esto es que es bastante imposible para la aplicación web manejar de lleno los parámetros de solicitud de las solicitudes GET, ya que algunos caracteres están codificados en latin1 y otros en UTF-8. Aviso: Las solicitudes POST funcionan ya que los navegadores codifican todos los parámetros de solicitud de los formularios completamente en UTF-8 si la página se define como UTF-8

Cosas para leer

Un agradecimiento muy grande para los escritores de la siguiente para dar la respuestas para mi problema:

  • 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 /

Nota importante

Mysql soporta el Plano Multilingüe Básico usando caracteres UTF-8 de 3 bytes. Si necesita salir de eso (ciertos alfabetos requieren más de 3 bytes de UTF-8), entonces necesita usar un tipo de columna VARBINARY o usar el utf8mb4 character set (que requiere MySQL 5.5.3 o posterior). Solo tenga en cuenta que usar el conjunto de caracteres utf8 en MySQL no funcionará el 100% del tiempo.

Tomcat con Apache

Una cosa más Si está utilizando Apache + Tomcat + mod_JK connector, también debe hacer los siguientes cambios:

  1. Agregue URIEncoding="UTF-8" en el servidor tomcat.archivo xml para conector 8009, es utilizado por el conector mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Vaya a su carpeta apache, es decir, /etc/httpd/conf y agregue AddDefaultCharset utf-8 en httpd.conf file. Nota: Primero compruebe que existe o no. Si existe puede actualizarlo con esta línea. Puede agregar esta línea en la parte inferior también.
 528
Author: kosoant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-11 16:07:44

Creo que lo resumió bastante bien en su propia respuesta.

En el proceso de UTF-8-ing(?) de extremo a extremo es posible que también desee asegurarse de que Java está utilizando UTF-8. Use-Dfile.encoding = utf-8 como parámetro de la JVM (se puede configurar en catalina.bate).

 12
Author: stian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-27 21:54:08

Para agregar a la respuesta de kosoant, si está utilizando Spring, en lugar de escribir su propio filtro de Servlet, puede usar la clase org.springframework.web.filter.CharacterEncodingFilter que proporcionan, configurándola de la siguiente manera en su 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>
 9
Author: Raedwald,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 10:31:13

Esto es para la codificación griega en tablas MySQL cuando queremos acceder a ellas usando Java:

Utilice la siguiente configuración de conexión en su grupo de conexiones 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 no desea poner esto en un grupo de conexiones JNDI, puede configurarlo como una url JDBC como se ilustra en la siguiente línea:

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

Para mí y Nick, para que nunca lo olvidemos y perdamos más el tiempo.....

 1
Author: Mike Mountrakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-12-04 13:52:33

Buena respuesta detallada. solo quería agregar una cosa más que definitivamente ayudará a otros a ver la codificación UTF-8 en las URL en acción .

Siga los pasos a continuación para habilitar la codificación UTF-8 en URL en firefox.

  1. Escriba "about: config" en la barra de direcciones.

  2. Utilice el tipo de entrada de filtro para buscar " red.estándar-url.propiedad encode-query-utf8".

  3. la propiedad anterior será false por defecto, gire eso a TRUE.
  4. reinicie el navegador.

La codificación UTF-8 en URLs funciona por defecto en IE6/7/8 y chrome.

 1
Author: Jay,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-19 01:30:34

También quiero agregar desde aquí esta parte resolvió mi problema utf:

runtime.encoding=<encoding>
 1
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-01-15 02:19:46

Estoy con un problema similar, pero, en los nombres de archivo de un archivo que estoy comprimiendo con apache commons. Entonces, lo resolví con este comando:

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

Funciona muy bien para mí. Espero que ayude a alguien;)

 0
Author: caarlos0,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-07-20 13:45:30

Para mi caso de mostrar caracteres Unicode de paquetes de mensajes, no necesito aplicar la sección "Codificación de página JSP" para mostrar Unicode en mi página jsp. Todo lo que necesito es la sección" CharsetFilter".

 0
Author: bnguyen82,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-21 01:59:03

Otro punto que no se ha mencionado se refiere a los Servlets Java que trabajan con Ajax. Tengo situaciones en las que una página web está recogiendo texto utf-8 del usuario enviando esto a un archivo JavaScript que lo incluye en un URI enviado al Servlet. El Servlet consulta una base de datos, captura el resultado y lo devuelve como XML al archivo JavaScript que lo formatea e inserta la respuesta formateada en la página web original.

En una aplicación web estaba siguiendo un libro de Ajax temprano instrucciones para envolver el JavaScript en la construcción del URI. El ejemplo en el libro usó el método escape (), que descubrí (de la manera difícil) está mal. Para utf-8 debe usar encodeURIComponent ().

Pocas personas parecen rodar su propio Ajax en estos días, pero pensé que también podría agregar esto.

 0
Author: David,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-11-14 22:30:51

Acerca de CharsetFilter mencionado en la respuesta de @kosoant ....

Hay una compilación en Filter en tomcat web.xml (ubicado en conf/web.xml). El filtro se llama setCharacterEncodingFilter y se comenta por defecto. Puede descomentar esto (Por favor recuerde descomentar su filter-mapping también)

Tampoco hay necesidad de establecer jsp-config en su web.xml (tengo que probarlo para Tomcat 7+)

 0
Author: Alireza Fattahi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-01-09 05:24:48

En algún momento puede resolver el problema a través del asistente de Administrador de MySQL. En

Variables de inicio > Avanzado >

Y establecer Def. conjunto de caracteres: utf8

Tal vez esta configuración necesite reiniciar MySQL.

 0
Author: user3600935,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-13 18:34:13

Las respuestas anteriores no funcionaron con mi problema. Solo estaba en producción, con tomcat y apache mod_proxy_ajp. Post cuerpo perdido caracteres no ascii por ? El problema finalmente fue con JVM defaultCharset (US-ASCII en una instalación predeterminada: Charset dfset = Charset.defaultCharset();) por lo tanto, la solución se ejecutó tomcat server con un modificador para ejecutar la JVM con UTF-8 como conjunto de caracteres predeterminado:

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

(añadir esta línea a catalina.sh and service tomcat restart)

Tal vez usted también debe cambiar variable del sistema linux (edit~/.bashrc y ~/.perfil para el cambio permanente, ver 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

 0
Author: Rogelio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-17 06:18:01

En caso de que haya especificado en connection pool (mysql-ds.xml), en su código Java puede abrir la conexión de la siguiente manera:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://192.168.1.12:3308/mydb?characterEncoding=greek",
    "Myuser", "mypass");
 -1
Author: Mike Mountrakis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-10-09 12:42:41