如何使UTF-8在Java Webapps中工作?

时间:2020-03-06 14:46:44  来源:igfitidea点击:

我需要在Java Web应用程序中使用UTF-8(servlets + JSP,不使用框架),以支持??????等用于常规芬兰文本和西里尔字母,例如用于特殊情况。

我的设置如下:

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

使用的数据库:MySQL 5.x

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

如何实现呢?

解决方案

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

主要是字符???这是没有问题的,因为浏览器和tomcat / java用于Web应用程序的默认字符集是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"
/>

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

https://localhost:8443/ID/Users?action=search&name=*ж*

字符被当作UTF-8处理,并且被编码为%D0%B6(通常在到达服务器之前由浏览器编码)。

POST请求不受此影响。

CharsetFilter

然后是时候强制Java Web应用程序以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或者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>

可以在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片段的某种布局,则所有这些都需要。

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' />
   ...

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=ж

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

拉丁语1完全不了解西里尔字母。由于指示Tomcat将请求参数处理为UTF-8,因此它将该字符正确编码为%D0%B6.

如果并且当指示浏览器读取UTF-8编码的页面(带有请求标头和html meta-tag)时,至少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

结果是,由于某些字符在latin1中编码,而另一些字符在UTF-8中编码,因此webapp完全不可能正确地处理GET请求中的请求参数。
注意:如果页面被定义为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/zh-CN/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/

重要的提示

mysql支持使用3字节UTF-8字符的基本多语言平面。如果我们需要这样做(某些字母需要超过3个字节的UTF-8字节),则需要使用VARBINARY列类型的样式或者使用utf8mb4字符集(需要MySQL 5.5) .3或者更高版本)。请注意,在MySQL中使用utf8字符集不会100%地起作用。

Tomcat与Apache

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

  • 将URIEncoding =" UTF-8"添加到用于8009连接器的tomcat server.xml文件中,由mod_JK连接器使用。 &lt;连接器端口=" 8009"协议=" AJP / 1.3" redirectPort =" 8443" URIEncoding =" UTF-8" />
  • 转到apache文件夹,即/ etc / httpd / conf并在httpd.conf文件中添加AddDefaultCharset utf-8。注意:首先检查它是否存在。如果存在,我们可以使用此行对其进行更新。我们也可以在底部添加此行。

我认为我们在自己的回答中总结得很好。

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

当我们要使用Java访问它们时,这用于MySql表中的希腊编码:

在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

对于我和尼克,所以我们永远不会忘记它,浪费时间了.....

如果已在连接池(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");

不错的详细答案。只是想添加一件事,这肯定会帮助其他人看到实际使用的URL的UTF-8编码。

请按照以下步骤在firefox中的URL上启用UTF-8编码。

  • 在地址栏中输入" about:config"。
  • 使用过滤器输入类型来搜索" network.standard-url.encode-query-utf8"属性。
  • 上述属性默认为false,请将其设为TRUE。
  • 重新启动浏览器。

默认情况下,URL上的UTF-8编码在IE6 / 7/8和chrome中有效。

我还想从这里添加这部分解决了我的utf问题:

runtime.encoding=<encoding>