Java 內部以 UTF-16 處理字串,但 I/O 操作(檔案、網路、資料庫、編譯)依賴作業系統預設編碼。J2EE 環境涉及瀏覽器、Web 容器、JVM、資料庫、作業系統多層轉碼,任一環節不一致即產生亂碼。傳統方案(String.getBytes()/new String() 轉碼、容器配置編碼)皆治標不治本,且破壞封裝或違背容器與應用分離原則。
UTF-8 相容所有語言、無平台綁定、為 Web 標準編碼。解決之道是在應用程式掌控的所有輸入/輸出邊界,強制指定 UTF-8,不依賴外部環境預設值。
javac -encoding UTF-8 或 Ant/Maven/Gradle 編譯任務指定 encoding="UTF-8"。public class SetCharacterEncodingFilter implements Filter {
private String encoding = "UTF-8";
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
if (req.getCharacterEncoding() == null) {
req.setCharacterEncoding(encoding);
}
chain.doFilter(req, res);
}
// init/destroy 略
}
web.xml 配置:
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>com.example.SetCharacterEncodingFilter</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>
原理:瀏覽器提交表單編碼不一(IE 預設系統編碼、Firefox/Chrome 多為 UTF-8),Filter 在讀取參數前強制設定,確保 request.getParameter() 正確解碼。
<%@ page contentType="text/html;charset=UTF-8" %>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
雙重保險:page 指令控制 ServletResponse 編碼,meta 標籤告知瀏覽器解碼方式。
MySQL 範例:
jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true
?charSet=UTF-8。CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci(支援 Emoji)。new InputStreamReader(new FileInputStream(file), "UTF-8")<?xml version="1.0" encoding="UTF-8"?>,解析器自動處理。| 層級 | 檢查點 | 驗證方式 |
|---|---|---|
| 編譯 | class 檔案字串常數池編碼 | javap -v ClassName | grep CONSTANT_Utf8 |
| 請求 | 中文參數正確解碼 | Logger 印出 request.getParameter("name") |
| 響應 | 瀏覽器顯示正常 | 開發者工具 Network → Response Headers: Content-Type: text/html;charset=UTF-8 |
| 資料庫 | 中文存取正確 | DB Client 查詢原始位元組 HEX(column) |
| 日誌 | Log4j/Logback 輸出正常 | Appender 設定 encoding="UTF-8" |
作者實戰經驗:Struts、Tapestry、EJB、Hibernate、Jdon 等主流框架,套用上述五大邊界統一 UTF-8 後,從未遇過框架層面的編碼衝突。關鍵在於「在框架之前」透過 Filter、配置、啟動參數建立 UTF-8 執行環境。
new String(bytes, "ISO-8859-1").getBytes("UTF-8")。正解:Filter 已解決,業務代碼零處理。URIEncoding="UTF-8" 解決 GET 亂碼。正解:僅修正 URL 參數,POST Body 需 Filter;且違背應用可移植性。中文亂碼本質是「邊界編碼協議缺失」。建立「應用全鏈路 UTF-8」標準,在五大邊界各設一道防線,即可徹底消除亂碼,並獲得國際化擴展自由度。這不是技巧,是架構紀律。