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

Java 中文處理實戰:JDBC-ODBC Bridge Bug 繞過與 Solaris Servlet 亂碼解決方案

     編輯:Java 程式設計入門

問題一:JDBC-ODBC Bridge 中文截斷 Bug

現象

向資料表插入資料:英文正常,中文僅存前 7-8 字,後續截斷。部分資料庫 (如 Sybase SQL Anywhere 5.0) 不受影響。另存在無法建表 Bug。

根因

JDBC-ODBC Bridge (Type 1 驅動) 內部 Unicode → ANSI 轉換邏輯缺陷,導致雙位元組中文字元處理錯誤。

繞過方案:中英轉碼存儲法

核心思想: 將中文字串轉為「純 ASCII」字串存入,讀出後還原。利用 GB2312 編碼特性:漢字 = 兩個高位元組 (MSB=1),英文 = 單位元組 (MSB=0)。

編碼演算法

// 寫入:中文去高位 1,英文補 0 標記
public static String toTrueAsciiStr(String str) {
    StringBuffer sb = new StringBuffer();
    byte[] bt = str.getBytes(); // 系統預設編碼 (GBK/Big5)
    for (int i = 0; i < bt.length; i++) {
        if (bt[i] < 0) { // 高位元組 (漢字一半)
            sb.append((char)(bt[i] & 0x7F)); // 去掉 MSB
        } else { // 英文字元
            sb.append((char)0);    // 標記位
            sb.append((char)bt[i]); // 原字元
        }
    }
    return sb.toString();
}

// 讀出:還原
public static String unToTrueAsciiStr(String str) {
    byte[] bt = str.getBytes();
    int zeroCount = 0;
    for (byte b : bt) if (b == 0) zeroCount++;
    
    byte[] bt2 = new byte[bt.length - zeroCount];
    int j = 0;
    for (int i = 0; i < bt.length; i++) {
        if (bt[i] == 0) { // 英文標記
            i++;
            bt2[j++] = bt[i];
        } else { // 中文高位元組
            bt2[j++] = (byte)(bt[i] | 0x80); // 加回 MSB
        }
    }
    return new String(bt2); // 系統預設編碼解碼
}

注意事項

  • 存儲空間增加:每個英文字元額外 1 位元組
  • 資料庫工具直接查看為亂碼,需同樣還原邏輯
  • 根治建議: 棄用 JDBC-ODBC Bridge,改用 Type 4 純 Java 驅動 (MySQL Connector/J, Oracle JDBC, SQL Server JDBC 等)

問題二:Solaris 下 Servlet 中文亂碼

現象

Windows 開發測試正常,部署到 Solaris 伺服器:

  • 回傳網頁中文顯示亂碼
  • 中文關鍵字查詢資料庫失敗

根因排查

  1. 檢查請求編碼:`request.getCharacterEncoding()` 返回 `null` (瀏覽器未指定)
  2. 檢查 JVM 預設編碼:`System.getProperty("file.encoding")` → Solaris 常為 `ISO8859_1`,非 `GBK`/`Big5`/`UTF-8`
  3. Tomcat 配置缺失:`` 未設定

解決方案組合拳

1. 統一使用 UTF-8 (現代標準)






    EncodingFilter
    com.example.EncodingFilter
    
        encoding
        UTF-8
    


    EncodingFilter
    /*

2. EncodingFilter 實作

public class EncodingFilter implements Filter {
    private String encoding = "UTF-8";
    public void init(FilterConfig cfg) { 
        encoding = cfg.getInitParameter("encoding"); 
    }
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) 
            throws IOException, ServletException {
        req.setCharacterEncoding(encoding);
        res.setCharacterEncoding(encoding);
        res.setContentType("text/html;charset=" + encoding);
        chain.doFilter(req, res);
    }
    public void destroy() {}
}

3. JSP 頁面指令

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" %>

4. 資料庫連線編碼

// MySQL
jdbc:mysql://host:3306/db?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull

// Oracle (NLS_LANG 環境變數)
-Duser.language=zh -Duser.region=TW -Dfile.encoding=UTF-8

5. JVM 啟動參數強制編碼

-Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8

總結:中文處理黃金法則

  1. 全鏈路 UTF-8:瀏覽器 → Web 容器 → Servlet/JSP → JVM → 資料庫驅動 → 資料庫
  2. 棄用 Type 1 驅動:JDBC-ODBC Bridge、JDBC-ODBC 皆已淘汰
  3. 集中配置:Filter 統一設定編碼,避免分散式 `setCharacterEncoding`
  4. 資料庫層面:表/欄位 `CHARSET=utf8mb4`,連線 URL 明確指定編碼
  5. 測試驗證:部署前以中文測資跑完整寫入/讀出/查詢流程

中文亂碼本質是編碼不一致。建立統一編碼規範,自動化配置到基礎設施層,才能徹底根治。

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