Как заставить UTF-8 работать в веб-приложениях Java?

331

Мне нужно, чтобы UTF-8 работал в моем Java webapp (сервлеты + JSP, без использования фреймворка) для поддержки äöå и т.д. для обычного финского текста и кириллических алфавитов, таких как ЦжФ для особых случаев.

Моя настройка такова:

  • Среда разработки: Windows XP
  • Производственная среда: Debian

Используемая база данных: MySQL 5.x

Пользователи в основном используют Firefox2, но для доступа к сайту используются Opera 9.x, FF3, IE7 и Google Chrome.

Как это сделать?

Теги:
tomcat
utf-8
encoding

12 ответов

491
Лучший ответ

Отвечая на вопрос, как часто задаваемые вопросы этого сайта поощряют его. Это работает для меня:

В основном символы äåö не являются проблематичными, поскольку набор символов по умолчанию, используемый браузерами, и tomcat/java для webapps - latin1, т.е. ISO-8859-1, который "понимает" эти символы.

Чтобы получить UTF-8, работающий под Java + Tomcat + Linux/Windows + Mysql, требуется следующее:

Настройка Tomcat server.xml

Необходимо настроить, чтобы соединитель использовал UTF-8 для кодирования параметров URL-адреса (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"
/>

Ключевой частью является 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.

Другое, что делает этот фильтр, - это установить кодировку ответа по умолчанию, т.е. кодирование, в котором возвращен html/whatever. Альтернативой является установка кодировки ответа и т.д. В каждом контроллере приложения.

Этот фильтр необходимо добавить в web.xml или дескриптор развертывания 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>

Инструкции для создания этого фильтра находятся в tomcat wiki ( http://wiki.apache.org/tomcat/Tomcat/UTF-8)

Копирование страницы JSP

В web.xml добавьте следующее:

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

В качестве альтернативы, все JSP-страницы webapp должны иметь следующее в верхней части:

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

Если используется какой-то макет с различными JSP-фрагментами, то это необходимо в all из них.

HTML-метатеги

Кодирование страницы JSP сообщает JVM обрабатывать символы на странице JSP в правильной кодировке. Затем настало время сообщить vrowser, в котором кодировка html-страницы:

Это делается с помощью следующего в верхней части каждой xhtml-страницы, созданной 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-соединение

При использовании db необходимо определить, что соединение использует кодировку UTF-8. Это делается в context.xml или везде, где соединение JDBC определяется следующим образом:

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

База данных MySQL и таблицы

Используемая база данных должна использовать кодировку UTF-8. Это достигается путем создания базы данных со следующим:

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

Затем все таблицы должны быть в 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;

Ключевой частью является CHARSET = utf8.

Конфигурация сервера MySQL

Необходимо также настроить MySQL serveri. Обычно это делается в Windows путем изменения my.ini -file и в Linux путем настройки my.cnf -file. В этих файлах должно быть определено, что все клиенты, подключенные к серверу, используют utf8 в качестве набора символов по умолчанию и что кодировка по умолчанию, используемая сервером, также является utf8.

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

   [mysql]
   default-character-set=utf8

Процедуры и функции Mysql

Они также должны иметь определенный набор символов. Например:

   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: latin1 и UTF-8

Если и когда он определен в tomcat server.xml, параметры запроса GET закодированы в UTF-8, обрабатываются следующие запросы GET:

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

Поскольку символы ASCII кодируются одинаково с латинскими и UTF-8, строка "Petteri" обрабатывается правильно.

Кириллический символ ж вообще не понимается в латинском языке1. Поскольку 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*

В латинском языке символ ä кодируется как % E4. Несмотря на то, что страница/запрос/все определено для использования UTF-8. Закодированная версия UTF-8 ä имеет значение % C3% A4

Результатом этого является то, что webapp не может корректно обрабатывать параметры запроса из запросов 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/ru/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/

Важное примечание

поддерживает Базовая многоязычная плоскость с использованием 3-байтных символов UTF-8. Если вам нужно выйти за пределы этого (для некоторых алфавитов требуется более 3 байтов UTF-8), вам нужно либо использовать атрибут типа столбца VARBINARY, либо использовать utf8mb4 набор символов (для чего требуется MySQL 5.5.3 или новее). Просто имейте в виду, что использование набора символов utf8 в MySQL не будет работать в течение 100% времени.

Tomcat с Apache

Еще одна вещь. Если вы используете соединитель Apache + Tomcat + mod_JK, вам также необходимо выполнить следующие изменения:

  • Добавить URIEncoding = "UTF-8" в файл tomcat server.xml для коннектора 8009, он используется коннектором mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  • Перейдите в папку apache i.e /etc/httpd/conf и добавьте AddDefaultCharset utf-8 в httpd.conf file. Примечание.. Сначала убедитесь, что он существует или нет. Если существует, вы можете обновить его с помощью этой строки. Вы также можете добавить эту строку внизу.
  • 0
    Эти шаги также работают со Struts / tile и базой данных postgres.
  • 17
    Два комментария: 1) в теги HMTL-meta вы включили декларацию xml. Удалите его, он будет запускать браузеры только в режиме причуд, вы не хотите иметь это. Кроме того, метатеги HTML на самом деле уже неявно выполняются JSP pageEncoding , так что вы даже можете оставить это в стороне. 2) в базе данных MySQL и таблицах, которые вы использовали utf8_swedish_si , это должен был быть utf8_unicode_ci . Вы можете даже оставить параметры сортировки, достаточно просто использовать CHARACTER SET utf8 .
