JSP 例外處理完整實作指南
系統性掌握 JSP 例外處理機制:三類例外分類、錯誤頁面配置、Exception 隱含物件、JSTL 結構化錯誤顯示與區域性 try-catch 處理策略。
JSP 三類例外分類
| 類別 | 特性 | 範例 | 編譯期處理 |
| 檢查型例外 (Checked Exception) | 預期可復原的錯誤,必須處理 | FileNotFoundException、SQLException、IOException | 不可忽略,必須 try-catch 或 throws |
| 執行時例外 (Runtime Exception) | 程式邏輯錯誤,可避免 | NullPointerException、ArrayIndexOutOfBoundsException、ArithmeticException | 編譯期可忽略 |
| 錯誤 (Error) | 系統層級嚴重問題,無法復原 | StackOverflowError、OutOfMemoryError、NoClassDefFoundError | 編譯期忽略,幾乎無法處理 |
錯誤頁面機制 - 全域例外處理
頁面指定錯誤頁面
<%@ page errorPage="ShowError.jsp" %>
<html><body>
<%
int x = 1;
if (x == 1) {
throw new RuntimeException("錯誤條件觸發!!!");
}
%>
</body></html>
錯誤頁面實作 (ShowError.jsp)
<%@ page isErrorPage="true" %>
<html><head><title>錯誤頁面</title></head><body>
<h1>發生錯誤</h1>
<p>抱歉,系統發生錯誤。</p>
<p>例外堆疊追蹤:</p>
<pre>
<% exception.printStackTrace(response.getWriter()); %>
</pre>
</body></html>
關鍵指令差異
| 指令 | 屬性 | 用途 |
| page | errorPage | 指定發生例外時導向的錯誤頁面 |
| page | isErrorPage | 宣告此頁為錯誤頁面,啟用 exception 隱含物件 |
執行結果
java.lang.RuntimeException: 錯誤條件觸發!!!
at org.apache.jsp.main_jsp._jspService(main_jsp.java:xx)
...
發生錯誤
抱歉,系統發生錯誤。
例外堆疊追蹤:
Exception 隱含物件完整 API
僅在 isErrorPage="true" 頁面可用,型別為 java.lang.Throwable:
| 方法 | 回傳值 | 說明 |
| getMessage() | String | 例外訊息 (建構子傳入) |
| getCause() | Throwable | 根本原因例外 |
| toString() | String | 類別名稱 + 訊息 |
| printStackTrace() | void | 輸出堆疊追蹤至 System.err |
| printStackTrace(PrintWriter) | void | 輸出至指定 Writer |
| getStackTrace() | StackTraceElement[] | 堆疊追蹤元素陣列 |
| fillInStackTrace() | Throwable | 重設堆疊追蹤為當前位置 |
JSTL 結構化錯誤頁面 - 推薦做法
ShowError.jsp (JSTL 版)
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<%@ page isErrorPage="true" %>
<html><head><title>錯誤詳情</title></head><body>
<h1>系統錯誤</h1>
<table width="100%" border="1">
<tr valign="top">
<td width="40%"><b>錯誤訊息:</b></td>
<td>${pageContext.exception}</td>
</tr>
<tr valign="top">
<td><b>請求 URI:</b></td>
<td>${pageContext.errorData.requestURI}</td>
</tr>
<tr valign="top">
<td><b>狀態碼:</b></td>
<td>${pageContext.errorData.statusCode}</td>
</tr>
<tr valign="top">
<td><b>堆疊追蹤:</b></td>
<td>
<c:forEach var="trace" items="${pageContext.exception.stackTrace}">
<p>${trace}</p>
</c:forEach>
</td>
</tr>
</table>
</body></html>
JSTL 版優勢
- 結構化表格呈現,易讀性佳
- 分離錯誤類型、請求資訊、堆疊追蹤
- 可擴充加入時間戳記、使用者資訊、請求參數
- 符合 MVC 分離關注點原則

web.xml 全域錯誤頁面配置
<web-app>
<!-- 例外類型對應錯誤頁面 -->
<error-page>
<exception-type>java.lang.NullPointerException</exception-type>
<location>/errors/null-pointer.jsp</location>
</error-page>
<error-page>
<exception-type>java.sql.SQLException</exception-type>
<location>/errors/database.jsp</location>
</error-page>
<!-- HTTP 狀態碼對應錯誤頁面 -->
<error-page>
<error-code>404</error-code>
<location>/errors/404.jsp</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/errors/500.jsp</location>
</error-page>
<!-- 預設通用錯誤頁面 -->
<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>/errors/general.jsp</location>
</error-page>
</web-app>
區域性 try-catch 區塊 - 精細控制
適用場景
- 單一頁面處理多種不同例外
- 不同例外需不同回應邏輯
- 避免跳轉至錯誤頁面,保持頁面流程
實作範例
<html><head><title>Try-Catch 範例</title></head><body>
<%
try {
int i = 1;
i = i / 0; // 觸發 ArithmeticException
out.println("結果:" + i);
} catch (ArithmeticException e) {
out.println("算術錯誤:" + e.getMessage());
} catch (NullPointerException e) {
out.println("空指標錯誤:" + e.getMessage());
} catch (Exception e) {
out.println("其他錯誤:" + e.getMessage());
}
%>
</body></html>
執行結果
算術錯誤:/ by zero
最佳實務
- 捕獲具體例外優先:子類別在前,父類別在後
- 記錄完整堆疊追蹤:log.error("訊息", e) 而非 log.error(e.getMessage())
- 使用者友善訊息:技術細節記錄日誌,畫面顯示業務語意
- 資源清理:finally 區塊關閉連線、釋放鎖、關閉串流
例外處理策略對照表
| 策略 | 適用範圍 | 優點 | 缺點 |
| 頁面 errorPage | 單一頁面 | 簡單、快速套用 | 分散配置、難以維護 |
| web.xml error-page | 全應用程式 | 集中管理、型別/狀態碼區分 | 需重新部署修改 |
| Filter 攔截 | 全應用程式 | 程式化控制、可記錄日誌、可轉向 | 複雜度較高 |
| try-catch 區塊 | 區域性業務邏輯 | 精細控制、保持流程、可區域復原 | 程式碼冗長、易遺漏 |
| ControllerAdvice (Spring) | Spring MVC 全域 | 統一 REST 錯誤格式、解耦業務邏輯 | 需 Spring 框架 |
生產環境錯誤頁面檢查清單
- [ ] 移除詳細堆疊追蹤 (僅開發環境顯示)
- [ ] 顯示友善錯誤訊息與客服聯繫資訊
- [ ] 記錄完整錯誤至日誌系統 (含請求參數、使用者、時間)
- [ ] 返回首頁/上一頁連結
- [ ] 監控系統告警整合 (5xx 錯誤率超標通知)
- [ ] 自訂 404、403、500、503 頁面