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

367

Necesito que UTF-8 funcione en mi aplicación web Java (servlets + JSP, sin marco utilizado) para admitir äöå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
  • Ambiente de producción: Debian

Base de datos utilizada: MySQL 5.x

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

¿Cómo lograr esto?

kosoant
fuente

Respuestas:

552

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

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 webapps es latin1, es decir. ISO-8859-1 que "entiende" esos caracteres.

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

Configuración de server.xml de Tomcat

Es necesario configurar que el conector use UTF-8 para codificar los 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 maneja todos los parámetros GET entrantes como codificados 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.

CharsetFilter

Entonces es hora de forzar a la aplicación web de Java a manejar todas las solicitudes y respuestas como codificadas en 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 se asegura de que si el navegador no ha configurado la codificación utilizada en la solicitud, esté configurado 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 establecer la codificación de respuesta, etc. en cada controlador de la aplicación.

Este filtro debe agregarse a 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 hacer 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 usa 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 en la página JSP en la codificación correcta. Entonces es hora de decirle al navegador en qué codificación se encuentra 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 usa una base de datos, debe definirse que la conexión usa codificación UTF-8. Esto se hace en context.xml o donde la conexión JDBC se defiende 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 usar 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, todas las tablas deben estar en UTF-8 también:

   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. Por lo general, esto se hace en Windows modificando my.ini -file y en Linux configurando my.cnf -file. En esos archivos se debe definir que todos los clientes conectados al servidor usan utf8 como el 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

Mysql procedimientos y funciones

Estos también necesitan tener definido el conjunto 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 y cuando 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 se codifican de la misma manera con latin1 y UTF-8, la cadena "Petteri" se maneja correctamente.

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

Siempre y cuando se indique 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 todos los caracteres 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é hay de äåö?

La especificación HTTP define que, por defecto, 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 . A pesar de que la página / solicitud / todo está definido para usar UTF-8 . La versión codificada UTF-8 de ä es % C3% A4

El resultado de esto es que es bastante imposible para la aplicación web manejar 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 se define 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

admite el plano multilingüe básico con caracteres UTF-8 de 3 bytes. Si necesita salir de eso (ciertos alfabetos requieren más de 3 bytes de UTF-8), entonces debe usar un VARBINARYtipo de columna o usar el utf8mb4conjunto de caracteres (que requiere MySQL 5.5.3 o posterior). Solo 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 debe hacer los siguientes cambios:

  1. Agregue URIEncoding = "UTF-8" en el 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. Ir a su carpeta de Apache es decir, /etc/httpd/confy añadir AddDefaultCharset utf-8en httpd.conf file. Nota: Primero verifique si existe o no. Si existe, puede actualizarlo con esta línea. También puede agregar esta línea en la parte inferior.
kosoant
fuente
Estos pasos también funcionan con Struts / tiles y una base de datos postgres.
kosoant
17
Dos comentarios: 1) en las etiquetas meta HMTL incluiste una declaración xml. Elimínelo, solo activaría los navegadores en el modo peculiar, no desea tener eso. Además, las metaetiquetas HTML ya están hechas de manera implícita por JSP pageEncoding, por lo que incluso podría dejarlas de lado. 2) en la base de datos MySQL y las tablas que usó utf8_swedish_si, esto debería haber sido utf8_unicode_ci. Incluso podría dejar de lado la intercalación, solo CHARACTER SET utf8es suficiente.
BalusC
Ninguno de los documentos que consulté con respecto a las metaetiquetas HTML y el modo peculiar (por ejemplo , ericmeyeroncss.com/bonus/render-mode.html , en.wikipedia.org/wiki/Quirks_mode ) indica que la presencia de <meta http-equiv = 'Contenido -Type 'tiene algún impacto en el modo de renderizado.
Marcel Stör
Como nota al margen interesante, es posible que también desee tener en cuenta que si tiene un escucha que accede a un parámetro de solicitud, deberá agregar un escucha que establezca el conjunto de caracteres en lugar de un filtro porque los escuchas se ejecutan antes que los filtros. Seguí todos los pasos y todavía no funcionó debido a esto. Solo pensé en transmitir esta información, en caso de que alguien más tenga un problema similar.
testing123
3
## Tomcat con Apache ## Una cosa más Si está usando el conector Apache + Tomcat + mod_JK, entonces también debe hacer los siguientes cambios: 1. Agregue URIEncoding = "UTF-8" en el archivo tomcat server.xml para el conector 8009, es utilizado por el conector mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/> 2. Pase a su carpeta de apache, es decir, /etc/httpd/confy agregue AddDefaultCharset utf-8el archivo 'httpd.conf'. Nota: primero verifique si existe o no. Si existe, puede actualizarlo con esta línea. También puede agregar esta línea en la parte inferior.
Vijay Shegokar
14

