中文亂碼本質是編碼不一致導致的字節解碼錯誤。全鏈路涉及:瀏覽器 → Tomcat → SpringMVC → MyBatis → JDBC → MySQL。任一環節編碼不匹配即產生亂碼。本文提供系統性排查與修復方案。
| 層級 | 配置點 | 標準值 | 驗證方式 |
|---|---|---|---|
| 瀏覽器 | HTTP Header / Meta 標簽 | UTF-8 | F12 Network → Response Headers |
| Tomcat | server.xml Connector | URIEncoding="UTF-8" | GET 參數中文正常 |
| SpringMVC | CharacterEncodingFilter | UTF-8 + forceEncoding=true | POST 表單中文正常 |
| JSP/Thymeleaf | pageEncoding / charset | UTF-8 | 頁面顯示正常 |
| MyBatis | resultType / TypeHandler | 匹配數據庫字段類型 | Blob/Clob 正確讀取 |
| JDBC URL | connection parameters | characterEncoding=utf8mb4 | 寫入讀取無亂碼 |
| MySQL | 表/庫/連接編碼 | utf8mb4 / utf8mb4_general_ci | SHOW VARIABLES LIKE 'char%' |
<filter>
<filter-name>encodingFilter</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>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443"
URIEncoding="UTF-8"
useBodyEncodingForURI="true" />
// 方案一:@ResponseBody 返回 String 時指定編碼
@GetMapping(value = "/api/text", produces = "text/plain;charset=UTF-8")
@ResponseBody
public String getText() { return "中文內容"; }
// 方案二:返回對象,配置 HttpMessageConverter
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
StringHttpMessageConverter stringConverter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
converters.add(0, stringConverter); // 優先級最高
}
}
// 方案三:全局響應攔截器
@Component
public class EncodingResponseInterceptor implements HandlerInterceptor {
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
response.setCharacterEncoding("UTF-8");
}
}
<!-- Mapper XML:Blob 字段映射為 byte[] -->
<select id="selectContent" resultType="java.util.HashMap">
SELECT id, content FROM article WHERE id = #{id}
</select>
<!-- Service 處理 -->
public String getContent(Long id) {
Map<String, Object> row = mapper.selectContent(id);
byte[] blobData = (byte[]) row.get("content"); // 或 getBytes("content")
return new String(blobData, StandardCharsets.UTF_8);
}
jdbc:mysql://localhost:3306/mydb?
useUnicode=true&
characterEncoding=utf8mb4&
useSSL=false&
serverTimezone=UTC&
allowPublicKeyRetrieval=true
-- 1. 檢查當前編碼
SHOW VARIABLES LIKE 'character_set_%';
SHOW VARIABLES LIKE 'collation_%';
-- 2. 修改配置文件 my.cnf / my.ini
[mysqld]
character-set-server=utf8mb4
collation-server=utf8mb4_general_ci
init_connect='SET NAMES utf8mb4'
[client]
default-character-set=utf8mb4
[mysql]
default-character-set=utf8mb4
-- 3. 重啟 MySQL 後,修改現有庫表
ALTER DATABASE mydb CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci;
ALTER TABLE article CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
-- 或單獨修改字段
ALTER TABLE article MODIFY content LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
亂碼現象
├── 頁面顯示 ? / 鏡像字符
│ ├── 檢查 JSP pageEncoding="UTF-8"
│ ├── 檢查 SpringMVC produces="...charset=UTF-8"
│ └── 檢查 Tomcat URIEncoding="UTF-8"
├── 數據庫存入 ?? / 亂碼
│ ├── 檢查 JDBC URL characterEncoding=utf8mb4
│ ├── 檢查 MySQL 表/庫編碼 utf8mb4
│ └── 檢查 MyBatis resultType 是否匹配 (Blob→byte[])
├── GET 請求參數亂碼
│ └── Tomcat server.xml URIEncoding="UTF-8"
├── POST 請求參數亂碼
│ └── CharacterEncodingFilter forceEncoding=true
└── 文件下載中文文件名亂碼
└── URLEncoder.encode(fileName, "UTF-8") + 瀏覽器兼容處理
中文亂碼解決核心三步:全鏈路 UTF-8 統一 → Blob/Clob 正確類型映射 → MySQL utf8mb4 徹底配置。建立「編碼檢查清單」納入代碼評審,新增接口必驗中文場景,從源頭杜絕亂碼。