Показать ещё 19 комментариев
12

Я думаю, вы хорошо подвели его в своем собственном ответе.

В процессе UTF-8-ing (?) из конца в конец вы также можете убедиться, что сам java использует UTF-8. Используйте -Dfile.encoding = utf-8 как параметр для JVM (можно настроить в catalina.bat).

  • 0
    Это помогло мне, я сделал все упомянутое, но кодировка JVM была windows-1250, как только я перешел на UTF-8, он работал безупречно.
  • 2
    Где вы добавите это в файл Catalina.bat, пожалуйста?
8

Чтобы добавить к ответ kosoant, если вы используете 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>
  • 1
    Этот фильтр должен быть первым фильтром в web.xml
1

Я хочу также добавить из здесь эта часть решила мою проблему с utf:

runtime.encoding=<encoding>
1

Хороший подробный ответ. просто хотел добавить еще одну вещь, которая определенно поможет другим увидеть кодировку UTF-8 в URL-адресах в действии.

Выполните следующие действия, чтобы включить кодировку UTF-8 в URL-адресах в firefox.

  • введите "about: config" в адресной строке.

  • Используйте тип ввода фильтра для поиска свойства "network.standard-url.encode-query-utf8".

  • указанное выше свойство будет ложным по умолчанию, поверните его к ИСТИНА.
  • перезапустите браузер.

Кодировка UTF-8 по URL-адресам работает по умолчанию в IE6/7/8 и хром.

1

Это для греческого кодирования в таблицах MySql, когда мы хотим получить к ним доступ с помощью Java:

Используйте следующую настройку соединения в пуле соединений 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>

Если вы не хотите помещать это в пул соединений JNDI, вы можете настроить его как JDBC-url, как показано на следующей строке:

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

Для меня и Ника, поэтому мы никогда не забываем об этом и теряем время.

  • 4
    Я все еще предпочел бы UTF-8 выше греческого (и преобразовать ваши текущие греческие данные в UTF-8), чтобы ваше приложение было готово к мировому господству.
0

Некоторое время вы можете решить проблему через мастер администратора MySQL. В

Переменные запускa > Дополнительно >

и установите Def. char Set: utf8

Возможно, этой конфигурации необходимо перезапустить MySQL.

0

О CharsetFilter, упомянутом в ответе @kosoant....

В tomcat web.xml есть место сборки Filter (находится в conf/web.xml). Фильтр имеет имя setCharacterEncodingFilter и прокомментирован по умолчанию. Вы можете раскомментировать это (пожалуйста, не забудьте раскомментировать его filter-mapping)

Также нет необходимости устанавливать jsp-config в web.xml (у меня есть тест для Tomcat 7+)

0

Еще один момент, о котором не упоминалось, относится к Java Servlets, работающему с Ajax. У меня есть ситуации, когда веб-страница собирает текст utf-8 от пользователя, отправляющего его в файл JavaScript, который включает его в URI, отправленный на Servlet. Servlet запрашивает базу данных, фиксирует результат и возвращает его как XML в файл JavaScript, который форматирует его и вставляет отформатированный ответ на исходную веб-страницу.

В одном веб-приложении я следил за ранними инструкциями по книге Ajax для того, чтобы обернуть JavaScript при построении URI. В примере в книге использовался метод escape(), который я обнаружил (трудный путь) неправильно. Для utf-8 вы должны использовать encodeURIComponent().

Немногие люди, похоже, катят свой Ajax в эти дни, но я думал, что могу добавить это.

0

В моем случае отображения символа Юникода из пакетов сообщений мне не нужно применять раздел "Копирование страницы JSP", чтобы отображать Unicode на моей странице jsp. Все, что мне нужно, это раздел "CharsetFilter".

0

У меня есть аналогичная проблема, но в файлах файла я сжимаю с помощью apache. Итак, я решил это с помощью этой команды:

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

он работает очень хорошо для меня. Надеюсь, что это поможет кому угодно;)

-1

Если вы указали в пуле соединений (mysql-ds.xml), в своем Java-коде вы можете открыть соединение следующим образом:

DriverManager.registerDriver(new com.mysql.jdbc.Driver());
Connection conn = DriverManager.getConnection(
    "jdbc:mysql://192.168.1.12:3308/mydb?characterEncoding=greek",
    "Myuser", "mypass");

Ещё вопросы

Сообщество Overcoder
Наверх
Меню