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&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
mysqladmite 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 VARBINARY
tipo de columna o usar el utf8mb4
conjunto de caracteres (que requiere MySQL 5.5.3 o posterior). Solo tenga en cuenta que usar el utf8
juego 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:
- 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"/>
- Ir a su carpeta de Apache es decir,
/etc/httpd/conf
y añadir AddDefaultCharset utf-8
en 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.