數據流向:瀏覽器 → Tomcat → Filter → Servlet/Action → Service → DAO → Hibernate → JDBC → MySQL。任一節點編碼設置缺失或衝突,即導致亂碼。本文提供「零配置遺漏」的全鏈路 UTF-8 統一方案。
my.cnf / my.ini)[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_unicode_ci
init_connect='SET NAMES utf8mb4'
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
utf8 僅支持 BMP 平面(3 字節),生產環境強制 utf8mb4。ALTER DATABASE db CHARACTER SET utf8mb4; ALTER TABLE t CONVERT TO CHARACTER SET utf8mb4;CREATE DATABASE mydb CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE TABLE user (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8mb4&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
useUnicode=true&characterEncoding=utf8mb4 強制驅動以 UTF-8 收發。<property name="hibernate.connection.CharSet">utf8mb4</property>
<property name="hibernate.connection.characterEncoding">utf8mb4</property>
<property name="hibernate.connection.useUnicode">true</property>
<Connector port="8080" protocol="HTTP/1.1"
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
URIEncoding 解決 GET 請求參數中文亂碼。useBodyEncodingForURI 讓 POST 請求體編碼與 request.setCharacterEncoding 一致。<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<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> <!-- 強制覆蓋 request/response 編碼 -->
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
原理: Spring 提供的 CharacterEncodingFilter 在 doFilter 中調用 request.setCharacterEncoding(encoding) 和 response.setCharacterEncoding(encoding),forceEncoding=true 確保即使請求已讀取也強制重置。
public class EncodingFilter implements Filter {
private String encoding = "UTF-8";
private boolean force = true;
@Override
public void init(FilterConfig config) {
encoding = config.getInitParameter("encoding");
force = Boolean.parseBoolean(config.getInitParameter("forceEncoding"));
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
if (force || req.getCharacterEncoding() == null) {
req.setCharacterEncoding(encoding);
resp.setCharacterEncoding(encoding);
}
chain.doFilter(req, resp);
}
@Override public void destroy() {}
}
<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
</head>
pageEncoding:JSP 文件本身的保存編碼(IDE 必須同步設置)。contentType:響應 Headers 的 Content-Type。<meta charset>:瀏覽器渲染參考。<form action="/user/save" method="post" accept-charset="UTF-8">
<input name="name" />
</form>
accept-charset 明確告知瀏覽器以 UTF-8 編碼表單數據。
| 層級 | 檢查點 | 驗證命令/現象 |
|---|---|---|
| DB | 庫/表/列編碼 | SHOW CREATE TABLE user; 顯示 utf8mb4 |
| JDBC | 連接串參數 | 日誌顯示 SET NAMES utf8mb4 |
| Hibernate | 配置屬性 | 啟動日誌無編碼警告 |
| Tomcat | Connector 設置 | GET 中文參數正常 |
| Filter | 順序第一、force=true | POST 中文參數正常 |
| JSP | pageEncoding=UTF-8 | 頁面顯示正常 |
| 前端 | meta charset、accept-charset | 表單提交無亂碼 |
pageEncoding,不配 Filter → POST 亂碼。utf8,插入 Emoji 報錯 Incorrect string value → 必須 utf8mb4。亂碼本質是 「編碼協議不匹配」。建立「UTF-8 全鏈路」標準:數據庫 utf8mb4 → JDBC 顯式編碼 → Tomcat URIEncoding → Spring CharacterEncodingFilter(force=true) → JSP pageEncoding=UTF-8 → 前端 meta/form charset。一次配置,永久解決。新項目啟動即納入規範,老項目按清單逐層補齊,杜絕亂碼反彈。