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

我的设置如下:

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

使用的数据库:MySQL 5.x

用户主要使用Firefox2,但也使用Opera 9.x、 FF3、IE7和谷歌浏览器被用来访问该网站.

如何做到这一点?

推荐答案

Answering myself as the FAQ of this site encourages it. This works for me:

大多数字符äåö都不是问题,因为浏览器和tomcat/java用于Web应用程序的默认字符集是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以UTF-8编码的方式处理所有传入的GET参数.

 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.

这个过滤做的另一件事是设置默认的响应编码ie.返回的html/任何内容采用的编码.另一种方法是在应用程序的每个控制器中设置响应编码等.

必须将此过滤器添加到网站.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>

The instructions for making this filter are found at the 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>

或者,WebApp的所有JSP页面的顶部需要有以下内容:

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

如果使用了具有不同JSP片段的某种布局,那么它们中的所有部分都需要这样做.

HTML元标记

JSP页面编码告诉JVM以正确的编码处理JSP页面中的字符.

这是通过在webapp生成的每个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;

关键部分是字符集=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以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"的处理是正确的.

在latin1中根本不理解西里尔文字符ж.因为Tomcat被指示将请求参数作为UTF-8处理,所以它将该字符正确地编码为%D0%b6.

如果指示浏览器以UTF-8编码(带有请求头和html元标记)读取页面,则至少Firefox2/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.Even though the page/request/everything is defined to use UTF-8美元.ä的UTF-8编码版本是%C3%A4

这样做的结果是,webapp不可能正确处理GET请求中的请求参数,因为有些字符是用拉丁文1编码的,而有些字符是用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/

重要提示

supports the Basic Multilingual Plane using 3-byte UTF-8 characters. If you need to go outside of that (certain alphabets require more than 3-bytes of UTF-8), then you either need to use a flavor of VARBINARY column type or use the utf8mb4 character set (which requires MySQL 5.5.3 or later). Just be aware that using the utf8 character set in MySQL won't work 100% of the time.

带有Apache的Tomcat

如果您使用的是Apache+Tomcat+mod_JK连接器,那么还需要做以下更改:

  1. 将URIEncoding="UTF-8"添加到tomcat服务器中.用于8009连接器的xml文件,由mod_JK连接器使用.<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
  2. 转到apache文件夹,即/etc/httpd/conf,在httpd.conf file中添加AddDefaultCharset utf-8.Note:首先判断它是否存在.如果存在,您可以使用此行更新它.你也可以在底部加上这一行.

Java相关问答推荐

如何在Inspaut中获取当前路径的 * 模式 *?

使用log 4j2格式的Hibernate 显示SQL日志(log)

Javascript更新alert 可扩展内容样式与CSS—按钮更多/更少

JsonPath在多个线程中返回错误的值

RxJava PublishSubject缓冲区元素超时

解析Javadoc时链接的全限定类名

Java中是否有某种类型的池可以避免重复最近的算术运算?

如何使用Maven和Spring Boot将构建时初始化、跟踪类初始化正确传递到本机编译

在bash中将数组作为Java程序的参数传递

我无法获取我的Java Spring应用程序的Logback跟踪日志(log)输出

将带有js文件的 bootstrap 程序导入maven项目时出错

如何让JavaFx应用程序识别依赖项?

Java-动态绑定-问题-了解

类型集合的Jackson JsonNode:类型引用的对象读取器应该是Singleton吗?

Spring安全令牌刷新和JWT签名与本地计算的签名不匹配

如何使用log4j2(Json)记录由";异常引起的所有";?

无法使用Freemarker从XML中读取重复的标记值

在整数列表中查找和可被第三个整数整除的对时出现无法解释的RunTimeError

控制器建议异常处理

javax.crypto-密码对象-提供者服务是如何工作的?