这几天发现团队中的几个新成员对于开发中的编码理解的不是很好,特意写这篇文章,帮助大家理解。
首先,我们明确我们的目标在我们的工程中全部使用UTF-8编码。
其次,我们需要了解开发中解除到的编码包括文件内容编码、请求参数编码、返回内容编码。
文件内容编码
首先我们讨论文件内容编码。jsp页面是我们MVC模式中的View,是展现到前台的页面,所以这个页面必须要支持多字节字符串(日常主要是中文),我们必须为其设置编码格式。
我们先看一个简单的jsp示例文件:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>中文页面</title>
</head>
<body>
<h1>您好,这个页面支持中文。</h1>
</body>
</html>
注意:
- 每个JSP文件的pageEncoding是基础,只有你设置了这个,tomcat在请求过来时将JSP文件转换为java文件(servlet源文件)的时候才会将其转换为非乱码格式,否则如果你将pageEncoding设置为US-ASCII,文件中的中文都会是乱码了;
- JSP头部的contentType和html部分的meta中的Content-Type其实是一回事,都是设置最后展现的时候告诉浏览器这个页面的字符集,如果这里指定的字符集浏览器中没有安装,正常情况下浏览器会提示去安装,和具体显示不太搭界。
- contentType中的charset还有个作用就是设置我们的请求响应的编码,也就是说,如果我们提交请求的时候使用的编码格式不正确,那么最后输出的结果可能也不正确,具体在servlet中我们可以通过pageContext.getResponse().getCharacterEncoding()得到这些值;
所以按照以上理论,正常情况下我们只需要设置pageEncoding就可以了,但为了支持有些用户使用的英文系统,为了提示使用者去下载中文支持,需要添加contentType。
请求参数编码
struts中使用
首先我们看一下struts2中如何使用字符编码。我们建立一个简单的struts2工程,写一个DummyAction:
package com.freesoft.action;
import com.opensymphony.xwork2.ActionSupport;
public class DummyAction extends ActionSupport {
/**
*
*/
private static final long serialVersionUID = -9106994256206918756L;
private String username;
private String password;
private Integer age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String execute() throws Exception {
System.out.println("username is " + username);
System.out.println("password is " + password);
System.out.println("age is " + age);
return SUCCESS;
}
}
我们的请求页面是:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>中文网页</title>
</head>
<body>
<h1>中文网页测试</h1>
<s:form action="dummy.action">
<s:textfield name="username" label="username"></s:textfield>
<s:textfield name="password" label="password"></s:textfield>
<s:textfield name="age" label="age"></s:textfield>
<s:submit value="submit"></s:submit>
</s:form>
</body>
</html>
结果页面:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:label value="%{username}"></s:label>
</body>
</html>
我们在请求中输入中文的名字,发现可以正确处理中文。那么我们再去深入,当你在你的struts.xml配置文件的package外面加上:
<constant name="struts.i18n.encoding" value="US-ASCII"></constant>
的时候,再去使用中文名,就会出现乱码,说明是i18n这个interceptor中的encoding属性设定了字符编码格式。我们去源码中也可以很清楚的看到默认的编码格式设置的是在org.apache.struts2.dispatcher.Dispatcher文件中使用注解方式注入。文件default.properties中就设置了这个值:
### This can be used to set your default locale and encoding scheme
# struts.locale=en_US
struts.i18n.encoding=UTF-8
所以我们可以自己去覆盖这个值。
Servlet方式
好了,struts方式搞定了之后能够保证我们的工作不出问题,下面我们随便讲讲servlet工作的流程:
servlet默认情况下是不会处理字符编码的,所以在request和response中都要你自己设置,我们看一下源代码(原来在tomcat/webapp下面的,从tomcat 7.0.20就转移到tomcat自己的源码中了,所以还需要下载一个tomcat源代码),这个类:org.apache.catalina.filters.SetCharacterEncodingFilter。
让我们再看看Tomcat给的建议,保证你在所有地方都是用UTF-8:
- 在server.xml的Connector中设置URIEncoding="UTF-8",类似于这种:
<Connector port="8090" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" enableLookups="false" redirectPort="8443" acceptCount="100" debug="0" connectionTimeout="20000" disableUploadTimeout="true" URIEncoding="UTF-8"/>
- 使用一个filter来使得编码转换为UTF-8,可以使用Tomcat提供的这个;
- 在jsp中设置contentType使用UTF-8;
- 使response的输出都使用UTF-8,也就是使用:
或者response.setContentType("text/html; charset=UTF-8")
response.setCharacterEncoding("UTF-8")
- 你使用的任何会产生内容的库(例如Velocity, Freemarker,等等)中的编码设置都设置为UTF-8。
- 在所有可能读取参数的情况之前加载你的编码转换Filter;