JSP 除錯技術全攻略
JSP/Servlet 涉及客戶端-伺服器互動,除錯極具挑戰。掌握從簡單列印到專業除錯器的完整技術棧,快速定位與解決問題。
基礎列印除錯:System.out.println()
優點
- 零依賴:System 為核心類別,任何環境可用 (Servlet、JSP、EJB、獨立應用)
- 非侵入式:不中斷執行流程,適合計時敏感系統
- 輸出導向:Tomcat 導向
logs/stdout.log
基本語法
System.out.println("除錯訊息: 變數值 = " + variable);
實戰範例
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<html><body>
<c:forEach var="counter" begin="1" end="10" step="1">
<c:out value="${counter-5}"/><br/>
<% System.out.println("counter = " + pageContext.findAttribute("counter")); %>
</c:forEach>
</body></html>
輸出結果
// 瀏覽器顯示
-4 -3 -2 -1 0 1 2 3 4 5
// Tomcat logs/stdout.log
counter=1
counter=2
counter=3
counter=4
counter=5
counter=6
counter=7
counter=8
counter=9
counter=10
進階日誌框架:JDK Logger (java.util.logging)
優點
- J2SE 內建,無額外依賴
- 支援多層級:SEVERE、WARNING、INFO、CONFIG、FINE、FINER、FINEST
- 可配置輸出格式、目的地、過濾規則
實戰範例
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.logging.Logger" %>
<html><body>
<% Logger logger = Logger.getLogger(this.getClass().getName()); %>
<c:forEach var="counter" begin="1" end="10" step="1">
<c:set var="myCount" value="${counter-5}" />
<c:out value="${myCount}"/><br/>
<%
String msg = "counter=" + pageContext.findAttribute("counter")
+ " myCount=" + pageContext.findAttribute("myCount");
logger.info(msg);
%>
</c:forEach>
</body></html>
輸出範例 (stdout.log)
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=1 myCount=-4
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=2 myCount=-3
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=3 myCount=-2
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=4 myCount=-1
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=5 myCount=0
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=6 myCount=1
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=7 myCount=2
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=8 myCount=3
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=9 myCount=4
24-Sep-2013 23:31:31 org.apache.jsp.main_jsp _jspService INFO: counter=10 myCount=5
日誌層級選擇指南
| 層級 | 用途 | 範例 |
| SEVERE | 嚴重錯誤,系統可能無法運作 | 資料庫連線失敗、記憶體不足 |
| WARNING | 潛在問題,但系統仍可運作 | 設定檔遺失使用預設值、重試成功 |
| INFO | 一般資訊,關鍵流程節點 | 使用者登入、訂單建立、API 呼叫 |
| CONFIG | 設定資訊 | 啟動參數、資料庫連線字串 |
| FINE | 詳細追蹤資訊 | 方法進入/離開、參數值 |
| FINER | 更詳細追蹤 | 迴圈變數、中間計算結果 |
| FINEST | 最詳細追蹤 | 每行程式碼執行、極大量資料 |
企業級日誌:Log4j / SLF4J / Logback
Log4j 2 配置範例 (log4j2.xml)
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
<Appenders>
<Console name="Console" target="SYSTEM_OUT">
<PatternLayout pattern="%d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
</Console>
<RollingFile name="File" fileName="logs/app.log"
filePattern="logs/app-%d{yyyy-MM-dd}.log.gz">
<PatternLayout pattern="%d %p %c{1.} [%t] %m%n"/>
<Policies>
<TimeBasedTriggeringPolicy/>
</Policies>
</RollingFile>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="Console"/>
<AppenderRef ref="File"/>
</Root>
<Logger name="com.myapp" level="debug"/>
</Loggers>
</Configuration>
程式碼使用
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyServlet extends HttpServlet {
private static final Logger log = LoggerFactory.getLogger(MyServlet.class);
protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
log.debug("處理請求: {}", req.getRequestURI());
log.info("使用者 {} 存取系統", getCurrentUser());
try {
// 業務邏輯
} catch (Exception e) {
log.error("處理失敗", e); // 自動包含堆疊追蹤
}
}
}
IDE 整合除錯:NetBeans / IntelliJ IDEA / Eclipse
核心功能
| 功能 | 說明 |
| 中斷點 | 程式碼特定行暫停執行,檢查變數狀態 |
| 單步執行 | Step Over (F8)、Step Into (F7)、Step Out (Shift+F8) |
| 觀察點/變數監視 | 監控特定變數值變化 |
| 條件中斷點 | 僅當條件滿足時中斷 |
| 熱部署 | 修改程式碼後無需重啟伺服器 |
NetBeans 設定 Tomcat 除錯
- Tools → Servers → Add Server → Apache Tomcat
- 專案右鍵 → Properties → Run → Server 選擇 Tomcat
- Debug → Debug Project (Ctrl+F5)
- 在 JSP/Java 程式碼設定中斷點
- 瀏覽器存取對應頁面,IDE 將在中斷點暫停
命令列除錯器:JDB (Java Debugger)
適用場景
- 無 GUI 環境的伺服器
- 生產環境緊急診斷 (需謹慎)
- 自動化除錯腳本
設定步驟
- 啟動 JVM 除錯模式:
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000 -jar app.jar
- 連接 JDB:
jdb -attach 8000
- 設定類別路徑包含 Servlet API、JSP 編譯類別、專案類別
- 設定中斷點:
stop in com.myapp.MyServlet.doGet
- 瀏覽器發送請求觸發中斷點
常用 JDB 指令
| 指令 | 功能 |
| stop at/stop in | 設定中斷點 |
| cont | 繼續執行 |
| step / next | 單步進入 / 跳過 |
| print <expr> | 列印運算式值 |
| locals | 顯示區域變數 |
| where / wherei | 顯示堆疊追蹤 |
| threads / thread | 列出/切換執行緒 |
實用除錯技巧
1. 瀏覽器檢視原始碼
- 區分「伺服器端錯誤」vs「HTML/CSS 排版問題」
- 瀏覽器 → 檢視原始碼 (Ctrl+U) 或開發者工具 (F12)
2. 強制重新整理避免快取
| 瀏覽器 | 快捷鍵 |
| Chrome / Firefox / Edge | Ctrl+Shift+R / Shift+F5 |
| Safari | Shift+重新整理按鈕 |
| IE | Ctrl+F5 |
3. HTTP 標頭檢查
- 開發者工具 → Network 標籤 → 檢查 Request/Response Headers
- 驗證 Content-Type、Set-Cookie、Cache-Control、Content-Language
4. 註解法隔離問題
- 二分法註解程式碼區塊,快速定位錯誤範圍
- JSP 使用
<%-- 註解 --%> (伺服器端,不輸出至瀏覽器)
5. 例外堆疊追蹤分析
- 從最底層 Caused by 向上追蹤根本原因
- 關注專案套件名稱的堆疊幀 (非框架內部)
- 結合原始碼行號精確定位
除錯策略選擇指南
| 場景 | 推薦方法 | 理由 |
| 快速驗證變數值 | System.out.println | 零設定、即時可見 |
| 開發環境日常除錯 | IDE 除錯器 | 視覺化、單步、變數監視 |
| 測試/預發環境問題追蹤 | Log4j/SLF4J + 集中日誌 | 持久化、可搜尋、多實例聚合 |
| 生產環境緊急診斷 | JDB / 遠端 IDE 除錯 | 不重啟、不影響其他使用者 |
| 效能分析 | Profiler (VisualVM, JProfiler) | CPU/記憶體/執行緒分析 |