如何让 UTF-8 在 Java Web 应用程序中工作?
题
我需要让 UTF-8 在我的 Java web 应用程序(servlet + JSP,不使用框架)中工作以支持 äöå
ETC。对于常规芬兰语文本和西里尔字母,例如 ЦжФ
对于特殊情况。
我的设置如下:
- 开发环境:视窗XP
- 生产环境:德班
使用的数据库:MySQL 5.x
用户主要使用Firefox2,但也使用Opera 9.x、FF3、IE7和Google Chrome访问该网站。
如何实现这一目标?
解决方案
作为本网站的常见问题解答鼓励我自己回答。这对我有用:
大多数字符 äåö 都不是问题,因为浏览器和 tomcat/java 用于 web 应用程序的默认字符集是 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 以 UTF-8 编码处理所有传入的 GET 参数。结果,当用户将以下内容写入浏览器的地址栏时:
https://localhost:8443/ID/Users?action=search&name=*ж*
字符 ж 作为 UTF-8 处理并编码为(通常在到达服务器之前由浏览器编码)为 %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/whatever 的编码。另一种方法是设置响应编码等。在应用程序的每个控制器中。
该过滤器必须添加到 网络.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 维基 (http://wiki.apache.org/tomcat/Tomcat/UTF-8)
JSP页面编码
在你的 网络.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 页面采用哪种编码:
这是通过 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 连接
使用数据库时,必须定义连接使用 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&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 中通过修改来完成 我的.ini -file 并在 Linux 中通过配置 我的cnf -文件。在这些文件中,应定义连接到服务器的所有客户端都使用 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 ;
获取请求: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”。
西里尔字母 ж 在 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*
进入编码版本
https://localhost:8443/ID/Users?action=search&name=*P%E4ivi*
在 latin1 中,该字符 ä 被编码为 %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/
重要的提示
mysql 支持 基础多语种飞机 使用 3 字节 UTF-8 字符。如果你需要超出这个范围(某些字母需要超过 3 个字节的 UTF-8),那么你要么需要使用某种风格 VARBINARY
列类型或使用 utf8mb4
字符集 (需要 MySQL 5.5.3 或更高版本)。请注意,使用 utf8
MySQL 中的字符集不会 100% 有效。
Tomcat 与 Apache
另一件事如果您使用 Apache + Tomcat + mod_JK 连接器,那么您还需要进行以下更改:
- 将 URIEncoding="UTF-8" 添加到 8009 连接器的 tomcat server.xml 文件中,它由 mod_JK 连接器使用。
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>
- 转到您的 apache 文件夹,即
/etc/httpd/conf
并添加AddDefaultCharset utf-8
在httpd.conf file
. 笔记: 首先检查它是否存在。如果存在,您可以使用此行更新它。您也可以在底部添加此行。
其他提示
我认为您在自己的回答中总结得很好。
在从头到尾的 UTF-8-ing(?) 过程中,您可能还想确保 java 本身正在使用 UTF-8。使用 -Dfile.encoding=utf-8 作为 JVM 的参数(可以在 catalina.bat 中配置)。
要添加到 科索安特的回答, ,如果您使用 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>
我还想添加来自 这里 这部分解决了我的 utf 问题:
runtime.encoding=<encoding>
当我们想使用 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
对于我和尼克来说,所以我们永远不会忘记它,不再浪费时间......
好详细的答案。只是想再添加一件事,这肯定会帮助其他人查看 URL 上的 UTF-8 编码的实际情况。
按照以下步骤在 Firefox 中启用 URL 的 UTF-8 编码。
在地址栏中输入“about:config”。
使用过滤器输入类型搜索“network.standard-url.encode-query-utf8”属性。
- 上面的属性默认为 false,将其设置为 TRUE。
- 重新启动浏览器。
默认情况下,URL 上的 UTF-8 编码在 IE6/7/8 和 Chrome 中有效。
我遇到了类似的问题,但是,在我使用 apache commons 压缩的文件的文件名中。所以,我用这个命令解决了它:
convmv --notest -f cp1252 -t utf8 * -r
它对我来说非常有效。希望它对任何人都有帮助;)
对于我从消息包中显示 Unicode 字符的情况,我不需要应用“JSP 页面编码”部分来在我的 jsp 页面上显示 Unicode。我需要的只是“CharsetFilter”部分。
尚未提及的另一点涉及与 Ajax 一起使用的 Java Servlet。我遇到过这样的情况:网页从用户处获取 utf-8 文本,并将其发送到 JavaScript 文件,该文件将其包含在发送到 Servlet 的 URI 中。Servlet 查询数据库,捕获结果并将其作为 XML 返回到 JavaScript 文件,JavaScript 文件对其进行格式化并将格式化的响应插入到原始网页中。
在一个 Web 应用程序中,我遵循一本早期 Ajax 书籍的说明,将 JavaScript 封装到构建 URI 中。书中的例子使用了 escape() 方法,我发现它(困难的方法)是错误的。对于 utf-8,您必须使用encodeURIComponent()。
如今似乎很少有人推出自己的 Ajax,但我想我不妨添加这个。
关于 CharsetFilter
@kosoant 回答中提到....
有一个内置 Filter
在雄猫中 web.xml
(位于 conf/web.xml
)。过滤器被命名为 setCharacterEncodingFilter
并默认被注释。您可以取消注释(请记住取消注释 filter-mapping
也 )
也无需设置 jsp-config
在你的 web.xml
(我已经针对 Tomcat 7+ 进行了测试)
有时您可以通过 MySQL 管理员向导解决问题。在
启动变量 > 高级 >
并设置默认值。字符集:utf8
也许这个配置需要重启MySQL。
之前的回复并不能解决我的问题。它仅在生产环境中,使用 tomcat 和 apache mod_proxy_ajp。帖子正文丢失了非 ASCII 字符?最后的问题是 JVM defaultCharset(默认安装中的 US-ASCII:charset dfset = charset.defaultcharset();)因此,该解决方案是通过修饰符运行的tomcat服务器,可将JVM运行,用UTF-8作为默认charset:
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
在 Spring MVC 5 + Tomcat 9 + JSP 上遇到同样的问题。
经过长时间的研究,得出了一个优雅的解决方案(不 需要 过滤器 和 不 需要 变化 在雄猫中 服务器.xml (从8.0.0-RC3版本开始))
在 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 */ }
在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 */ }
以 UTF-8 编码保存所有消息源和视图文件。
添加 <%@ 页面 contentType="text/html;charset=UTF-8" %> 或者 每个 *.jsp 文件中的 <%@ page pageEncoding="UTF-8" %> 或者 将 jsp-config 描述符添加到 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>
如果您已在连接池 (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");