根據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>