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

JSP 程式設計六大常見陷阱與解決方案:NullPointer、NumberFormat、資源洩漏全攻略

     編輯:J2EE

陷阱一:println(null) 不拋異常,隱藏 Bug

現象: out.println(user.getName()),若 getName() 回傳 null,輸出字面字串 "null",而非拋出 NullPointerException。

風險: 後續字串操作(substring、equals、length())將拋出 NPE,除錯困難。

解決:

<%-- 安全輸出 --%>
<%= user.getName() != null ? user.getName() : "" %>
<%-- 或 JSTL --%>
<c:out value="${user.name}" default="未填寫" />

陷阱二:NullPointerException 高發區

典型代碼:

if (request.getParameter("username").equals("admin")) { ... } // 參數不存在 → NPE
out.println(session.getAttribute("user")); // 屬性不存在 → 輸出 null,後續操作崩潰

防禦性編程模板:

String username = request.getParameter("username");
if (username != null && username.equals("admin")) { ... }

Object userObj = session.getAttribute("user");
if (userObj != null) {
    User user = (User) userObj;
    // 安全使用
}

工具類封裝: StringUtils.isNotBlank()、Objects.requireNonNull() (Java 7+)。

陷阱三:NumberFormatException — 使用者輸入非數字

場景: int age = Integer.parseInt(request.getParameter("age"));,使用者輸入「abc」或空值。

解決:

try {
    int age = Integer.parseInt(request.getParameter("age"));
} catch (NumberFormatException e) {
    // 記錄日誌、提示用戶、設定預設值
    request.setAttribute("error", "年齡必須為數字");
    forwardToErrorPage(req, resp);
}

進階: 使用 Scanner、Apache Commons NumberUtils、Spring TypeConverter 統一參數綁定與驗證。

陷阱四:StringIndexOutOfBoundsException — 字串操作越界

原因: str.substring(0, 10) 但 str.length() < 10;str.charAt(5) 但 str == null。

解決:

public static String safeSubstring(String str, int begin, int end) {
    if (str == null) return "";
    int len = str.length();
    if (begin < 0) begin = 0;
    if (end > len) end = len;
    if (begin >= end) return "";
    return str.substring(begin, end);
}

// 或轉換為 byte[] 處理二進制安全
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);

建議: 將常用字串操作封裝至 StringUtil JavaBean,JSP 呼叫 StringUtil.truncate(str, 100)。

陷阱五:NoClassDefFoundError — 類路徑配置錯誤

原因: .class 檔案放置位置不符合容器規範;JAR 包缺失或版本衝突。

標準放置規則:

類型放置路徑
專案類別WEB-INF/classes/套件/類別.class
第三方 JARWEB-INF/lib/*.jar
共享庫 (JDBC 驅動等)Tomcat lib/*.jar (舊版 common/lib)

排查步驟: 確認類檔案存在 → 套件名稱正確 → 無重複 JAR 衝突 → 重啟容器。

陷阱六:資源洩漏導致 java.lang.Error / 系統癱瘓

核心原因: 資料庫連線、檔案流、網路 Socket、Statement/ResultSet 未關閉,導致連線池耗盡、檔案描述符耗盡、GC 壓力劇增。

鐵律:獲取資源 → try 使用 → finally 關閉

Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
    conn = dataSource.getConnection();
    pstmt = conn.prepareStatement(sql);
    rs = pstmt.executeQuery();
    // 處理結果
} finally {
    // 逆序關閉,單獨 try-catch 避免前一個關閉失敗阻塞後續
    try { if (rs != null) rs.close(); } catch (SQLException ignore) {}
    try { if (pstmt != null) pstmt.close(); } catch (SQLException ignore) {}
    try { if (conn != null) conn.close(); } catch (SQLException ignore) {}
}

Java 7+ Try-with-resources (推薦):

try (Connection conn = dataSource.getConnection();
     PreparedStatement pstmt = conn.prepareStatement(sql);
     ResultSet rs = pstmt.executeQuery()) {
    // 自動關閉,順序正確,異常安全
}

綜合最佳實踐清單

  1. 參數獲取統一封裝:RequestUtil.getString(req, "param", "default") 內建 null/空值處理。
  2. 業務邏輯下沉 JavaBean/Service:JSP 僅做參數綁定與結果顯示,零 try-catch。
  3. 使用 JSTL/EL 替代 Scriptlet:${empty param.name ? '預設' : param.name} 內建空值安全。
  4. 資源管理交給框架/連線池:Spring JdbcTemplate、MyBatis、Hibernate 自動處理關閉。
  5. 異常統一處理:web.xml <error-page> + 全域異常攔截器,避免堆疊洩露。
  6. 程式碼審查檢查點:每個 getConnection()、new FileInputStream()、HttpClient.execute() 都有對應 close()。

總結

JSP 開發六大陷阱本質上是「防禦性編程缺失」與「資源管理不當」。將驗證、轉換、資源控制封裝至工具類與框架層,JSP 退回純粹視圖角色,是根治之道。現代開發中,拒絕在 JSP 寫 Java 代碼,擁抱 Spring MVC + Thymeleaf/FreeMarker 或前後端分離架構,從源頭消除此類問題。

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