Как заставить 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=*ж*

символ 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 типа столбца VARBINARY либо использовать utf8mb4 символов utf8mb4 (для которого требуется MySQL 5.5.3 или более поздняя utf8mb4). Просто учтите, что использование utf8 символов 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. Перейдите в папку apache, то есть /etc/httpd/conf и добавьте AddDefaultCharset utf-8 в httpd.conf file. Примечание. Сначала проверьте, существует он или нет. Если существует, вы можете обновить его с помощью этой строки. Вы также можете добавить эту строку внизу.

Ответ 2

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

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

Ответ 3

Чтобы добавить к ответ 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>

Ответ 4

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

runtime.encoding=<encoding>

Ответ 5

Это для греческого кодирования в таблицах 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

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

Ответ 6

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

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

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

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

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

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

Ответ 7

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

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

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

Ответ 8

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

Ответ 9

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

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

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

Ответ 10

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

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

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

Ответ 11

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

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

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

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

Ответ 12

Предыдущие ответы не работали с моей проблемой. Это было только в производстве, с 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

Ответ 13

Столкнулся с такой же проблемой на 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>
    

Ответ 14

Если вы указали в пуле соединений (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");