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

367

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

Моя установка следующая:

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

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

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

Как этого добиться?

kosoant
источник
См. Также stackoverflow.com/questions/153527/…
Raedwald

Ответы:

552

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

В основном, символы не являются проблематичными, поскольку набор символов по умолчанию, используемый браузерами, а 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=*ж*

символ is обрабатывается как UTF-8 и кодируется (обычно браузером перед тем, как даже попасть на сервер) как % D0% B6 .

На запрос POST это не влияет.

CharsetFilter

Затем пришло время заставить приложение Java обрабатывать все запросы и ответы в кодировке 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 / что угодно. Альтернативой является установка кодировки ответа и т. Д. В каждом контроллере приложения.

Этот фильтр необходимо добавить в файл web.xml или дескриптор развертывания веб-приложения:

 <!--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 ( 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-страницах веб-приложения должно быть следующее:

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

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

HTML-мета-теги

Кодировка страницы JSP говорит JVM обрабатывать символы на странице JSP в правильной кодировке. Затем пришло время сообщить браузеру, в какой кодировке находится HTML-страница:

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

   <?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-соединение

При использовании БД необходимо определить, что соединение использует кодировку 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-символы кодируются одинаково как с помощью latin1, так и 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*

В латинице 1 символ ä кодируется как % E4 . Хотя страница / запрос / все определено для использования UTF-8 . Версия ä в кодировке UTF-8: % C3% A4

В результате этого веб-приложение не может корректно обрабатывать параметры запроса из запросов GET, поскольку некоторые символы кодируются в латинице 1, а другие - в 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/

Важная заметка

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

Tomcat с Apache

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

  1. Добавьте URIEncoding = "UTF-8" в файл tomcat server.xml для соединителя 8009, он используется соединителем mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. Гото ваш апач папку т.е. /etc/httpd/confи добавить AddDefaultCharset utf-8в httpd.conf file. Примечание. Сначала проверьте, существует он или нет. Если существует, вы можете обновить его с помощью этой строки. Вы также можете добавить эту строку внизу.
kosoant
источник
Эти шаги также работают со Struts / tile и базой данных postgres.
Косоант
17
Два комментария: 1) в теги HMTL-meta вы включили декларацию xml. Удалите его, он будет запускать браузеры только в режиме причуд, вы не хотите иметь это. Кроме того, метатеги HTML на самом деле уже неявно выполняются JSP pageEncoding, так что вы даже можете оставить их в стороне. 2) в базе данных и таблицах MySQL вы использовали utf8_swedish_si, это должно было быть utf8_unicode_ci. Вы можете даже оставить сопоставление, CHARACTER SET utf8достаточно.
BalusC
Ни один из документов, к которым я обращался в отношении метатегов HTML и режима причуд (например, ericmeyeroncss.com/bonus/render-mode.html , en.wikipedia.org/wiki/Quirks_mode ), не указывает на то, что наличие <meta http-эквивалента = 'Content -Type 'оказывает влияние на режим рендеринга.
Марсель Стёр
В качестве интересного примечания вы также можете знать, что если у вас есть прослушиватель, который обращается к параметру запроса, вам нужно будет добавить прослушиватель, который устанавливает кодировку вместо фильтра, потому что слушатели выполняются перед фильтрами. Я следовал за всеми шагами, и это все еще не работало из-за этого. Просто подумал, что передам эту информацию, на случай, если у кого-то еще возникнет подобная проблема.
testing123
3
## Tomcat с Apache ## Еще одна вещь Если вы используете коннектор Apache + Tomcat + mod_JK, вам также необходимо внести следующие изменения: 1. Добавить URIEncoding = "UTF-8" в файл tomcat server.xml для коннектора 8009, это используется соединителем mod_JK. <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/> 2. Перейдите в папку apache т.е. /etc/httpd/confи добавьте AddDefaultCharset utf-8файл httpd.conf. Примечание: сначала проверьте, существует он или нет. Если существует, вы можете обновить его с помощью этой строки. Вы также можете добавить эту строку внизу.
Виджай Шегокар
14

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

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

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

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

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

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

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

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

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

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

  3. указанное выше свойство будет ложным по умолчанию, установите значение TRUE.
  4. перезапустите браузер.

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

сойка
источник
1

Предыдущие ответы не работали с моей проблемой. Это было только в производстве, с tomcat и apache mod_proxy_ajp. Сообщение тело потерял не ASCII символов? Наконец, проблема была с JVM defaultCharset (US-ASCII в установке по умолчанию: Charset dfset = Charset.defaultCharset ();), поэтому было решено запустить сервер tomcat с модификатором для запуска JVM с UTF-8 в качестве кодировки по умолчанию:

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

(добавьте эту строку в catalina.sh и перезапустите сервис Tomcat)

Возможно, вы также должны изменить системную переменную Linux (отредактируйте ~ / .bashrc и ~ / .profile для постоянного изменения, см. Https://perlgeek.de/en/article/set-up-a-clean-utf8-environment )

экспорт LC_ALL = en_US.UTF-8
экспорт LANG = en_US.UTF-8

export LANGUAGE = en_US.UTF-8

Рохелио Тривиньо
источник
0

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

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

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

caarlos0
источник
0

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

bnguyen82
источник
0

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

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

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

Дэвид
источник
0

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

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

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

Алиреза Фаттахи
источник
0

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

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

и установите Def. Набор символов: utf8

Может быть, этот конфиг нужно перезагрузить MySQL.

user3600935
источник
0

Столкнулся с такой же проблемой на Spring MVC 5 + Tomcat 9 + JSP.
После долгих исследований пришло элегантное решение ( нет необходимости в фильтрах и нет необходимости вносить изменения в Tomcat server.xml (начиная с версии 8.0.0-RC3))

  1. В реализации WebMvcConfigurer задайте кодировку по умолчанию для messageSource (для чтения данных из исходных файлов сообщений в кодировке 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. В реализации DispatcherServletInitializer @Override метод onStartup и установка в нем кодировки символов запроса и ресурса.

    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. Сохраните все источники сообщений и просмотрите файлы в кодировке UTF-8.

  4. Добавьте <% @ page contentType = "text / html; charset = UTF-8"%> или <% @ page pageEncoding = "UTF-8"%> в каждый файл * .jsp или добавьте дескриптор jsp-config в 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>
Андрей Вештард
источник
-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");
Майк Маунтракис
источник