亂碼的本質是 「編碼不一致導致的字節序列解碼錯誤」。在 Java Web 體系中,數據流經多個環節,每個環節若編碼設置不一致,即會產生亂碼。
瀏覽器輸入/顯示 (瀏覽器編碼)
↓ HTTP 傳輸 (URL 編碼 / 請求主體編碼)
Web 伺服器/容器 (Tomcat URIEncoding / request.setCharacterEncoding)
↓ Java 內部處理 (Unicode UTF-16)
業務邏輯 / 數據庫驅動 (連接串 characterEncoding)
↓ 數據庫存儲 (表/列字符集: utf8mb4 / gbk)
數據庫讀取 → 反向流程 → 瀏覽器顯示 (response.setContentType charset)
核心鐵律:全鏈路統一編碼,推薦全站 UTF-8 (或 UTF-8MB4)。
| 字符集 | 說明 | Java 編碼名 | 備註 |
|---|---|---|---|
| GB2312-80 | 國家標準,6763 漢字 | GB2312 / EUC_CN | 早期系統,字符集較小 |
| GBK | GB2312 擴展,兼容 GB2312,含 2萬+ 字符 | GBK / CP936 | Windows 中文默認,MySQL 早期常用 |
| GB18030-2000 | 國家標準,強制兼容 GBK,含少數民族字,變長編碼 (1/2/4 字節) | GB18030 | 現代國標要求,JDK 1.4+ 支持 |
| Big5 | 繁體中文常用編碼 | Big5 / Cp950 | 台灣/香港地區歷史系統 |
| Unicode (UTF-16) | Java 內部字符表示 (char 2 字節,補充字符 4 字節) | 內部使用 | Java char 為 UTF-16 代碼單元 |
| UTF-8 | Unicode 變長編碼 (1-4 字節),ASCII 兼容,**Web 國際化標準** | UTF-8 | 強烈推薦全棧統一使用 |
現象:URL `?name=張三` 到達後端變 `??` 或 `涓婂競`。
原因:Tomcat 7 默認用 ISO-8859-1 解碼 URL 查詢字符串;Tomcat 8+ 默認 UTF-8。
修復 (server.xml Connector):
<Connector port="8080" protocol="HTTP/1.1"
URIEncoding="UTF-8" <!-- 關鍵:指定 URL 解碼編碼 -->
connectionTimeout="20000"
redirectPort="8443" />
舊版 Tomcat 7 臨時方案:`new String(param.getBytes("ISO-8859-1"), "UTF-8")` (不推薦,升級容器)。
現象:`request.getParameter("name")` 獲取亂碼。
原因:容器默認用 ISO-8859-1 解碼請求主體。
修復:在讀取任何參數前 設置:
// Servlet / Filter / Controller 入口第一行
request.setCharacterEncoding("UTF-8");
最佳實踐:配置 **字符編碼過濾器** (web.xml 或 Spring `CharacterEncodingFilter`),全局攔截保證。
注意:`multipart/form-data` (文件上傳) 需上傳組件 (Commons FileUpload / Servlet 3.0 Part API) 支持編碼設置,通常在解析前同樣需 `request.setCharacterEncoding`。
現象:JSP 頁面輸出中文變 `???` 或亂碼。
修復雙管齊下:
response.setContentType("text/html; charset=UTF-8");
// 或
response.setCharacterEncoding("UTF-8"); // 等效於設置 Content-Type charset 部分
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
原理:`pageEncoding` 指導容器以何種編碼讀取 .jsp 源文件 (生成 Servlet 時字符串常量正確);`contentType` 指導響應頭,瀏覽器據此解碼顯示。
MySQL 典型配置:
Oracle/SQL Server/PostgreSQL:同理確保數據庫/表/列字符集、JDBC 連接屬性、Java 端編碼三方一致。
Spring Boot 2.x/3.x 默認已全鏈路 UTF-8:
| 層級 | 關鍵配置項 | 推薦值 |
|---|---|---|
| 瀏覽器/前端 | HTML Meta / AJAX Content-Type | <meta charset="UTF-8"> / application/json; charset=UTF-8 |
| Web 容器 | Connector URIEncoding | UTF-8 |
| 請求處理 | request.setCharacterEncoding / Filter | UTF-8 (最早執行) |
| JSP 頁面 | pageEncoding / contentType | UTF-8 / UTF-8 |
| 響應輸出 | response.setContentType / setCharacterEncoding | text/html; charset=UTF-8 |
| 數據庫 | Schema/Table/Column Charset + JDBC URL | utf8mb4 / useUnicode=true&characterEncoding=utf8 |
| 文件/日誌 | IDE/Editor/File Encoding / Logback encoding | UTF-8 |
]]>堅持 「全棧 UTF-8 (utf8mb4)」,配置 字符編碼過濾器 為最早攔截點,升級容器至 Tomcat 9+/Jetty 9+,即可徹底告別中文亂碼噩夢。