在JavaWeb系统的开发过程中,中文乱码是很头疼的问题,如何解决中文乱码成了一个很棘手的问题。
其实解决中文乱码问题的核心思想还是编码的转换,即把字符串从一种编码方式转换成另一种编码方式,如:把字符串从ISO-8859-1这种编码转换成UTF-8。
对于这种实现,我们经常地做法如下:
String value = "2121fafsdfsdfsdfsd中文";
value = new String(value.getBytes("iso8859-1"),"UTF-8");
这种解决方案如果要是在每个java类中去操作的话会很烦人的,万一需要变一种编码方式(当然这种情况极少出现,几乎不可能)的话,需要修改的地方太多,不便于后期的维护。要是能够采用一种统一的解决方案来解决这个问题的话,将会起到事半功倍的效果。
那么,我们该如何实现统一的解决方案呢?这时,过滤器就派上用场了。
思路就是我们可以做一个过滤器,对所有的请求进行统一的编码转换。实现方式如下:
方式一:使用包装类的形式解决
首先编写过滤器:
package com.ygp.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/**
* @function:设置系统统一的编码方式为UTF-8,解决中文乱码问题
* @author yankunpeng
* @date 2015-1-27下午03:19:29
* @mailto [email protected]
*/
public class MyEncodingFilter implements Filter {
private static final Logger log = Logger.getLogger(MyEncodingFilter.class);
private String encoding;
private FilterConfig filterConfig;
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public void doFilter(ServletRequest req, ServletResponse rsp,
FilterChain chain) throws IOException, ServletException {
log.info("进入" + log.getName() + "的doFilter方法");
log.info("开始执行过滤器MyEncodingFilter.............");
log.info("encoding:" + encoding);
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) rsp;
// 解决post中文乱码问题
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=" + encoding);
// 解决GET中文乱码问题
MyHttpServletRequestWrapper myRequest = new MyHttpServletRequestWrapper(
request);
// 传递给目标servlet或jsp的实际上时包装器对象的引用,而不是原始的HttpServletRequest对象
chain.doFilter(myRequest, response);
log.info("离开" + log.getName() + "的doFilter方法");
}
public void init(FilterConfig filterConfig) throws ServletException {
log.info("进入" + log.getName() + "的init方法");
log.info("开始初始化过滤器MyEncodingFilter.............");
this.filterConfig = filterConfig;
String encoding = filterConfig.getServletContext().getInitParameter(
"encoding");
if (encoding != null && encoding.trim().length() != 0) {
this.encoding = encoding;
}
log.info("encoding:" + encoding);
log.info("离开" + log.getName() + "的init方法");
}
public void destroy() {
log.info("进入" + log.getName() + "的destroy方法");
log.info("开始销毁过滤器MyEncodingFilter.............");
System.out.println(filterConfig.getFilterName() + "被销毁");
encoding = null;
filterConfig = null;
log.info("离开" + log.getName() + "的destroy方法");
}
}
实现我们的包装类:
package com.ygp.filter;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import org.apache.log4j.Logger;
/**
* @function:设置系统统一的编码方式为UTF-8,解决中文乱码问题
* @author yankunpeng
* @date 2015-1-27下午03:19:29
* @mailto [email protected]
*/
public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
private static final Logger log = Logger
.getLogger(MyHttpServletRequestWrapper.class);
private String encoding = "UTF-8";
private HttpServletRequest request;
public MyHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
this.request = request;
}
/**
* 获得被装饰对象的引用和采用的字符编码
*
* @param request
* @param encoding
*/
public MyHttpServletRequestWrapper(HttpServletRequest request,
String encoding) {
super(request);
this.encoding = encoding;
this.request = request;
}
/**
* 实际上就是调用被包装的请求对象的getParameter方法获得参数,然后再进行编码转换
*/
public String getParameter(String name) {
String value = this.request.getParameter(name);
value = ((value == null) ? null : convert(value));
return value;
}
public String convert(String parameter) {
log.info("编码转换之前:" + parameter);
String value = "";
try {
if (this.request.getMethod().equalsIgnoreCase("GET")) {
value = new String(parameter.trim().getBytes("ISO-8859-1"),
encoding);
} else {
value = parameter;
}
} catch (UnsupportedEncodingException e) {
log.info(e);
}
return value;
}
@Override
public String[] getParameterValues(String name) {
String[] values = this.request.getParameterValues(name);
String[] newValues = new String[values.length];
// 判断是否是GET
if (request.getMethod().equalsIgnoreCase("GET")) {
for (int i = 0; i < values.length; i++) {
try {
if (values[i] != null) {
newValues[i] = new String(values[i].getBytes(), request
.getCharacterEncoding());
} else {
newValues[i] = null;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return newValues;
} else {
return values;
}
}
// 重构方法
@SuppressWarnings("unchecked")
@Override
/**
* 此方法是struts2的模型驱动需要使用的方法,所以需要重写
*/
public Map getParameterMap() {
try {
if (!this.request.getMethod().equals("GET")) {// 判断是否是get请求方式
return this.request.getParameterMap();
}
Map map = this.request.getParameterMap(); // 接受客户端的数据
Map newmap = new HashMap();
for (Map.Entry entry : map.entrySet()) {
String name = entry.getKey();
String values[] = entry.getValue();
if (values == null) {
newmap.put(name, new String[] {});
continue;
}
String newvalues[] = new String[values.length];
for (int i = 0; i < values.length; i++) {
String value = values[i];
value = new String(value.getBytes("iso8859-1"),
this.request.getCharacterEncoding());
newvalues[i] = value; // 解决乱码后封装到Map中
}
newmap.put(name, newvalues);
}
return newmap;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
最后是我们的配置文件web.xml:
<context-param>
<description>全局编码 description>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
context-param>
<filter>
<filter-name>myEncodingFilterfilter-name>
<filter-class>com.ygp.filter.MyEncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>myEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
方式二:使用动态代理的方式解决
首先使用动态代理实现我们的过滤器:
package com.ygp.filter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
public class CharacterEncodingFilter implements Filter {
private static final Logger log = Logger
.getLogger(CharacterEncodingFilter.class);
private String encoding = "UTF-8";// 这里定义的事默认值,如果web.xml中没有配置,则取这个默认值,否则取配置的值
private String old_encoding = "ISO-8859-1";
private FilterConfig filterConfig;
public void setEncoding(String encoding) {
this.encoding = encoding;
}
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
log.info("进入" + log.getName() + "的doFilter方法");
log.info("开始执行过滤器CharacterEncodingFilter.............");
log.info("encoding:" + encoding);
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
// 解决post中文乱码问题
request.setCharacterEncoding(encoding);
response.setCharacterEncoding(encoding);
response.setContentType("text/html;charset=" + encoding);
// 解决get请求的中文乱码.放行将代理对象带过去,将会拦截对getParameter,getParameterValues,getParameterMap的访问,转正常了,再返回给浏览器
chain.doFilter((ServletRequest) Proxy.newProxyInstance(this.getClass()
.getClassLoader(), request.getClass().getInterfaces(),
new InvocationHandler() {
@SuppressWarnings("unchecked")
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
String methodname = method.getName(); // 拿到当前的方法
if (methodname.equals("getParameter")) {
// 执行request.getParameter获取结果
String value = (String) method
.invoke(request, args);
// 判断是否是GET
if (request.getMethod().equalsIgnoreCase("GET")) {
try {
if (value != null) {
value = new String(value
.getBytes(old_encoding),
request.getCharacterEncoding());// 转换编码返回
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return value;
}
if (methodname.equals("getParameterValues")) {
String[] values = (String[]) method.invoke(request,
args); // 执行request.getParameterValues获取结果
String[] newValues = new String[values.length];
// 判断是否是GET
if (request.getMethod().equalsIgnoreCase("GET")) {
for (int i = 0; i < values.length; i++) {
try {
if (values[i] != null) {
newValues[i] = new String(values[i]
.getBytes(), request
.getCharacterEncoding());
} else {
newValues[i] = null;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
return newValues;
} else {
return values;
}
}
if (methodname.equals("getParameterMap")) {
try {
// 执行request.getParameterMap获取结果
Map map = (Map) method
.invoke(request, args);
Map newmap = new HashMap();
// 判断是否是GET
if (request.getMethod().equalsIgnoreCase("GET")) {
for (Map.Entry entry : map
.entrySet()) {
String name = entry.getKey();
String values[] = entry.getValue();
if (values == null) {
newmap.put(name, new String[] {});
continue;
}
String newvalues[] = new String[values.length];
for (int i = 0; i < values.length; i++) {
String value = values[i];
value = new String(
value
.getBytes(old_encoding),
request
.getCharacterEncoding());
newvalues[i] = value; // 解决乱码后封装到Map中
}
newmap.put(name, newvalues);
}
return newmap;
} else {
return map;
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// 交给request执行请求
return method.invoke(request, args);
}
}), response);
log.info("离开" + log.getName() + "的doFilter方法");
}
public void init(FilterConfig filterConfig) throws ServletException {
log.info("进入" + log.getName() + "的init方法");
log.info("开始初始化过滤器CharacterEncodingFilter.............");
this.filterConfig = filterConfig;
String encoding = filterConfig.getServletContext().getInitParameter(
"encoding");
if (encoding != null && encoding.trim().length() != 0) {
this.encoding = encoding;
}
log.info("encoding:" + encoding);
log.info("离开" + log.getName() + "的init方法");
}
public void destroy() {
log.info("进入" + log.getName() + "的destroy方法");
log.info("开始销毁过滤器CharacterEncodingFilter.............");
System.out.println(filterConfig.getFilterName() + "被销毁");
encoding = "UTF-8";
filterConfig = null;
log.info("离开" + log.getName() + "的destroy方法");
}
}
最后是配置文件web.xml配置:
<context-param>
<description>全局编码 description>
<param-name>encodingparam-name>
<param-value>UTF-8param-value>
context-param>
<filter>
<filter-name>characterEncodingFilterfilter-name>
<filter-class>com.ygp.filter.CharacterEncodingFilterfilter-class>
filter>
<filter-mapping>
<filter-name>characterEncodingFilterfilter-name>
<url-pattern>/*url-pattern>
filter-mapping>
使用包装类和动态代理的方式均可以实现我们的功能。