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 → 資料庫字符集轉換,**前提是連線屬性正確**。
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" isELIgnored="false" %>
<%@ page import="java.sql.*, java.util.*" %>
@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 保證此順序)。
// 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";
SELECT * FROM NLS_DATABASE_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET', 'NLS_NCHAR_CHARACTERSET');
-- 結果: NLS_CHARACTERSET = ZHS16GBK
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` |
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)**。