如何获得UTF-8工作在Java web应用程序?

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

我的设置如下:

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

使用数据库:MySQL 5.x

用户主要使用Firefox2,也有Opera 9。使用的浏览器类型为:FF3、IE7、谷歌Chrome。

如何做到这一点?

230985 次浏览

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

大多数字符äåö不是问题,因为浏览器和tomcat/java用于webapps的默认字符集是latin1 ie。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编码。 因此,当用户向浏览器地址栏写入以下内容时:

. xml
 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/whatever的编码。另一种方法是在应用程序的每个控制器中设置响应编码等。

这个过滤器必须添加到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-meta标签

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

当使用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"
/>

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的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”被正确处理。

西里尔字母ж在拉丁语中是完全看不懂的。因为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*

在拉丁语中,字符一个被编码为% 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),那么你要么需要使用VARBINARY列类型,要么使用utf8mb4字符集(这需要MySQL 5.5.3或更高版本)。只是要注意,在MySQL中使用utf8字符集不会在100%的时间内工作。

Tomcat与Apache

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

  1. 在8009连接器的tomcat server.xml文件中添加URIEncoding="UTF-8",供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注意:首先检查它是否存在。如果存在,你可以用这一行来更新它。你也可以在底部加上这一行。

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

在从端到端的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编码。

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

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

  3. 上述属性默认为false,将其设置为TRUE。
  4. 重新启动浏览器。

在IE6/7/8和chrome浏览器中,url默认使用UTF-8编码。

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

runtime.encoding=<encoding>

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

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

这对我来说很有效。希望它能帮助到任何人;)

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

要添加到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>

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

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

现在似乎很少有人自己编写Ajax,但我想我不妨加上这个。

关于@kosoant answer ....中提到的CharsetFilter

在tomcat web.xml中的Filter中有一个构建(位于conf/web.xml)。过滤器名为setCharacterEncodingFilter,默认情况下是注释的。你可以取消注释它(请记住也取消注释它的filter-mapping)

此外,不需要在你的web.xml中设置jsp-config(我已经为Tomcat 7+测试了它)

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

启动变量>高级>

并设置Def. char set:utf8

可能这个配置需要重启MySQL。

以前的回答对我的问题不起作用。它只在生产环境中使用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和service tomcat restart)

也许你还必须改变linux系统变量(编辑~/。Bashrc和~/。永久更改配置文件,参见https://perlgeek.de/en/article/set-up-a-clean-utf8-environment)

< p >出口LC_ALL = en_US。utf - 8 < br > 出口LANG = en_US。utf - 8 < / p >

出口的语言= en_US。utf - 8

在Spring MVC 5 + Tomcat 9 + JSP上面临同样的问题 经过长时间的研究,得出了一个优雅的解决方案(在Tomcat server.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. In the DispatcherServletInitializer implementation @Override the onStartup method and set request and resource character encoding in it.

    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. Save all message source and view files in UTF-8 encoding.

  4. Add <%@ page contentType="text/html;charset=UTF-8" %> or <%@ page pageEncoding="UTF-8" %> in each *.jsp file or add jsp-config descriptor to web.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>