中文亂碼源於編碼不一致:瀏覽器編碼 → HTTP 傳輸編碼 → 伺服器解碼 → JVM 內部編碼 → 資料庫儲存編碼 → 反向輸出。任一環節錯位即產生亂碼。本文針對 Tomcat 環境,系統梳理五大高發場景與解決方案。
現象:JSP 檔案儲存為 UTF-8/GBK,瀏覽器顯示亂碼。
原因:JSP 編譯為 Servlet 時,若未指定 pageEncoding,容器預設用 ISO-8859-1 讀取源檔。
解決:頁面頂端第一行宣告:
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
contentType:設定 HTTP Response 標頭 Content-Type: text/html;charset=UTF-8,告訴瀏覽器以 UTF-8 解碼。pageEncoding:告訴 JSP 編譯器源檔編碼為 UTF-8。現象:request.getParameter("name") 取得中文參數為亂碼。
原因:Tomcat 預設用 ISO-8859-1 解碼 Request Body。
解決:配置全域 Filter (放在所有 Filter 鏈最前):
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
req.setCharacterEncoding("UTF-8"); // 必須在 getParameter() 前呼叫
resp.setCharacterEncoding("UTF-8");
chain.doFilter(req, resp);
}
}
web.xml 註冊 (若不用註解):
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.example.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
現象:POST 正常,GET 亂碼。
原因:GET 參數在 URL Query String,屬於 HTTP 標頭範圍,request.setCharacterEncoding() 不影響標頭解碼。Tomcat 解碼 URL 使用 URIEncoding 設定。
解決:修改 $CATALINA_HOME/conf/server.xml,在 `URIEncoding="UTF-8":
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
useBodyEncodingForURI="true":若未設定 URIEncoding,回退使用 request.getCharacterEncoding() (即 Filter 設定值),雙重保險。現象:JSP 中寫死中文標籤 (如 ``),換環境或編譯亂碼。
最佳實務:程式碼與內容分離,使用 `
ApplicationResources.properties (ISO-8859-1 編碼):
button.search=查詢
label.username=用戶名
native2ascii 轉換為 Unicode 轉義檔 ApplicationResources_zh_TW.properties:
native2ascii -encoding UTF-8 ApplicationResources.properties ApplicationResources_zh_TW.properties
產生:button.search=\u67e5\u8a22
WEB-INF/classes/。struts-config.xml 配置:<message-resources parameter="ApplicationResources" /><bean:message key="button.search" /> 或 <fmt:message key="button.search" />優點:支援多國語系 (i18n)、編碼安全、內容維護集中化。
URL 加入參數:
jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull
Tomcat `
<parameter>
<name>url</name>
<value><![CDATA[jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=UTF-8]]></value>
</parameter>
<parameter>
<name>driverClassName</name>
<value>com.mysql.cj.jdbc.Driver</value>
</parameter>
注意:MySQL 8.0+ 驅動類為 com.mysql.cj.jdbc.Driver,舊版為 com.mysql.jdbc.Driver。
| 層級 | 檢查項目 | 標準值 |
|---|---|---|
| IDE/編輯器 | 檔案編碼 | UTF-8 |
| JSP | pageEncoding / contentType | UTF-8 |
| Servlet/Filter | request/response.setCharacterEncoding | UTF-8 |
| Tomcat Connector | URIEncoding / useBodyEncodingForURI | UTF-8 / true |
| 資料庫連線 | characterEncoding / connectionCollation | UTF-8 / utf8mb4_general_ci |
| 資料表/欄位 | CHARSET / COLLATE | utf8mb4 / utf8mb4_general_ci |
| 前端 HTML | <meta charset="UTF-8"> | UTF-8 |
| JS/CSS 檔案 | 檔案編碼 | UTF-8 |
中文亂碼本質是編碼協議不匹配。建立全鏈路 UTF-8 標準,配合 Filter 統一 Request/Response、Tomcat `URIEncoding` 解決 GET、資源包隔離頁面文字、JDBC URL 明確指定編碼,即可徹底根治。避免在代碼中手動 `new String(bytes, "ISO-8859-1")` 轉碼,那是治標不治本的惡習。