Creo que lo resumiste bastante bien en tu 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. Utilice -Dfile.encoding = utf-8 como parámetro para la JVM (se puede configurar en catalina.bat).

stian
fuente
Esto me ayudó, hice todo lo mencionado, pero la codificación JVM fue windows-1250 tan pronto como cambié a UTF-8 funcionó a la perfección.
coding_idiot
2
¿Dónde agrega eso en el archivo Catalina.bat, por favor?
Noah
11

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.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
fuente
1
Este filtro debe ser el primer filtro en web.xml
olyanren
2

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

runtime.encoding=<encoding>
Juan
fuente
1

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

Use 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 lo ilustra la siguiente línea:

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

Para mí y Nick, así que nunca lo olvidamos y perdemos más tiempo .....

Mike Mountrakis
fuente
55
Todavía preferiría UTF-8 sobre griego (y convertir sus datos griegos actuales a UTF-8) para que su aplicación esté lista para dominar el mundo.
BalusC
1

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 las URL en Firefox.

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

  2. Utilice el tipo de entrada de filtro para buscar la propiedad "network.standard-url.encode-query-utf8".

  3. la propiedad anterior será falsa por defecto, convierta eso en VERDADERO.
  4. reiniciar el navegador.

La codificación UTF-8 en URL funciona de forma predeterminada en IE6 / 7/8 y Chrome.

Arrendajo
fuente
1

Las respuestas anteriores no funcionaron con mi problema. Solo estaba en producción, con tomcat y apache mod_proxy_ajp. ¿El cuerpo del mensaje perdió 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 fue ejecutar el servidor Tomcat con un modificador para ejecutar JVM con UTF-8 como conjunto de caracteres predeterminado:

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

(agregue esta línea a catalina.sh y reinicie el servicio tomcat)

Tal vez también deba cambiar la variable del sistema de Linux (edite ~ / .bashrc y ~ / .profile para un cambio permanente, consulte 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
fuente
0

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

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

me funciona muy bien Espero que ayude a cualquiera;)

caarlos0
fuente
0

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".

bnguyen82
fuente
0

Otro punto que no se ha mencionado se relaciona con los Servlets Java que trabajan con Ajax. Tengo situaciones en las que una página web recoge texto utf-8 del usuario que lo envía 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 las instrucciones de un libro de Ajax anterior para concluir el JavaScript en la construcción del URI. El ejemplo en el libro usó el método escape (), que descubrí (por las malas) que está mal. Para utf-8 debe usar encodeURIComponent ().

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

David
fuente
0

Sobre lo CharsetFiltermencionado en @kosoant respuesta ...

Hay una construcción en Filtertomcat web.xml(ubicado en conf/web.xml). El filtro se nombra setCharacterEncodingFiltery se comenta por defecto. Puede descomentar esto (recuerde descomentarlo filter-mappingtambién)

Además, no es necesario configurarlo jsp-configen su web.xml(lo he probado para Tomcat 7+)

Alireza Fattahi
fuente
0

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

Quizás esta configuración necesite reiniciar MySQL.

usuario3600935
fuente
0

Enfrenté el mismo problema en Spring MVC 5 + Tomcat 9 + JSP.
Después de la larga investigación, llegó a una solución elegante ( sin necesidad de filtros y sin necesidad de cambios en el servidor Tomcat.xml (a partir de la versión 8.0.0-RC3))

  1. En la implementación de WebMvcConfigurer, establezca la codificación predeterminada para messageSource (para leer datos de archivos de origen de mensajes en la codificación 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. En la implementación DispatcherServletInitializer, @Override el método onStartup y establezca la codificación de caracteres de solicitud y recurso en él.

    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. Guarde toda la fuente del mensaje y vea los archivos en codificación UTF-8.

  4. Agregue <% @ page contentType = "text / html; charset = UTF-8"%> o <% @ page pageEncoding = "UTF-8"%> en cada archivo * .jsp o agregue el descriptor jsp-config a 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
fuente
-1

En caso de que haya especificado en el grupo de conexiones (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");
Mike Mountrakis
fuente