根据filter的执行顺序知,会先执行CharacterEncoding过滤器,再执行Struts2过滤器。
CharacterEncodingFilter的核心doFilterInternal方法如下:
view plaincopy to clipboardprint?
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
request.setCharacterEncoding(this.encoding);//设置字符集编码
if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
response.setCharacterEncoding(this.encoding);
}
}
filterChain.doFilter(request, response);//激活下一个过滤器
}
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
request.setCharacterEncoding(this.encoding);//设置字符集编码
if (this.forceEncoding && responseSetCharacterEncodingAvailable) {
response.setCharacterEncoding(this.encoding);
}
}
filterChain.doFilter(request, response);//激活下一个过滤器
}
很简洁,只要this.encoding != null就会设置request的字符集编码,this.encoding就是web.xml中CharacterEncoding过滤器配置的encoding为GBK。
到这里我们已经执行了一个Filter(CharacterEncoding)已经把request的字符集设置为GBK,然后执行filterChain.doFilter(request, response);//激活下一个过滤器即我们定义的Struts2过滤器。
到这里request的字符集编码还是GBK,但是我们在Action中取得的中文为乱码,使用request.getCharacterEncoding()获取的编码为UTF-8,那么我们可以肯定问题出在FilterDispatcher过滤器上。查看FilterDispatcher的源代码,在其doFilter方法里找到了prepareDispatcherAndWrapRequest方法,看其名字是对request进行预处理和封装的方法。
view plaincopy to clipboardprint?
protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
Dispatcher du = Dispatcher.getInstance();
if (du == null) {
Dispatcher.setInstance(dispatcher);
dispatcher.prepare(request, response);//设置编码的关键地方
} else {
dispatcher = du;
}
//省略一些代码
return request;
}
protected HttpServletRequest prepareDispatcherAndWrapRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException {
Dispatcher du = Dispatcher.getInstance();
if (du == null) {
Dispatcher.setInstance(dispatcher);
dispatcher.prepare(request, response);//设置编码的关键地方
} else {
dispatcher = du;
}
//省略一些代码
return request;
}
展开dispatcher.prepare(request, response)发现:
view plaincopy to clipboardprint?
public void prepare(HttpServletRequest request, HttpServletResponse response) {
String encoding = null;
if (defaultEncoding != null) {
encoding = defaultEncoding;
}
//省略了一些代码
if (encoding != null) {
try {
request.setCharacterEncoding(encoding);//设置了字符集编码
} catch (Exception e) {
LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
}
}
//省略了一些代码
}
public void prepare(HttpServletRequest request, HttpServletResponse response) {
String encoding = null;
if (defaultEncoding != null) {
encoding = defaultEncoding;
}
//省略了一些代码
if (encoding != null) {
try {
request.setCharacterEncoding(encoding);//设置了字符集编码
} catch (Exception e) {
LOG.error("Error setting character encoding to '" + encoding + "' - ignoring.", e);
}
}
//省略了一些代码
}
可以发现FilterDispatcher过滤器设置了request的字符编码,值来自defaultEncoding(看上面的代码),而defaultEncoding则是通过struts的配置文件取得的,即struts.i18n.encoding的属性值。view plaincopy to clipboardprint?
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
public static void setDefaultEncoding(String val) {
defaultEncoding = val;
}
@Inject(StrutsConstants.STRUTS_I18N_ENCODING)
public static void setDefaultEncoding(String val) {
defaultEncoding = val;
}
如果没有配置struts.i18n.encoding的值,默认是UTF-8.现在我们明白为什么中文是乱码了,也明白了为什么在Action中获取的编码是UTF-8啦。解决方法也很简单,在struts.xml文件中配置好struts.i18n.encoding的值为GBK即可,可以选择是否去掉spring的编码过滤器。
<constant name="struts.i18n.encoding" value="gbk"></constant>