Tomcat乱码解决
最近遇到个问题,在浏览器中提交一个请求,包含中文值的参数,在服务器端接收到编码为ISO-8859-1
,而不是期望的UTF-8
,结果造成乱码。
应用的架构为jsp+tomcat+struts+postgresql。
通过排查和struts,postgresql都没有关系。Tomcat的默认的编码使用的ISO-8859-1
,参考tomcat faq一般通过以下几个步骤把整个环境设置为UTF-8
。
-
提交请求的页面
-
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
-
HTML
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-
-
请求编码设置
-
GET: 在server.xml的<Connector>中指定
URIEncoding="UTF-8"
。 -
POST:使用过滤器
-
package yan.test.tomcat.encoding;
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;
public class CharacterEncodingFilter implements Filter{
@Override
public void destroy(){
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,ServletException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
}
}
<filter>
<filter-name>characterEncoding</filter-name>
<filter-class>yan.test.tomcat.encoding.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>characterEncoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
我的问题很奇怪,通过上面的办法在servlet接收到的字符还是使用ISO-8859-1
编码。最后发现原来在这个应用中配置了个valve。在请求到达我的编码过滤器的时候,已经被getParameter(),这样就导致请求编码使用了默认的ISO-8859-1
。
解决方法是在该valve类的invoke方法开始的地方添加request.setCharacterEncoding("UTF-8");
附录
修改请求参数的方法:
因为请求是不可更改的,如果向请求参数map中put,会得到例外java.lang.IllegalStateException: No modifications are allowed to a locked ParameterMap
方法:自己实现一个HttpServletRequestWrapper
package yan.test.tomcat.encoding;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class MYHttpServletRequestWrapper extends HttpServletRequestWrapper{
Map<String, String[]> params = null;
public MYHttpServletRequestWrapper(HttpServletRequest request,Map inParam) {
super(request);
params = new HashMap(inParam);
}
public void setParameter(String key,String value){
params.put(key, new String[]{value});
}
public void setParameter(String key,String[] values){
params.put(key, values);
}
@Override
public String getParameter(String name) {
Object v = params.get(name);
if (v == null) {
return null;
} else if (v instanceof String[]) {
String[] strArr = (String[]) v;
if (strArr.length > 0) {
return strArr[0];
} else {
return null;
}
} else {
return v.toString();
}
}
@Override
public Map<String, String[]> getParameterMap() {
return params;
}
@Override
public Enumeration<String> getParameterNames() {
Vector l = new Vector(params.keySet());
return l.elements();
}
@Override
public String[] getParameterValues(String name) {
return params.get(name);
}
}
然后在修改请求的地方(例如一个过滤器)使用其中的2个setParameter()方法来修改请求参数。
if (request.getParameter("name") != null){
HttpServletRequest http_req = (HttpServletRequest)request;
MYHttpServletRequestWrapper myrequest = new MYHttpServletRequestWrapper(http_req, request.getParameterMap());
myrequest.setParameter("name",new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8") );
request = myrequest;
}
chain.doFilter(request,response);