如何让UTF-8在Java webapps中运行?

kos*_*ant 363 java mysql encoding tomcat utf-8

我需要在我的Java webapp(servlets + JSP,没有使用框架)中使用UTF-8来支持äöå常规芬兰语文本和???特殊情况下的西里尔字母.

我的设置如下:

  • 开发环境:Windows XP
  • 制作环境:Debian

使用的数据库:MySQL 5.x.

用户主要使用Firefox2,但Opera 9.x,FF3,IE7和谷歌Chrome也用于访问该网站.

怎么做到这一点?

kos*_*ant 547

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

大多数字符äåö不是问题,因为浏览器使用的默认字符集和用于webapps的tomcat/java是latin1即.ISO-8859-1"理解"这些角色.

要使UTF-8在Java + Tomcat + Linux/Windows + Mysql下工作,需要以下内容:

配置Tomcat的server.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"
/>
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,关键部分是URIEncoding ="UTF-8".这保证了Tomcat将所有传入的GET参数处理为UTF-8编码.因此,当用户将以下内容写入浏览器的地址栏时:

 https://localhost:8443/ID/Users?action=search&name=*?*
Run Code Online (Sandbox Code Playgroud)

字符被处理为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() {
    }
}
Run Code Online (Sandbox Code Playgroud)

此过滤器确保如果浏览器未设置请求中使用的编码,则将其设置为UTF-8.

此过滤器完成的另一件事是设置默认响应编码即.返回的html /是什么的编码.另一种方法是在应用程序的每个控制器中设置响应编码等.

必须将此过滤器添加到web.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>
Run Code Online (Sandbox Code Playgroud)

有关制作此过滤器的说明,请访问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>
Run Code Online (Sandbox Code Playgroud)

或者,webapp的所有JSP页面都需要在它们的顶部有以下内容:

 <%@page pageEncoding="UTF-8" contentType="text/html; charset=UTF-8"%>
Run Code Online (Sandbox Code Playgroud)

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

HTML元标记

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

这是通过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' />
   ...
Run Code Online (Sandbox Code Playgroud)

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"
    />
Run Code Online (Sandbox Code Playgroud)

MySQL数据库和表

使用过的数据库必须使用UTF-8编码.这是通过使用以下内容创建数据库来实现的:

   CREATE DATABASE `ID_development` 
   /*!40100 DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci */;
Run Code Online (Sandbox Code Playgroud)

然后,所有表格也必须是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;
Run Code Online (Sandbox Code Playgroud)

关键部分是CHARSET = utf8.

MySQL服务器配置

还必须配置MySQL serveri.通常,这可以通过修改my.ini -file 在Windows中完成,在Linux中通过配置my.cnf -file来完成.在这些文件中,应该定义连接到服务器的所有客户端都使用utf8作为默认字符集,并且服务器使用的默认字符集也是utf8.

   [client]
   port=3306
   default-character-set=utf8

   [mysql]
   default-character-set=utf8
Run Code Online (Sandbox Code Playgroud)

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 ;
Run Code Online (Sandbox Code Playgroud)

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=?
Run Code Online (Sandbox Code Playgroud)

由于ASCII字符的编码方式与latin1和UTF-8相同,因此正确处理字符串"Petteri".

latin1中完全没有理解西里尔字符.因为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*
Run Code Online (Sandbox Code Playgroud)

进入编码版本

    https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*
Run Code Online (Sandbox Code Playgroud)

在latin1中,角色ä编码为%E4.即使页面/请求/所有内容都定义为使用UTF-8.UT的UTF-8编码版本是%C3%A4

结果是,webapp很难从GET请求中正确处理请求参数,因为某些字符在latin1中编码,而其他字符在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字符的Basic Multilingual Plane.如果你需要超出它(某些字母表需要超过3个字节的UTF-8),那么你需要使用一种VARBINARY列类型或使用utf8mb4字符集(这需要MySQL 5.5.3或更高版本).请注意使用utf8 MySQL中字符集不会100%有效.

Tomcat与Apache

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

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

  • 两条评论:1)在**HMTL-meta标签**中你包含了一个xml声明.删除它,它只会在怪异模式下触发浏览器,你不想拥有它.此外,HTML元标记实际上已经由JSP`pageEncoding`隐式完成,因此您甚至可以将其保留.2)在**MySQL数据库和表**中你使用了`utf8_swedish_si`,这应该是`utf8_unicode_ci`.你甚至可以离开整理,只需`CHARACTER SET utf8`即可. (17认同)
  • ## Tomcat with 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 'httpd.conf'文件中的-8`.**注意:**首先检查它是否存在.如果存在,您可以使用此行更新它.您也可以在底部添加此行. (3认同)

sti*_*ian 13

我想你在自己的答案中总结得很好.

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

  • 你在Catalina.bat文件中将它添加到哪里? (2认同)

Rae*_*ald 11

要添加到kosoant的答案,如果您使用的是Spring,而不是编写自己的Servlet过滤器,则可以使用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>
Run Code Online (Sandbox Code Playgroud)