Как заставить UTF-8 работать в Java webapps?
Мне нужно заставить UTF-8 работать в моем Java webapp (сервлеты + JSP, фреймворк не используется) для поддержки äöå
и т.д. для обычного финского текста и кириллицы, например, ЦжФ
для особых случаев.
Моя настройка следующая:
- Среда разработки: Windows XP
- Производственная среда: Debian
Используемая база данных: MySQL 5.x
Пользователи в основном используют Firefox2, но также Opera 9.x, FF3, IE7 и Google Chrome используются для доступа к сайту.
Как этого добиться?
Переведено автоматически
Ответ 1
Отвечаю сам, поскольку часто задаваемые вопросы на этом сайте поощряют это. У меня это работает:
В основном символы "" не являются проблемой, поскольку набор символов по умолчанию, используемый браузерами и tomcat / java для веб-приложений, является latin1, т.е.. ISO-8859-1, который "понимает" эти символы.
Чтобы заставить UTF-8 работать в Java + Tomcat + Linux / Windows + Mysql, требуется следующее:
Настройка Tomcat server.xml
Необходимо настроить, чтобы соединитель использовал UTF-8 для кодирования параметров URL (GET request):
<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"
/>
Ключевой частью является URIEncoding="UTF-8" в приведенном выше примере. Это гарантирует, что Tomcat обрабатывает все входящие параметры GET в кодировке UTF-8.
В результате, когда пользователь пишет следующее в адресную строку браузера:
https://localhost:8443/ID/Users?action=search&name=*ж*
символ ж обрабатывается как UTF-8 и кодируется (обычно браузером еще до попадания на сервер) как %D0%B6.
На запрос POST это не влияет.
CharsetFilter
Тогда пришло время заставить Java webapp обрабатывать все запросы и ответы в кодировке UTF-8. Для этого необходимо определить фильтр набора символов, подобный следующему:
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() {
}
}
Этот фильтр гарантирует, что если браузер не установил кодировку, используемую в запросе, то она установлена в UTF-8.
The other thing done by this filter is to set the default response encoding ie. the encoding in which the returned html/whatever is. The alternative is to set the response encoding etc. in each controller of the application.
This filter has to be added to the web.xml or the deployment descriptor of the 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>
The instructions for making this filter are found at the tomcat wiki (http://wiki.apache.org/tomcat/Tomcat/UTF-8)
JSP page encoding
In your web.xml, add the following:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<page-encoding>UTF-8</page-encoding>
</jsp-property-group>
</jsp-config>
Alternatively, all JSP-pages of the webapp would need to have the following at the top of them:
<%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
If some kind of a layout with different JSP-fragments is used, then this is needed in all of them.
HTML-meta tags
JSP page encoding tells the JVM to handle the characters in the JSP page in the correct encoding.
Then it's time to tell the browser in which encoding the html page is:
This is done with the following at the top of each xhtml page produced by the 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-connection
When using a db, it has to be defined that the connection uses UTF-8 encoding. This is done in context.xml or wherever the JDBC connection is defiend as follows:
<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"
/>
MySQL database and tables
The used database must use UTF-8 encoding. This is achieved by creating the database with the following:
CREATE DATABASE `ID_development`
/*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci */;
Then, all of the tables need to be in UTF-8 also:
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;
The key part being CHARSET=utf8.
MySQL server configuration
MySQL serveri has to be configured also. Typically this is done in Windows by modifying my.ini -file and in Linux by configuring my.cnf -file.
In those files it should be defined that all clients connected to the server use utf8 as the default character set and that the default charset used by the server is also utf8.
[client]
port=3306
default-character-set=utf8
[mysql]
default-character-set=utf8
Mysql procedures and functions
These also need to have the character set defined. For example:
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 ;
GET requests: latin1 and UTF-8
If and when it's defined in tomcat's server.xml that GET request parameters are encoded in UTF-8, the following GET requests are handled properly:
https://localhost:8443/ID/Users?action=search&name=Petteri
https://localhost:8443/ID/Users?action=search&name=ж
Поскольку символы ASCII кодируются одинаково как в latin1, так и в UTF-8, строка "Petteri" обрабатывается правильно.
Символ кириллицы ж вообще не понимается в latin1. Поскольку Tomcat проинструктирован обрабатывать параметры запроса как UTF-8, он правильно кодирует этот символ как %D0%B6.
Если и когда браузерам будет дано указание читать страницы в кодировке UTF-8 (с заголовками запросов и html-метатегом), по крайней мере Firefox 2/3 и другие браузеры того периода сами кодируют символ как %D0%B6.
Конечным результатом является то, что найдены все пользователи с именем "Petteri", а также найдены все пользователи с именем "ж".
Но как насчет этого?
HTTP-спецификация определяет, что по умолчанию URL-адреса кодируются как latin1. В результате firefox2, firefox3 и т.д. Кодируются следующие
https://localhost:8443/ID/Users?action=search&name=*Päivi*
в кодированной версии
https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*
В latin1 символ ä кодируется как %E4. Несмотря на то, что страница / запрос / все определено для использования UTF-8. Версия с кодировкой UTF-8 для является %C3%A4 в кодировке UTF-8.
Результатом этого является то, что веб-приложение совершенно не может корректно обрабатывать параметры запроса из запросов GET, поскольку некоторые символы кодируются в latin1, а другие в UTF-8. Обратите внимание: запросы POST действительно работают, поскольку браузеры полностью кодируют все параметры запроса из форм в UTF-8, если страница определена как UTF-8
Материал для чтения
Большое спасибо авторам следующего за ответы на мою проблему:
- 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/
Важное примечание
mysql поддерживает базовую многоязычную плоскость, использующую 3-байтовые символы UTF-8. Если вам нужно выйти за рамки этого (для определенных алфавитов требуется более 3 байт UTF-8), то вам нужно либо использовать разновидность VARBINARY
типа столбца, либо использовать utf8mb4
набор символов (для которого требуется MySQL 5.5.3 или более поздней версии). Просто имейте в виду, что использование utf8
набора символов в MySQL не будет работать в 100% случаев.
Tomcat с Apache
Еще одна вещь, если вы используете Apache + Tomcat + mod_JK connector, то вам также необходимо внести следующие изменения:
- Добавьте URIEncoding="UTF-8" в tomcat server.xml файл для соединителя 8009, он используется соединителем mod_JK.
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
- Перейдите в свою папку apache, т.е.
/etc/httpd/conf
и добавьтеAddDefaultCharset utf-8
вhttpd.conf file
. Примечание: Сначала проверьте, существует она или нет. Если он существует, вы можете обновить его этой строкой. Вы также можете добавить эту строку внизу.
Ответ 2
Я думаю, вы достаточно хорошо подвели итог в своем собственном ответе.
В процессе редактирования UTF-8 (?) из конца в конец вы также можете захотеть убедиться, что сама java использует UTF-8. Используйте -Dfile.encoding=utf-8 в качестве параметра JVM (можно настроить в catalina.bat).
Ответ 3
Чтобы добавить к ответу косоанта, если вы используете Spring, а не пишете свой собственный фильтр сервлетов, вы можете использовать класс, который org.springframework.web.filter.CharacterEncodingFilter
они предоставляют, настроив его следующим образом в вашем 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>
Ответ 4
Я также хочу добавить из здесь эта часть решила мою проблему с utf:
runtime.encoding=<encoding>