JSP 作為 Java Web 開發的標準技術,雖然普及度極高,但其設計哲學與實際使用中存在諸多爭議。本文對比 JSP 與模板引擎,深度剖析 JSP 七大核心痛點,並提供相應解決方案與現代化替代建議。
out.println(\"...\") 硬編碼 HTML,維護極其痛苦。JSP 允許在頁面任意位置編寫 Java 代碼 (<% %>、<%= %>),誘導開發者將業務邏輯、SQL 查詢、複雜計算直接寫在視圖層。模板引擎 (如 Velocity) 僅提供簡單的變量輸出、條件、循環指令,強迫邏輯前移到 Controller/Service。
JSP 獲取上下文路徑:
<a href="<%= request.getContextPath() %>/index.html">首頁</a>
<!-- 或冗長的標籤 -->
<a href="<jsp:getProperty name="request" property="contextPath"/>/index.html">首頁</a>
Velocity:
#set($ctx = $request.contextPath)
<a href="$ctx/index.html">首頁</a>
模板語法更接近自然語言,設計師零學習成本。
JSP 包含頭尾需定義變量、靜態包含指令,路徑硬編碼:
<% String title = "頁面標題"; %>
<%@ include file="/header.jsp" %>
...
<%@ include file="/footer.jsp" %>
Velocity 原生支援佈局與覆蓋:
#set($title = "頁面標題")
#parse("layout.vm") # 佈局模板內部 #parse("header.vm") $!bodyContent #parse("footer.vm")
JSP 循環需寫完整 Java 迭代器代碼:
<% Enumeration e = list.elements(); while (e.hasMoreElements()) { ISP isp = (ISP)e.nextElement(); %>
<%= isp.getName() %><br>
<% } %>
Velocity 一行搞定:
#foreach($isp in $isps)
$isp.name <br>
#end
JSP 先翻譯為 Servlet 再編譯,錯誤堆疊指向生成的 Java 文件行號,而非原始 JSP 行。例如靜態變量聲明錯誤:
<% static String title = "Global"; %> <!-- 錯誤:方法內不能有 static -->
報錯指向生成 Servlet 的第 70 行,提示 "Statement expected",新手完全無法理解。
模板引擎直接解析執行,錯誤精確定位到模板文件行列。
JSP 容器需內置 tools.jar (含 javac),Sun 拒絕開源該庫,導致純 Java 容器 (如早期 Jetty、Resin) 需依賴 IBM Jikes 等第三方編譯器,跨平台性受損。模板引擎無編譯步驟,純解釋執行,天然跨平台。
每個 JSP 編譯生成一個 .class 文件,30KB JSP 產生 30KB+ class,磁碟佔用翻倍。所有 class 長駐內存 (除非類卸載),大型站點內存壓力大。模板引擎無編譯產物,內存緩存完全可控。
JSP 的設計初衷包含「降低 ASP 開發者遷移門檻」(語法極度相似),這在 2000 年前後極具戰略價值。但今日視角下:
| 場景 | 推薦方案 | 理由 |
|---|---|---|
| 傳統專案維護、團隊僅懂 JSP | 繼續使用 JSP + JSTL + EL,禁用 Scriptlet | 零遷移成本,規範開發規約可控制質量 |
| 新專案、前後端分離、API 化 | Thymeleaf (服務端渲染) / React/Vue (前端渲染) + Spring Boot | 現代化生態、類型安全、前端工程化、支援原型開發 |
| 高性能模板渲染、大並發 | FreeMarker / Velocity / Pebble | 解析快、內存效率高、語法純粹 |
| 郵件/報表/靜態頁生成 | Thymeleaf / FreeMarker (脫離 Web 容器運行) | 模板引擎原生支援獨立運行 |
<%@ page isELIgnored="false" %> 啟用 EL 表達式。<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>。<c:forEach>、<c:if>、<fmt:formatDate>、<c:url> 等標籤。
4. 業務數據由 Controller 封裝為 POJO/Map 放入 request/session/application 域,JSP 僅讀取展示。
5. 複雜展示邏輯封裝為自定義標籤或 EL 函數,不在 JSP 寫 Java 代碼。
6. 配置 Maven jspc 插件預編譯 JSP,構建階段發現語法錯誤。
JSP 是 Java Web 發展史上的里程碑,解決了 Servlet 生成 HTML 的痛苦,推動了 MVC 模式普及。但其「允許在視圖寫 Java」的設計在今天看是反模式。模板引擎通過強制分離、簡化語法、消除編譯,更符合現代前後端分離、設計師協作、高性能渲染的需求。理解 JSP 的缺陷,不是為了否定它,而是為了在受限環境下寫出更好的 JSP,或在選型時做出更清醒的決策。