在 Java Web 開發中,POST 請求的中文亂碼只需在 `ServletRequest` 上設定字元編碼即可輕鬆解決。然而,GET 請求的參數編碼處理卻較為棘手,因為參數附在 URL 上,伺服器預設使用 ISO-8859-1 解碼,導致中文出現亂碼。本文將介紹如何結合過濾器與裝飾者設計模式(靜態代理),優雅地增強 `HttpServletRequest` 的 `getParameter` 方法,從根源上解決 GET 請求亂碼問題。
解決方案的核心在於攔截請求並包裝原始 Request。我們建立一個繼承自 `HttpServletRequestWrapper` 的包裝類,重寫 `getParameter` 方法:當檢測到是 GET 請求時,手動將參數從 ISO-8859-1 轉碼為 UTF-8;其他情況則直接委託給原始請求對象。最後在過濾器中用這個包裝類替換原始 request 繼續傳遞給後續過濾器或 Servlet。
面對增強介面實現類的需求,常見方案有繼承、裝飾者模式、動態代理、字節碼增強等。
綜合考量,裝飾者模式配合 `HttpServletRequestWrapper` 是解決此問題的最佳實踐。
繼承 `HttpServletRequestWrapper`,僅重寫 `getParameter` 方法:
package com.example.utils;
import java.io.UnsupportedEncodingException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class EncodingRequestWrapper extends HttpServletRequestWrapper {
public EncodingRequestWrapper(HttpServletRequest request) {
super(request);
}
@Override
public String getParameter(String name) {
// 僅處理 GET 請求
if ("get".equalsIgnoreCase(super.getMethod())) {
String value = super.getParameter(name);
if (value != null) {
try {
// 核心轉碼邏輯:ISO-8859-1 -> UTF-8
return new String(value.getBytes("ISO-8859-1"), "UTF-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("編碼轉換失敗", e);
}
}
}
// 非 GET 或參數為 null,直接返回原始值
return super.getParameter(name);
}
}
在 `doFilter` 中設定 POST 編碼,並用包裝類替換 request:
import java.io.IOException;
import javax.servlet.*;
public class CharacterEncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 1. 解決 POST 亂碼
request.setCharacterEncoding("UTF-8");
// 2. 解決 GET 亂碼:包裝請求對象
HttpServletRequest httpRequest = (HttpServletRequest) request;
EncodingRequestWrapper wrappedRequest = new EncodingRequestWrapper(httpRequest);
// 3. 傳遞包裝後的請求
chain.doFilter(wrappedRequest, response);
}
// init 和 destroy 方法省略...
}
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.example.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
結合過濾器進行統一攔截,利用裝飾者模式(靜態代理)包裝 `HttpServletRequest` 並重寫 `getParameter`,是解決 GET 請求中文亂碼的經典、通用且優雅的方案。它體現了面向介面編程、單一職責與開閉原則,是 Java Web 基礎架構中值得掌握的設計模式實戰案例。