JSTL (JSP Standard Tag Library) 是 JSP 開發的標準化標簽庫集合,提供迭代、條件、XML 處理、國際化、資料庫訪問等核心功能。本文聚焦 **Core** 與 **SQL** 標簽庫,通過實戰範例展示如何利用 JSTL 構建簡潔、可維護、無腳本程序的 JSP 頁面,並對比 PHP/ColdFusion 等傳統模式的優勢。
| 庫 | URI | 前綴 | 核心功能 |
|---|---|---|---|
| Core | https://java.sun.com/jsp/jstl/core | c | 變量設置、條件判斷、迭代循環、URL 處理、異常捕獲、重定向 |
| XML | https://java.sun.com/jsp/jstl/xml | x | XML 解析、XPath 選擇、XSLT 轉換、流控制 |
| I18N | https://java.sun.com/jsp/jstl/fmt | fmt | 格式化數字/日期、消息包、請求編碼、時區、本地化 |
| SQL | https://java.sun.com/jsp/jstl/sql | sql | 查詢、更新、事務、數據源配置、結果集遍歷 |
| Functions | https://java.sun.com/jsp/jstl/functions | fn | 字符串操作、集合操作、長度、分割、替換、轉義 |
jakarta-taglibs-standard (包含 `jstl.jar`, `standard.jar`)。<Resource name="jdbc/MyDB" auth="Container" type="javax.sql.DataSource"
maxTotal="20" maxIdle="5" maxWaitMillis="10000"
username="root" password="secret" driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost:3306/testdb?useUnicode=true&characterEncoding=UTF-8"/>
<c:set var="siteName" value="MyShop" scope="application"/>
<c:set var="user" value="${sessionScope.user}" scope="page"/>
<c:remove var="tempVar" scope="session"/>
<c:choose>
<c:when test="${user.role == 'admin'}">
<a href="/admin">管理後台</a>
</c:when>
<c:when test="${user.role == 'editor'}">
<a href="/editor">編輯工作台</a>
</c:when>
<c:otherwise>
<a href="/profile">個人中心</a>
</c:otherwise>
</c:choose>
<c:forEach var="product" items="${productList}" varStatus="status">
<tr class="${status.index % 2 == 0 ? 'even' : 'odd'}">
<td>${status.count}</td>
<td><c:out value="${product.name}"/></td>
<td><fmt:formatNumber value="${product.price}" type="currency"/></td>
<td><c:if test="${product.stock > 0}">有庫存</c:if></td>
</tr>
</c:forEach>
<a href="<c:url value='/product/detail'><c:param name='id' value='${product.id}'/></c:url>">詳情</a>
⚠️ **警告**:SQL 標簽將數據庫邏輯置於視圖層,**違反分層架構**,僅適用於:原型驗證、極簡內部工具、無服務層的微型項目。生產項目**強烈建議**使用 Service + DAO + Controller 模式。
<sql:setDataSource var="ds" driver="com.mysql.jdbc.Driver"
url="jdbc:mysql://localhost/testdb" user="root" password="secret"/>
<sql:query var="products" dataSource="${ds}" maxRows="20">
SELECT id, name, price, stock FROM products WHERE category = ?
<sql:param value="${param.category}"/>
</sql:query>
<c:forEach var="row" items="${products.rows}">
${row.name} - ${row.price} - ${row.stock}<br/>
</c:forEach>
<c:if test="${products.rowCount == 0}">無匹配產品</c:if>
<sql:transaction dataSource="${ds}" isolation="read_committed">
<sql:update var="count">
UPDATE products SET stock = stock - 1 WHERE id = ?
<sql:param value="${param.id}"/>
</sql:update>
<sql:update>
INSERT INTO orders (product_id, user_id, qty) VALUES (?, ?, 1)
<sql:param value="${param.id}"/>
<sql:param value="${sessionScope.user.id}"/>
</sql:update>
</sql:transaction>
| 維度 | JSTL + JSP | PHP | ColdFusion |
|---|---|---|---|
| 標準化 | JCP 標準規范 (JSR-52),多容器可移植 | 單一實現,語言內建 | 商業產品 (Adobe/Lucee),標準化程度低 |
| 類型安全 | EL 表達式 + 容器類型轉換 | 弱類型,隱式轉換陷阱多 | 弱類型,標簽屬性驗證較強 |
| 標簽擴展性 | Tag Library Descriptor (TLD) 規範,可自定義標簽庫 | 函數/類擴展,無標簽標準 | 自定義標簽 (CFX/CFC),生態封閉 |
| 企業級特性 | 事務、連接池、JNDI、安全管理、集群 Session | 需框架/擴展實現 | 內建但綁定平台 |
| 學習曲線 | 中等 (需理解 Servlet/JSP 生命周期、EL、作用域) | 低 (語法簡單、文檔豐富) | 低 (標簽語義化程度高) |
| 生態成熟度 | 極高 (Spring、Struts、JSF 整合無縫) | 極高 (Laravel、Symfony、WordPress) | 中等 (社區較小) |
JSTL 確立了 JSP 開發的「無腳本」規範,配合 EL 表達式,將視圖邏輯限制在聲明式標簽範圍內,極大提升了頁面可讀性、可維護性與安全性。雖然現代 Web 框架 (Spring MVC + Thymeleaf, JSF, React/Vue) 已成為主流,但理解 JSTL 設計哲學——**標準化聲明式視圖邏輯**——對於維護存量系統、設計自定義標簽庫、把握視圖層職責邊界,仍具不可替代的指導價值。