代码之家  ›  专栏  ›  技术社区  ›  kosoant

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

  •  352
  • kosoant  · 技术社区  · 16 年前

    我需要在我的Java WebAPP(servlet +jsp,没有框架使用)中支持UTF-8工作。 äöå 等。用于常规芬兰语文本和西里尔字母,如 ЦжФ 对于特殊情况。

    我的设置如下:

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

    使用的数据库:mysql 5.x

    用户主要使用FireFox2,也使用Opera9.x、FF3、IE7和Google Chrome访问该网站。

    如何做到这一点?

    13 回复  |  直到 7 年前
        1
  •  532
  •   Unmitigated    7 年前

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

    大多数字符是不存在问题的,因为浏览器和Tomcat/Java用于Web应用程序所使用的默认字符集是LATIN 1,即ISO-859-1,“理解”这些字符。

    要获得UTF-8在Java+Tomcat + LINUX/WINDOWS + MySQL下工作需要如下:

    配置Tomcat的server.xml

    必须配置连接器使用UTF-8对URL(GET REQUEST)参数进行编码:

    <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编码的Quarante。 因此,当用户将以下内容写入浏览器的地址栏时:

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

    字符gaw被处理为utf-8,并被编码为(通常由浏览器在到达服务器之前)as %D0%B6 .

    Post请求不受此影响。

    字符滤波器

    然后是强制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 或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>
    

    或者,webapp的所有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编码。这是在 上下文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中通过修改 米尼 -通过配置 肌动蛋白 -文件。 在这些文件中,应该定义所有连接到服务器的客户机都使用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=ж
    

    因为ASCII字符的编码方式与Latin1和UTF-8相同,所以正确处理字符串“petteri”。

    在拉丁语1中,西里尔文字符“霏”根本不被理解。因为指示Tomcat将请求参数作为utf-8处理,所以它将该字符正确编码为 %D0%B6 .

    如果和当浏览器被指示以UTF-8编码(带有请求头和HTML元标记)读取页面时,至少该时期的Firefox 2/3和其他浏览器都将字符本身编码为 %D0%B6 .

    最终结果是找到了所有名为“petteri”的用户,也找到了所有名为“wang”的用户。

    但是,你觉得呢?

    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*
    

    拉丁语1中的角色 腐殖质 编码为 %E4 . 即使页面/请求/所有内容都定义为使用UTF-8 . _的UTF-8编码版本是 %C3%A4

    这样做的结果是,webapp很难正确处理来自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/

    重要注意事项

    支持 Basic Multilingual Plane 使用3字节的UTF-8字符。如果您需要超出这个范围(某些字母表需要超过3字节的UTF-8),那么您要么需要使用 VARBINARY 列类型或使用 utf8mb4 character set (需要MySQL5.5.3或更高版本)。只需注意使用 utf8 MySQL中的字符集不会100%工作。

    带阿帕奇的汤姆猫

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

    1. 将uriencoding=“utf-8”添加到8009连接器的tomcat server.xml文件中,供mod_jk connector使用。 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
    2. 转到Apache文件夹,即 /etc/httpd/conf 并添加 AddDefaultCharset utf-8 在里面 httpd.conf file . 注: 首先检查它是否存在。如果存在,您可以用此行更新它。您也可以在底部添加此行。
        2
  •  12
  •   stian    16 年前

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

    在utf-8-ing过程中(?)从端到端,您可能还希望确保Java本身使用UTF-8。使用-dfile.encoding=utf-8作为jvm的参数(可以在catalina.bat中配置)。

        3
  •  10
  •   Community CDub    8 年前

    添加到 kosoant's answer ,如果您使用的是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>
    
        4
  •  2
  •   n00begon Priidu Neemre    12 年前

    我还想从 here 这部分解决了我的UTF问题:

    runtime.encoding=<encoding>
    
        5
  •  1
  •   Mike Mountrakis    15 年前

    当我们想用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
    

    对我和尼克来说,我们永远不会忘记它,也不会再浪费时间……

        6
  •  1
  •   Jay    15 年前

    回答得很详细。只想再增加一件事,这肯定会帮助其他人看到在URL上的UTF-8编码在行动中。

    按照下面的步骤在Firefox中启用URL的UTF-8编码。

    1. 在地址栏中键入“about:config”。

    2. 使用筛选器输入类型搜索“network.standard url.encode-query-utf8”属性。

    3. 默认情况下,上述属性将为假,将其设置为真。
    4. 重新启动浏览器。

    URL上的UTF-8编码在IE6/7/8和Chrome中默认工作。

        7
  •  0
  •   caarlos0    14 年前

    我有一个类似的问题,但是,在一个文件的文件名中,我用ApacheCommons进行压缩。 所以,我用这个命令解决了这个问题:

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

    它对我很管用。希望它能帮助任何人;)

        8
  •  0
  •   bnguyen82    13 年前

    对于显示来自消息束的Unicode字符的情况,我不需要应用“JSP页面编码”部分来在JSP页面上显示Unicode。我只需要“charsetfilter”部分。

        9
  •  0
  •   David striking against AI    9 年前

    还没有提到的另一点涉及使用Ajax工作的Java servlet。在某些情况下,网页会从用户那里获取utf-8文本,并将其发送到一个javascript文件,该文件包含在发送到servlet的URI中。servlet查询数据库,捕获结果并将其作为XML返回到javascript文件,该文件对其进行格式化,并将格式化的响应插入到原始网页中。

    在一个Web应用程序中,我遵循了早期的Ajax手册中关于在构建URI时包装JavaScript的说明。书中的示例使用了escape()方法,我发现(硬方法)是错误的。对于UTF-8,必须使用EncodeUriComponent()。

    现在似乎很少有人使用自己的Ajax,但我想我还是添加一点。

        10
  •  0
  •   Alireza Fattahi    8 年前

    关于 CharsetFilter @kosoant answer中提到……

    有一个内置的 Filter 在Tomcat中 web.xml (位于 conf/web.xml )过滤器命名为 setCharacterEncodingFilter 默认为注释。您可以取消对此的注释(请记住取消注释 filter-mapping 太)

    也不需要设置 jsp-config 在你 Web.XML (我已经为Tomcat 7+测试过了)

        11
  •  0
  •   MrSalesi    8 年前

    有时您可以通过MySQL管理员向导解决问题。在

    启动变量>高级>

    并设置DEF。字符集:UTF8

    也许这个配置需要重启mysql。

        12
  •  0
  •   Rogelio Triviño    7 年前

    以前的回答对我的问题不起作用。它只是在生产中,与Tomcat和Apache mod_proxy_ajp。邮件正文是否丢失了非ASCII字符? 最后一个问题是jvm default charset(us-ascii在默认设置中:charset fset=charset.default charset();) 因此,解决方案是使用修改器运行tomcat server,以使用utf-8作为默认字符集运行jvm:

    JAVA_OPTS="$JAVA_OPTS -Dfile.encoding=UTF-8" 
    

    (将此行添加到catalina.sh并服务tomcat restart)

    可能还必须更改Linux系统变量(编辑~/.bashrc和~/.profile以获取永久更改,请参见 https://perlgeek.de/en/article/set-up-a-clean-utf8-environment )

    导出lc_all=en_us.utf-8
    导出lang=en_.utf-8

    导出语言=en_-us.utf-8

        13
  •  -1
  •   LPL user462990    13 年前

    在连接池(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");
    
    推荐文章