Servlet Filter 提供了強大的攔截機制,可在請求到達 Servlet 前後處理 HttpServletRequest/HttpServletResponse。但 HttpServletRequest 的參數 Map 是不可修改的,這限制了 Filter 的應用場景——例如想在 Struts Action 前自動去除用戶輸入的多餘空格,卻無法直接修改請求參數。
裝飾模式通過組合而非繼承動態擴展對象功能。核心角色:
ServletRequest)HttpServletRequestImpl)Servlet 規範已提供 ServletRequestWrapper / HttpServletRequestWrapper 作為裝飾基類,開發者只需繼承並覆寫目標方法:
public class TrimRequestWrapper extends HttpServletRequestWrapper {
public TrimRequestWrapper(HttpServletRequest request) { super(request); }
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return value == null ? null : value.trim();
}
@Override
public Map getParameterMap() {
Map original = super.getParameterMap();
Map trimmed = new HashMap<>();
original.forEach((k, v) -> {
String[] arr = Arrays.stream(v).map(String::trim).toArray(String[]::new);
trimmed.put(k, arr);
});
return Collections.unmodifiableMap(trimmed);
}
// 同理覆寫 getParameterValues、getParameterNames 等
}
public class TrimFilter implements Filter {
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
chain.doFilter(new TrimRequestWrapper(request), resp);
}
// init/destroy 省略
}
在 web.xml 配置 Filter 即可全局生效,所有後續 Servlet/Filter/Struts Action 獲取到的參數均已去除首尾空白。
org.apache.struts.upload.MultipartRequestWrapper 覆寫參數獲取方法實現文件上傳解析。PageFlowRequestWrapper 增強請求處理能力。SecurityContextHolderAwareRequestWrapper 注入安全上下文信息。public class XssTrimFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (request instanceof HttpServletRequest) {
chain.doFilter(new XssTrimWrapper((HttpServletRequest) request), response);
} else {
chain.doFilter(request, response);
}
}
}
class XssTrimWrapper extends HttpServletRequestWrapper {
public XssTrimWrapper(HttpServletRequest request) { super(request); }
private String clean(String input) {
return input == null ? null : input.trim().replaceAll("[\\r\\n\\t]", "");
}
@Override public String getParameter(String name) { return clean(super.getParameter(name)); }
@Override public String[] getParameterValues(String name) {
String[] vals = super.getParameterValues(name);
return vals == null ? null : Arrays.stream(vals).map(this::clean).toArray(String[]::new);
}
@Override public Map getParameterMap() {
return super.getParameterMap().entrySet().stream()
.collect(Collectors.toMap(Map.Entry::getKey, e -> Arrays.stream(e.getValue()).map(this::clean).toArray(String[]::new)));
}
}
裝飾模式完美解決了「無法修改容器創建的不可變對象」的難題。通過 HttpServletRequestWrapper,我們可以在不侵入業務代碼的前提下,實現參數清洗、XSS 防護、編碼轉換、國際化等橫切關注點,是 Servlet 開發中極具實戰價值的設計模式應用。