如何让 UTF-8 在 Java Web 应用程序中工作?

2022-08-31 04:45:34

我需要让UTF-8在我的Java webapp(servlets + JSP,不使用框架)中工作,以支持常规芬兰语文本和西里尔字母表等特殊情况。äöåЦжФ

我的设置如下:

  • 开发环境:Windows XP
  • 生产环境:Debian

使用的数据库:MySQL 5.x

用户主要使用Firefox2,但也使用Opera 9.x,FF3,IE7和Google Chrome来访问该网站。

如何做到这一点?


答案 1

回答我自己作为本网站的常见问题解答鼓励它。这对我有用:

大多数字符äåö没有问题,因为浏览器和webapp的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(通常在到达服务器之前由浏览器编码)。

开机自检请求不受此影响。

字符集过滤器

然后是时候强制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或 web 应用的部署描述符:

 <!--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>

或者,Web 应用程序的所有 JSP 页面的顶部都需要包含以下内容:

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

如果使用某种具有不同 JSP 片段的布局,那么所有这些布局都需要这样做。

元标记

JSP 页编码告诉 JVM 以正确的编码处理 JSP 页中的字符。然后是时候告诉浏览器html页面的编码方式了:

这是通过 Web 应用生成的每个 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 编码。这是在上下文中完成的.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 的服务器中定义了 GET 请求参数.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

这样做的结果是,Web 应用程序完全不可能正确处理来自 GET 请求的请求参数,因为某些字符以 latin1 编码,而其他字符以 UTF-8 编码。注意:如果页面被定义为 UTF-8,则 POST 请求确实有效,因为浏览器会将表单中的所有请求参数完全编码为 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),那么你要么需要使用列类型的风格,要么使用utf8mb4字符集(这需要MySQL 5.5.3或更高版本)。请注意,在MySQL中使用字符集不会100%工作。VARBINARYutf8

Tomcat with Apache

还有一件事,如果您使用的是Apache + Tomcat + mod_JK连接器,那么您还需要进行以下更改:

  1. 将URIEncoding=“UTF-8”添加到tomcat服务器.xml文件中为8009连接器,它由mod_JK连接器使用。<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. 转到您的apache文件夹,即 并添加 .注意:首先检查它是否存在。如果存在,您可以使用此行更新它。您也可以在底部添加此行。/etc/httpd/confAddDefaultCharset utf-8httpd.conf file

答案 2

我认为你在自己的答案中很好地总结了这一点。

在 UTF-8-ing(?) 从头到尾的过程中,您可能还需要确保 java 本身使用的是 UTF-8。使用 -Dfile.encoding=utf-8 作为 JVM 的参数(可以在 catalina.bat 中配置)。


推荐