Як заставити UTF-8 працювати в веб-сайтах Java?


367

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

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

  • Середовище розробки: Windows XP
  • Виробниче середовище: Debian

Використовувана база даних: MySQL 5.x

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

Як цього досягти?


Відповіді:


552

Відповідаючи на себе як FAQ на цьому веб-сайті це заохочує. Це працює для мене:

Переважно символи äåö не є проблематичним, оскільки набір символів за замовчуванням, який використовується браузерами та tomcat / java для веб-сайтів, є latin1, тобто. ISO-8859-1, який "розуміє" цих символів.

Щоб UTF-8 працював під Java + Tomcat + Linux / Windows + Mysql, потрібно:

Налаштування сервера Tomcat.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 / що б там не було. Альтернативою є встановлення кодування відповіді тощо у кожному контролері програми.

Цей фільтр потрібно додати до 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>

Інструкції щодо створення цього фільтра можна знайти на wiki 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-сторінка:

Це робиться за допомогою наступного вгорі кожної сторінки xhtml, створеної веб-сайтом:

   <?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 ;

Отримайте запити: latin1 та UTF-8

Якщо і коли в сервері tomcat's 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*

У latin1 символ ä кодується як % E4 . Навіть незважаючи на те, що сторінка / запит / все визначено для використання UTF-8 . Версія ä, закодована UTF-8, є % C3% A4

Результатом цього є те, що webapp цілком неможливо правильно обробити параметри запиту з 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% часу.

Томат з апачем

Ще одна річ Якщо ви використовуєте роз'єм 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. Примітка. Спочатку перевірте, чи існує він чи ні. Якщо існує, ви можете оновити її за допомогою цього рядка. Ви також можете додати цей рядок і внизу.

Ці кроки також працюють із Struts / плитками та базою даних postgres.
косоант

17
Два коментарі: 1) у HMTL-мета-теги ви включили декларацію 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 ) не вказує на наявність <мета http-equiv = 'вмісту -Type 'впливає на режим візуалізації.
Marcel Stör

Як цікаву бічну зауваження ви також можете знати, що якщо у вас є слухач, який отримує доступ до параметра запиту, вам потрібно буде додати слухача, який встановлює схему замість фільтра, оскільки слухачі виконуються перед фільтрами. Я дотримувався всіх кроків, і це все ще не спрацювало через це. Я просто подумав, що я передам цю інформацію, якщо у когось іншого є подібна проблема.
тестування123

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).


Це допомогло мені, я зробив усе згадане, але кодування JVM було windows-1250, як тільки я перейшов на UTF-8, він працював бездоганно.
coding_idiot

2
Де ви додасте це у файл Catalina.bat, будь ласка?
Ной

11

Щоб додати до відповіді 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
olyanren

2

Я хотів би також додати з тут в цій частині вирішити мою проблему Utf:

runtime.encoding=<encoding>

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. Орган поштового зв'язку втрачений без асирійних знаків? Нарешті, проблема була з 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

експортувати LANGUAGE = en_US.UTF-8


0

У мене з подібною проблемою, але у назви файлів я стискаюсь з апач-спільнотою. Отже, я вирішив це за допомогою цієї команди:

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

це працює дуже добре для мене. Сподіваюся, це допоможе комусь;)


0

У моєму випадку відображення символу Unicode з пакетів повідомлень мені не потрібно застосовувати розділ "Кодування сторінки JSP" для відображення Unicode на моїй сторінці jsp. Все, що мені потрібно, - розділ "CharsetFilter".


0

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

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

Мало хто, здається, прокатує свій власний Аякс в ці дні, але я подумав, що можу також додати це.


0

Про CharsetFilterзгадане у відповіді @kosoant ....

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

Крім того, немає необхідності встановлювати jsp-configу своєму web.xml(я тестую його для Tomcat 7+)


0

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

Змінні запуску> Додатково>

і встановіть Def. char Set: utf8

Можливо, цей конфігуратор потребує перезавантаження MySQL.


0

Зіткнувся з тим же випуском на Spring MVC 5 + Tomcat 9 + JSP.
Після довгих досліджень прийшло до елегантного рішення ( не потрібні фільтри та не потрібні зміни у сервері Tomcat.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");
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.