首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java/JSP 中文亂碼終極解決方案:從原理到實戰的完整指南

     編輯:Java 相關知識

中文亂碼是 Java 開發者繞不開的坑。本質上,亂碼源於 字節流與字符流轉換時編碼不一致。Java 內部使用 UTF-16 (char),而外部資源(資料庫、檔案、網路、瀏覽器)多使用 UTF-8、GBK、GB2312 等字節編碼。凡涉及 byte[] ⇄ char/String 轉換之處,若編碼不匹配,必現亂碼。

亂碼產生的兩大類場景

類別典型場景轉換方向
源碼編譯.java/.jsp 檔案含中文常量/註釋檔案編碼 → JVM 內部編碼
外部交互表單提交、頁面輸出、資料庫讀寫、檔案讀寫、網路流byte[] ⇄ String

核心解決原則:編碼全鏈路統一

系統中所有「字節 ↔ 字符」轉換點,必須顯式指定編碼,不可依賴平台預設值(Charset.defaultCharset() 隨作業系統、啟動參數、容器配置而變)。

場景化解決方案

1. JSP / Servlet 請求與響應編碼

// 請求:必須在讀取參數前設置
request.setCharacterEncoding("UTF-8"); // 或 GBK

// 響應:設置 Content-Type 包含 charset
response.setContentType("text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");

最佳實踐:使用 Filter 統一攔截,配置於 web.xml 首位:

@WebFilter("/*")
public class EncodingFilter implements Filter {
    private String encoding = "UTF-8";
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) {
        req.setCharacterEncoding(encoding);
        resp.setCharacterEncoding(encoding);
        resp.setContentType("text/html;charset=" + encoding);
        chain.doFilter(req, resp);
    }
}

2. Java 與資料庫交互

  • 資料庫、表、欄位編碼統一為 utf8mb4 (MySQL) / UTF-8 (PostgreSQL/Oracle)
  • JDBC URL 顯式指定:jdbc:mysql://host/db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
  • 驅動程式版本 ≥ 5.1.47 (MySQL) / 42.2.0 (PostgreSQL) 確保 utf8mb4 完整支援

3. Java 與檔案/流交互

錯誤示範:直接使用 FileReader/FileWriter(隱式使用平台預設編碼)。

正確做法:使用 InputStreamReader/OutputStreamWriter 顯式指定編碼:

// 讀取 GBK 編碼檔案
try (BufferedReader br = new BufferedReader(
        new InputStreamReader(new FileInputStream(file), "GBK"))) {
    String line;
    while ((line = br.readLine()) != null) { /* ... */ }
}

// 寫入 UTF-8 檔案
try (BufferedWriter bw = new BufferedWriter(
        new OutputStreamWriter(new FileOutputStream(file), "UTF-8"))) {
    bw.write(content);
}

4. 容器層面配置

  • Tomcat:server.xml 中 <Connector URIEncoding="UTF-8" />
  • JVM 啟動參數:-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8

經典坑案例:SmartUpload + Resin 服務化後亂碼

組件內部用 new String(byte[]) 隱式用平台預設編碼解析上傳參數。Resin 註冊為 Windows 服務後,預設編碼從 Cp1252 變為 GBK,導致解析錯誤。修正:修改組件源碼,顯式傳入 charset 參數。

檢查清單:新專案從零開始的編碼規範

  1. 專案原始碼檔案統一保存為 UTF-8 無 BOM
  2. IDE、建構工具、CI 環境統一設置 file.encoding=UTF-8
  3. 資料庫/表/欄位編碼 utf8mb4
  4. 所有外部介面(HTTP、檔案、MQ、Redis、資料庫)協定文檔明確註明編碼
  5. 代碼審查檢查點:禁止出現無參數的 String(byte[])、new String(byte[])、FileReader、FileWriter、InputStreamReader/OutputStreamWriter 無編碼參數構造器

總結

亂碼不可怕,可怕的是「靠運氣」。建立「編碼顯式化、全鏈路一致、代碼審查強制」的工程文化,才是根治之道。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved