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

How to get UTF-8 working in Java webapps?

提问人:kosoant 提问时间:9/26/2008 最后编辑:informatik01kosoant 更新时间:2/23/2019 访问量:234505

问:

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

我的设置如下:

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

使用的数据库:MySQL 5.x

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

如何实现这一点?

Java MySQL Tomcat 编码 UTF-8

评论

0赞 Raedwald 1/28/2014
另请参阅 stackoverflow.com/questions/153527/...

答:

563赞 kosoant 9/26/2008 #1

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

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

POST 请求不受此影响。

字符集筛选器

然后,是时候强制 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/whatever 所采用的编码。另一种方法是在应用程序的每个控制器中设置响应编码等。

必须将此筛选器添加到 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 片段的布局,那么所有这些布局都需要这样做。

HTML-meta 标记

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服务器。通常,这是在 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 的服务器 .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*

在拉丁语 1 中,字符 ä 编码为 %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

使用 Apache 的 Tomcat

还有一件事:如果您使用的是 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/confAddDefaultCharset utf-8httpd.conf file

评论

0赞 kosoant 9/26/2008
这些步骤也适用于 Struts/tiles 和 postgres 数据库。
18赞 BalusC 12/4/2009
两个注释:1)在HMTL-meta标记中,您包含了一个xml声明。删除它,它只会在怪癖模式下触发浏览器,你不想拥有它。此外,HTML 元标记实际上已经由 JSP 隐式完成,因此您甚至可以将其保留。2)在你使用的MySQL数据库和表中,这应该是.你甚至可以把整理不去,就足够了。pageEncodingutf8_swedish_siutf8_unicode_ciCHARACTER SET utf8
0赞 Marcel Stör 11/17/2010
我查阅的关于 HTML 元标记和 quirks 模式的文档(例如 ericmeyeroncss.com/bonus/render-mode.htmlen.wikipedia.org/wiki/Quirks_mode)都没有表明 <meta http-equiv='Content-Type' 的存在对呈现模式有任何影响。
4赞 Vijay Shegokar 5/23/2014
## Tomcat with Apache ## 还有一件事 如果你使用的是 Apache + Tomcat + mod_JK 连接器,那么你还需要做以下更改: 1. 将 URIEncoding=“UTF-8” 添加到 tomcat 服务器.xml文件中,用于 8009 连接器,它由mod_JK连接器使用。 2. 转到您的 apache 文件夹,即 并添加 'httpd.conf' 文件。注意:首先检查它是否存在。如果存在,您可以使用此行更新它。您也可以在底部添加此行。<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>/etc/httpd/confAddDefaultCharset utf-8
1赞 Christopher Schultz 3/29/2016
关于 Tomcat 的说明:从 Tomcat 8 开始,a 的默认值是 now ,除非您使用严格的规范合规性(在这种情况下,它默认为但仍然可以被覆盖)。URIEncoding<Connector>UTF-8ISO-8859
14赞 stian 9/28/2008 #2

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

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

评论

0赞 coding_idiot 1/7/2013
这对我有帮助,我做了提到的所有事情,但 JVM 编码是 windows-1250,一旦我更改为 UTF-8,它就可以完美运行。
2赞 Noah 3/20/2014
请问您在Catalina.bat文件中的什么位置添加它?
1赞 Mike Mountrakis 12/4/2009 #3

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

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

评论

5赞 BalusC 12/4/2009
我仍然更喜欢 UTF-8 而不是希腊语(并将您当前的希腊语数据转换为 UTF-8),以便您的应用程序为统治世界做好准备。
-1赞 Mike Mountrakis 12/12/2009 #4

如果您在连接池 (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");
1赞 Jay 2/19/2010 #5

很好的详细答案。只是想再添加一件事,这肯定会帮助其他人看到 URL 上的 UTF-8 编码。

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

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

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

  3. 默认情况下,上述属性将为 false,请将其转换为 TRUE。
  4. 重新启动浏览器。

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

2赞 John 5/14/2010 #6

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

runtime.encoding=<encoding>
0赞 caarlos0 7/20/2011 #7

我遇到了类似的问题,但是,在文件的文件名中,我正在使用 apache commons 进行压缩。 所以,我用这个命令解决了它:

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

它对我来说效果很好。希望它能帮助任何人;)

0赞 bnguyen82 6/21/2012 #8

对于我从消息包中显示 Unicode 字符的情况,我不需要应用“JSP 页面编码”部分来在我的 jsp 页面上显示 Unicode。我所需要的只是“CharsetFilter”部分。

12赞 Raedwald 1/28/2014 #9

