JSP 允許任意 Java 代碼 (<% ... %>) 混雜 HTML,導致「視圖即邏輯」,前後端強耦合,維護困難。三大技術應運而生,分層解耦:
<%= ... %>。將 Java 邏輯封裝在 Tag Handler 類中,JSP 僅聲明式使用:
<%-- 原生 Java 代碼 --%>
<% User u = (User)request.getAttribute("user"); %>
<td><%= u.getName() %></td>
<%-- JSTL + EL --%>
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<td><c:out value="${user.name}"/></td>
| 標簽庫 | 前綴 | 適用框架 | 特點 |
|---|---|---|---|
| JSTL Core | c | 通用 | 標準化、<c:forEach>、<c:if>、<c:url> |
| JSTL Format | fmt | 通用 | 國際化、日期數字格式化 |
| Struts2 Tags | s | Struts2 | 表單綁定、OGNL 集成、UI 組件 |
| Spring Form | form | Spring MVC | 模型綁定、錯誤顯示、CSRF |
實現 Tag/SimpleTag 接口,配置 .tld,打包為 JAR 發布,實現項目級組件復用。
借鑑 ECMAScript (JS) 與 XPath,提供 ${expr} 語法。
pageScope、requestScope、sessionScope、applicationScope、param、header、cookie、initParam、pageContext。${user.address.city} 自動調用 Getter,空安全 (null 不拋異常)。${list[0]}、${map.key}。empty 判空、?: 三元。<c:forEach var="user" items="${userList}">
<h5>${user.name}</h5>
<h5>${user.org.name}</h5>
</c:forEach>
ActionContext 值棧,支持 #request、#session、#parameters 等上下文變量。list.{? #this.age > 18} 過濾、list.{#this.name} 投影。@java.util.UUID@randomUUID()、new java.util.ArrayList()。<s:iterator var="user" value="userList" status="stat">
<h5>索引: <s:property value="#stat.index"/></h5>
<h5>姓名: <s:property value="user.name"/></h5>
<h5>機構: <s:property value="user.org.name"/></h5>
</s:iterator>
| 維度 | Taglib | EL | OGNL |
|---|---|---|---|
| 定位 | 視圖組件/邏輯封裝 | 輕量數據訪問表達式 | 全功能對象圖導航語言 |
| 複雜度 | 低 (聲明式) | 極低 | 高 (圖靈完備) |
| 依賴 | JSP 容器 + 標簽庫 JAR | Servlet 2.4+ (內建) | OGNL 库 + 框架集成 |
| 典型場景 | 迴圈、判斷、格式化、URL 生成 | 屬性輸出、簡單條件、集合遍歷 | 復雜表單綁定、動態屬性、類型轉換、投影選擇 |
| 框架綁定 | 通用 (JSTL) / 框架專用 | 通用 | Struts2、WebWork、MyBatis (動態 SQL) |
**Taglib 解決「邏輯復用」,EL 解決「讀取簡化」,OGNL 解決「復雜導航與綁定」。** 理解三者定位與邊界,在維護舊系統時游刃有餘;新架構選擇更現代的模板引擎或前後端分離方案。