¿Cómo hacer que UTF-8 funcione en aplicaciones web Java?

Resuelto kosoant asked hace 15 años • 14 respuestas

Necesito que UTF-8 funcione en mi aplicación web Java (servlets + JSP, no se utiliza marco) para admitir, äöåetc., texto finlandés normal y alfabetos cirílicos, como ЦжФen 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 para acceder al sitio.

¿Cómo lograr esto?

kosoant avatar Sep 26 '08 18:09 kosoant
Aceptado

Respondiéndome a mí mismo como lo alientan las preguntas frecuentes de este sitio. Esto funciona para mí:

La mayoría de los caracteres äåö no son problemáticos ya que el conjunto de caracteres predeterminado utilizado por los navegadores y Tomcat/Java para las aplicaciones web es latin1, es decir. ISO-8859-1 que "entiende" esos caracteres.

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

Configurando el server.xml de Tomcat

Es necesario configurar que el conector utilice UTF-8 para codificar los parámetros de la 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 maneja todos los parámetros GET entrantes como 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 está codificado (generalmente por el navegador incluso antes de llegar al servidor) como %D0%B6 .

La solicitud POST no se ve afectada por esto.

Filtro de juego de caracteres

Entonces es hora de forzar a la aplicación web Java a manejar todas las solicitudes y respuestas con codificación UTF-8. Esto requiere que definamos un filtro de juego 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 garantiza que, si el navegador no ha configurado la codificación utilizada en la solicitud, esté configurada 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 el html/lo que sea. La alternativa es configurar la codificación de respuesta, etc. en cada controlador de la aplicación.

Este filtro debe agregarse al web.xml o al descriptor de implementación de la aplicación web:

 <!--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 crear este filtro se encuentran en la wiki de Tomcat ( http://wiki.apache.org/tomcat/Tomcat/UTF-8 ).

Codificación de página JSP

En su web.xml , agregue lo 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 deberían tener lo siguiente en la parte superior:

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

Si se utiliza algún tipo de diseño con diferentes fragmentos JSP, entonces esto es necesario en todos ellos.

Metaetiquetas HTML

La codificación de la página JSP le dice a la JVM que maneje los caracteres de 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 se hace con lo siguiente en la parte superior de cada página xhtml producida por la aplicación web:

   <?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' />
   ...

Conexión JDBC

Cuando se utiliza una base de datos, se debe definir que la conexión utilice codificación UTF-8. Esto se hace en context.xml o donde sea que la conexión JDBC esté definida 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 y tablas MySQL

La base de datos utilizada debe utilizar 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 */;

Luego, todas 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

El servidor MySQL también debe configurarse. Normalmente, esto se hace en Windows modificando el archivo my.ini y en Linux configurando el archivo my.cnf . En esos archivos se debe definir que todos los clientes conectados al servidor usan utf8 como juego de caracteres predeterminado y que el juego de caracteres predeterminado usado por el servidor también es utf8.

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

   [mysql]
   default-character-set=utf8

Procedimientos y funciones de MySQL.

Estos también deben tener definido el juego de caracteres. 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 ;

Solicitudes GET: latin1 y UTF-8

Si se define en server.xml de Tomcat que los parámetros de 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 están codificados 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 latín1. 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 se indica a los navegadores que lean las páginas en codificación UTF-8 (con encabezados de solicitud y metaetiqueta 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 se encuentran todos los usuarios con el nombre "Petteri" y también se encuentran todos los usuarios con el nombre "ж".

Pero ¿qué pasa con äåö?

La especificación HTTP define que, de forma predeterminada, las URL están codificadas como latin1. Esto da como resultado que firefox2, firefox3, etc. codifiquen 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/solicitud/todo está definido para usar UTF-8 . La versión codificada en UTF-8 de ä es %C3%A4

El resultado de esto es que es prácticamente imposible que la aplicación web maneje correctamente 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 está definida como UTF-8.

cosas para leer

Muchas gracias a los escritores de lo siguiente por dar las respuestas a 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

MySQLadmite el plano multilingüe básico utilizando caracteres UTF-8 de 3 bytes. Si necesita ir más allá de eso (ciertos alfabetos requieren más de 3 bytes de UTF-8), entonces necesita usar un tipo de tipo de VARBINARYcolumna o usar el utf8mb4juego de caracteres (que requiere MySQL 5.5.3 o posterior). Sólo tenga en cuenta que usar el utf8juego de caracteres en MySQL no funcionará el 100% del tiempo.

Tomcat con Apache

Una cosa más: si está utilizando el conector Apache + Tomcat + mod_JK, también deberá realizar los siguientes cambios:

  1. Agregue URIEncoding="UTF-8" al archivo Tomcat server.xml para el conector 8009, lo utiliza el conector mod_JK.<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Vaya a su carpeta de Apache, es decir, /etc/httpd/confy AddDefaultCharset utf-8agréguelo httpd.conf file. Nota: Primero verifique que exista o no. Si existe, puede actualizarlo con esta línea. También puede agregar esta línea en la parte inferior.
kosoant avatar Sep 26 '2008 11:09 kosoant

Creo que lo resumiste bastante bien en tu propia respuesta.

En el proceso de UTF-8-ing(?) de un extremo a otro, es posible que también desee asegurarse de que Java esté usando UTF-8. Utilice -Dfile.encoding=utf-8 como parámetro para la JVM (se puede configurar en catalina.bat).

stian avatar Sep 27 '2008 21:09 stian

Para agregar a la respuesta de kosoant , si está usando Spring, en lugar de escribir su propio filtro de Servlet, puede usar la clase org.springframework.web.filter.CharacterEncodingFilterque 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>
Raedwald avatar Jan 28 '2014 15:01 Raedwald

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

runtime.encoding=<encoding>
John avatar May 13 '2010 16:05 John