首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Oracle 11g (ZHS16GBK) 與 JSP (UTF-8) 字符集轉換亂碼徹底解決方案

     編輯:程式設計綜合問答

問題場景

  • 資料庫:Oracle 11g,字符集 **ZHS16GBK** (簡體中文 GBK 超集)
  • 開發工具:MyEclipse
  • JSP 頁面:`pageEncoding="UTF-8"`
  • 現象:中文插入資料庫顯示亂碼

核心原理:雙向編碼轉換鏈路

JSP (UTF-8) 
  → Servlet (request.getParameter 解碼) 
  → Java String (UTF-16) 
  → JDBC PreparedStatement (setString) 
  → JDBC Driver (轉為資料庫字符集 ZHS16GBK) 
  → Oracle Server (儲存為 ZHS16GBK)

**關鍵點**:JDBC Driver (ojdbc) **自動處理** Java UTF-16 → 資料庫字符集轉換,**前提是連線屬性正確**。

解決方案:三大支柱

1. JSP 頁面指令 (雙重保險)

<%@ page language="java" contentType="text/html; charset=UTF-8" 
         pageEncoding="UTF-8" isELIgnored="false" %>
<%@ page import="java.sql.*, java.util.*" %>
  • `contentType`:回應瀏覽器編碼
  • `pageEncoding`:JSP 檔案本身編碼 (儲存時必須為 UTF-8 無 BOM)

2. Servlet 請求/回應編碼過濾器 (強制統一)

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

⚠ `request.setCharacterEncoding("UTF-8")` **必須在讀取任何參數前**呼叫 (Filter 保證此順序)。

3. JDBC 連線 URL 明確指定字符集 (關鍵)

// Oracle 11g/12c/19c+ (ojdbc6/7/8.jar)
String url = "jdbc:oracle:thin:@localhost:1521:ORCL?useUnicode=true&characterEncoding=UTF-8";
// 或更明確 (ojdbc8 12.2+)
String url = "jdbc:oracle:thin:@localhost:1521/ORCL?oracle.jdbc.defaultNChar=true";
  • `useUnicode=true`:啟用 Unicode 處理
  • `characterEncoding=UTF-8`:告知 Driver 客戶端編碼為 UTF-8,**Driver 會自動轉換為資料庫的 ZHS16GBK**
  • `oracle.jdbc.defaultNChar=true`:將 `setString` 視為 `NCHAR/NVARCHAR2` 繞過字符集轉換 (需資料表欄位為 N 類型)

4. 確認資料庫字符集 (僅供查詢,不可輕易修改)

SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
-- 結果: NLS_CHARACTERSET = ZHS16GBK

完整插入範例 (PreparedStatement 參數化)

String sql = "INSERT INTO user_info (username, content) VALUES (?, ?)";
try (Connection conn = DriverManager.getConnection(url, "user", "pass");
     PreparedStatement ps = conn.prepareStatement(sql)) {
    
    ps.setString(1, "張三");      // Java String (UTF-16)
    ps.setString(2, "中文內容");   // 自動轉 ZHS16GBK 送入 Oracle
    
    ps.executeUpdate();
}

常見誤區與避坑

錯誤做法後果正確做法
手動 `new String(str.getBytes("UTF-8"), "GBK")`雙重編碼破壞、資料永久損壞**絕不手動轉碼**,交給 JDBC Driver
JSP 儲存為 GBK/ANSI源碼層面已錯誤IDE 設定專案/檔案編碼為 **UTF-8 無 BOM**
Tomcat `server.xml` URIEncoding 缺失GET 參數亂碼
資料庫欄位 `VARCHAR2` 存中文ZHS16GBK 環境下正常,但跨字符集遷移麻煩新專案建議用 `NVARCHAR2` + `oracle.jdbc.defaultNChar=true`

驗證步驟

  1. 瀏覽器 → JSP 表單輸入中文 → 提交
  2. 資料庫工具 (SQL Developer/PLSQL) 查詢:`SELECT DUMP(content, 1016) FROM user_info;`
  3. 檢視十六進位:GBK 編碼中文佔 2 bytes (如 `D6D0 CEC4` = "中文")
  4. JSP 讀取顯示:正常顯示中文 → **成功**

總結

Oracle ZHS16GBK + JSP UTF-8 **無需手動轉碼**。核心三步:
1. **JSP/Filter 強制 UTF-8** 請求回應編碼
2. **JDBC URL 加 `useUnicode=true&characterEncoding=UTF-8`**
3. **PreparedStatement 參數化** 直接 `setString` 中文
JDBC Driver 自動完成 UTF-16 ↔ ZHS16GBK 雙向轉換。若仍亂碼,檢查 **Tomcat URIEncoding、檔案儲存編碼、Driver 版本 (建議 ojdbc8)**。

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