Struts1 時代的經典痛點:所有頁面、配置均設置為 UTF-8,提交中文表單到 ActionForm 仍出現亂碼。根因在於 Struts1 直接將請求參數填充到 FormBean,繞過了 HttpServletRequest.setCharacterEncoding(),導致容器按默認 ISO-8859-1 解碼。本文提供兩種 Filter 解決方案(硬編碼/參數化配置),並擴展演示安全關鍵字過濾 Filter與多 Filter 鏈順序控制,助你徹底攻克編碼與安全雙重難題。
RequestProcessor 在 processPopulate() 階段調用 request.getParameter() 填充 FormBean。getParameter() 首次調用時鎖定編碼,若在此之前未調用 setCharacterEncoding(),容器使用默認 ISO-8859-1 解碼 URL 和 Body 參數。package com.xidian.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
@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 config) {}
@Override public void destroy() {}
}
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.xidian.filter.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
關鍵點: /* 攔截所有請求;chain.doFilter() 必須調用;Filter 必須配置在 Struts ActionServlet 之前(web.xml 順序決定)。
package com.xidian.filter;
import javax.servlet.*;
import java.io.IOException;
public class MyFilter implements Filter {
private String encoding = "UTF-8"; // 默認值
@Override
public void init(FilterConfig config) {
String param = config.getInitParameter("encoding");
if (param != null) encoding = param;
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding(encoding);
chain.doFilter(request, response);
}
@Override public void destroy() {}
}
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.xidian.filter.MyFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
優勢: 無需修改代碼即可切換編碼(如測試 GBK 環境),適合多環境部署。
package com.xidian.filter;
import javax.servlet.*;
import java.io.IOException;
public class SafeFilter implements Filter {
private String[] keywords;
@Override
public void init(FilterConfig config) {
String param = config.getInitParameter("keywords");
keywords = (param != null) ? param.split(";") : new String[0];
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String name = request.getParameter("name");
if (name != null) {
for (String kw : keywords) {
if (kw.equals(name)) {
request.setAttribute("err", "您不允許登錄<font color='red'>" + name + "</font>");
request.getRequestDispatcher("/WEB-INF/ifo.jsp").forward(request, response);
return; // 直接返回,阻斷後續鏈
}
}
}
chain.doFilter(request, response); // 合法放行
}
@Override public void destroy() {}
}
<!-- 1. 首先執行編碼 Filter,確保後續 Filter 讀取到正確字符 -->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.xidian.filter.MyFilter</filter-class>
<init-param><param-name>encoding</param-name><param-value>UTF-8</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 2. 其次執行安全 Filter,基於正確編碼做關鍵字匹配 -->
<filter>
<filter-name>SafeFilter</filter-name>
<filter-class>com.xidian.filter.SafeFilter</filter-class>
<init-param><param-name>keywords</param-name><param-value>拉登;小明;鳳姐</param-value></init-param>
</filter>
<filter-mapping>
<filter-name>SafeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
鐵律: 編碼 Filter 必須在最前面,否則安全 Filter 讀取到的參數已是亂碼,關鍵字匹配失效。
Struts2 內置 StrutsPrepareAndExecuteFilter 已在 prepare 階段調用 request.setCharacterEncoding(encoding),只需在 struts.xml 配置:
<constant name="struts.i18n.encoding" value="UTF-8"/>
無需手寫 Filter,框架級解決。
<filter-mapping> 聲明順序,切記「編碼優先」。