資料流向:資料庫存儲 → JDBC 驅動 → JVM 字串 → Web 容器 → 瀏覽器渲染。任一環節編碼不匹配,即產生亂碼。系統性解決需從五個層面入手。
-- my.cnf / my.ini (MySQL 服務端配置)
[mysqld]
character-set-server = utf8mb4
collation-server = utf8mb4_unicode_ci
[client]
default-character-set = utf8mb4
[mysql]
default-character-set = utf8mb4
重啟 MySQL 生效。建表時顯式指定:
CREATE TABLE `company` (
`cname` VARCHAR(10) NOT NULL,
`caddr` VARCHAR(100),
`ctel` VARCHAR(16)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
推薦 utf8mb4:支援完整 Unicode (含 Emoji),
utf8僅支援 BMP 平面 (3 字節),utf8mb4為 4 字節真正完整 UTF-8。
String url = "jdbc:mysql://localhost:3306/mydb?" +
"useUnicode=true&" +
"characterEncoding=utf8mb4&" +
"serverTimezone=Asia/Shanghai&" +
"useSSL=false&" +
"allowPublicKeyRetrieval=true";
Connection conn = DriverManager.getConnection(url, "user", "pass");
useUnicode=true:告知驅動使用 Unicode 編碼交互。characterEncoding=utf8mb4:指定網路傳輸編碼,必須與資料庫一致。characterSetResults=utf8mb4。<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <!-- Spring 提供 -->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value> <!-- 強制覆蓋 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
無 Spring 專案可自寫簡易 Filter:request.setCharacterEncoding("UTF-8"); response.setCharacterEncoding("UTF-8");。
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
若無法修改上游 (如舊系統 ISO-8859-1 存儲),在讀取時強制轉碼:
// 讀取請求參數 (GET 請求常見問題)
String name = request.getParameter("name");
if (name != null) {
name = new String(name.getBytes("ISO-8859-1"), "UTF-8");
}
// 讀取資料庫結果集
String dbValue = rs.getString("column_name");
// 若驅動未正確解碼,嘗試
String fixed = new String(dbValue.getBytes("ISO-8859-1"), "UTF-8");
警告:這是治標不治本,會增加 CPU 開銷且易出錯。務必優先修正層面一~三。
<meta charset="UTF-8">$.ajax({ contentType: "application/x-www-form-urlencoded; charset=UTF-8", ... }) 或 xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8")<form accept-charset="UTF-8">| 誤區 | 正確做法 |
|---|---|
| 以為 `utf8` 就夠了 | 必須用 `utf8mb4` 支援 Emoji/生僻字 |
| 只在 JSP 加 pageEncoding | 需全鏈路一致,缺一不可 |
| GET 請求中文亂碼用 POST 解決 | GET 請求依賴 Tomcat `URIEncoding`,POST 依賴 Filter/Request 編碼 |
| MySQL 8.0 仍用舊驅動類 `com.mysql.jdbc.Driver` | 必須升級為 `com.mysql.cj.jdbc.Driver` 並加 `serverTimezone` |
亂碼問題 90% 源於編碼鏈路不一致。建立標準化部署清單:資料庫 utf8mb4 → JDBC 顯式指定 → Tomcat URIEncoding → 全域 Filter 強制 UTF-8 → 頁面 Meta 聲明。一次配置到位,永久告別亂碼困擾。