为了补充kosoant的答案,如果你使用的是Spring,而不是编写自己的Servlet过滤器,你可以使用他们提供的类,在你的web.xml中配置如下:org.springframework.web.filter.CharacterEncodingFilter

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

评论

1赞 olyanren 5/6/2015
此筛选器必须是 web.xml 中的第一个筛选器
0赞 David 11/15/2015 #10

还有一点没有被提及,它与使用 Ajax 的 Java Servlet 有关。我遇到过这样的情况,即网页从用户那里获取 utf-8 文本,将其发送到 JavaScript 文件,该文件将其包含在发送到 Servlet 的 URI 中。Servlet 查询数据库,捕获结果并将其作为 XML 返回给 JavaScript 文件,该文件对其进行格式化,并将格式化的响应插入到原始网页中。

在一个 Web 应用程序中,我遵循了一本早期的 Ajax 书籍的说明,在构造 URI 时总结了 JavaScript。书中的例子使用了escape()方法,我发现(艰难的方式)是错误的。对于 utf-8,您必须使用 encodeURIComponent()。

如今,似乎很少有人推出自己的阿贾克斯,但我想我不妨补充一下。

0赞 Alireza Fattahi 1/9/2017 #11

关于@kosoant答案中提到的....CharsetFilter

tomcat 中有一个内置功能(位于 )。默认情况下,筛选器已命名并带有注释。您可以取消注释(请记得也取消注释)Filterweb.xmlconf/web.xmlsetCharacterEncodingFilterfilter-mapping

也无需在您的中设置(我已经为 Tomcat 7+ 测试了它)jsp-configweb.xml

0赞 MrSalesi 7/14/2017 #12

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

高级>>启动变量

并设置 Def. char Set:utf8

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

1赞 Rogelio Triviño 4/17/2018 #13

以前的回复对我的问题不起作用。它只是在生产中,有 tomcat 和 apache mod_proxy_ajp。Post body 丢失了非 ascii 字符? 最后问题出在JVM defaultCharset(默认安装中的US-ASCII:Charset dfset = Charset.defaultCharset();) 因此,解决方案是使用修饰符运行 tomcat 服务器,以运行 JVM 以 UTF-8 作为默认字符集:

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

(将此行添加到 catalina.sh 并服务 Tomcat 重新启动)

也许您还必须更改 linux 系统变量(编辑 ~/.bashrc 和 ~/.profile 永久更改,请参阅 https://perlgeek.de/en/article/set-up-a-clean-utf8-environment)

导出 LC_ALL=en_US。UTF-8
导出 LANG=en_US。UTF-8 格式

导出语言=en_US。UTF-8 格式

0赞 Andrei Veshtard 2/23/2019 #14

在 Spring MVC 5 + Tomcat 9 + JSP 上遇到了同样的问题。
经过长时间的研究,得出了一个优雅的解决方案(不需要过滤器不需要更改Tomcat服务器.xml(从8.0.0-RC3版本开始))

  1. 在 WebMvcConfigurer 实现中,为 messageSource 设置默认编码(用于从 UTF-8 编码的消息源文件中读取数据。

    @Configuration
    @EnableWebMvc
    @ComponentScan("{package.with.components}")
    public class WebApplicationContextConfig implements WebMvcConfigurer {
    
        @Bean
        public MessageSource messageSource() {
            final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
    
            messageSource.setBasenames("messages");
            messageSource.setDefaultEncoding("UTF-8");
    
            return messageSource;
        }
    
        /* other beans and methods */
    
    }
    
  2. 在 DispatcherServletInitializer 实现中,@Override onStartup 方法并在其中设置请求和资源字符编码。

    public class DispatcherServletInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        public void onStartup(final ServletContext servletContext) throws ServletException {
    
            // https://wiki.apache.org/tomcat/FAQ/CharacterEncoding
            servletContext.setRequestCharacterEncoding("UTF-8");
            servletContext.setResponseCharacterEncoding("UTF-8");
    
            super.onStartup(servletContext);
        }
    
        /* servlet mappings, root and web application configs, other methods */
    
    }
    
  3. 以 UTF-8 编码保存所有消息源并查看文件。

  4. 添加 <%@ page contentType=“text/html;charset=UTF-8“ %> <%@ page pageEncoding=”UTF-8“ %.jsp> 或添加 jsp-config 描述符到.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
     id="WebApp_ID" version="3.0">
        <display-name>AppName</display-name>
    
        <jsp-config>
            <jsp-property-group>
                <url-pattern>*.jsp</url-pattern>
                <page-encoding>UTF-8</page-encoding>
            </jsp-property-group>
        </jsp-config>
    </web-app>