JSP 規範定義了三個核心動作標簽 <jsp:useBean>、<jsp:setProperty>、<jsp:getProperty>,使 JavaBean 能以聲明式方式融入 JSP 頁面,實現「業務邏輯封裝在 Bean,頁面僅負責調用與展示」的分離。本文深度解析三大標簽的語法、屬性、作用域機制、類型轉換規則及最佳實踐。
<jsp:useBean id="beanId"
scope="page | request | session | application"
class="package.ClassName"
type="package.InterfaceOrSuperClass"
beanName="package.BeanName"
>
<!-- 初始化體:僅在 Bean 首次創建時執行 -->
<jsp:setProperty name="beanId" property="*" />
</jsp:useBean>
| 屬性 | 必填 | 說明 |
|---|---|---|
| id | 是 | 頁面內唯一變量名,對應 scripting variable (如 beanId.property)。區分大小寫。 |
| scope | 否 (默認 page) | 生命週期範圍:page 僅當前頁請求有效 (含 include/forward)request 請求範圍 (forward 共享)session 用戶會話範圍application 全局應用範圍 (ServletContext) |
| class | 二選一 | 具體實現類全限定名,需有公共無參構造器。容器調用 new ClassName() 實例化。 |
| type | 二選一 | 聲明類型 (接口/父類)。若單獨使用 type,Bean 必須已存在於指定 scope 中 (不創建新實例)。 |
| beanName | 二選一 | 配合 type 使用。通過 java.beans.Beans.instantiate() 實例化,支持序列化 Bean (.ser 文件) 或類名。 |
scope 中查找 id 同名對象。class/beanName 實例化 → 存入 scope → 執行 body 體 (通常放 setProperty 初始化)。<!-- 情況 1:class + type (類型寬化) -->
<jsp:useBean id="dao" class="com.impl.UserDaoImpl" type="com.dao.UserDao" scope="request" />
<%-- 頁面中 dao 變量類型為 UserDao 接口,實際對象為 UserDaoImpl --%>
<!-- 情況 2:僅 type (依賴現有對象) -->
<jsp:useBean id="user" type="com.model.User" scope="session" />
<%-- 須確保 session 中已有 "user" 屬性且為 User 實例,否則拋 InstantiationException --%>
<!-- 1. 自動匹配:請求參數名 = Bean 屬性名,自動調用 setter -->
<jsp:setProperty name="beanId" property="*" />
<!-- 2. 指定屬性自動匹配參數 -->
<jsp:setProperty name="beanId" property="username" />
<!-- 3. 參數名與屬性名不同 -->
<jsp:setProperty name="beanId" property="userName" param="username" />
<!-- 4. 直接指定固定值 -->
<jsp:setProperty name="beanId" property="status" value="active" />
request.getParameterNames(),對每個參數名 p,若 Bean 有 setP(Type),則調用 bean.setP(request.getParameter(p))。類型轉換自動處理 (String -> 基本類型/String/Date 等,遵循 JavaBeans 規範 PropertyEditor)。<%= expr %> (JSP 1.x) / ${expr} (JSP 2.0 EL)。param 與 value 不能同時使用。<jsp:getProperty name="beanId" property="propertyName" />
name 對象。getPropertyName()。toString(),基本類型轉包裝類再 toString)。out 對象 (相當於 out.print(value))。前置條件:Bean 必須已在之前的 useBean 或其他方式放入作用域中。
package com.example.model;
public class UserBean implements java.io.Serializable {
private String username;
private String password;
private String email;
private int age;
private java.util.Date regDate = new java.util.Date(); // 默認值
// 標準 Getter/Setter (省略)...
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
// ... 其他屬性同理
}
<%@ page contentType="text/html;charset=UTF-8" %>
<html><body>
<h2>用戶註冊處理</h2>
<!-- 1. 聲明 Bean,請求範圍,自動創建 -->
<jsp:useBean id="user" class="com.example.model.UserBean" scope="request">
<!-- 2. 自動將所有請求參數注入 Bean (username, password, email, age) -->
<jsp:setProperty name="user" property="*" />
</jsp:useBean>
<!-- 3. 顯式設置默認/固定值 (註冊時間由 Bean 構造器默認,此處演示 value 用法) -->
<jsp:setProperty name="user" property="status" value="pending" />
<h3>註冊信息確認</h3>
<table border="1">
<tr><th>字段</th><th>值</th></tr>
<tr><td>用戶名</td><td><jsp:getProperty name="user" property="username" /></td></tr>
<tr><td>郵箱</td><td><jsp:getProperty name="user" property="email" /></td></tr>
<tr><td>年齡</td><td><jsp:getProperty name="user" property="age" /></td></tr>
<tr><td>註冊時間</td><td><jsp:getProperty name="user" property="regDate" /></td></tr>
<tr><td>狀態</td><td><jsp:getProperty name="user" property="status" /></td></tr>
</table>
<%-- 後續可將 user 對象傳遞給 Service/DAO 持久化 --%>
</body></html>
<form action="register.jsp" method="post">
用戶名: <input name="username" /><br/>
密碼: <input type="password" name="password" /><br/>
郵箱: <input name="email" /><br/>
年齡: <input name="age" /><br/>
<input type="submit" value="註冊" />
</form>
| 主題 | 關鍵點 |
|---|---|
| 作用域選擇 | page 默認,僅頁面內;request 配合 <jsp:forward> 傳遞數據;session 用戶登錄狀態、購物車;application 全局配置、緩存數據。 |
| 類型轉換與 PropertyEditor | 標準轉換:String -> 基本類型、String、Date (格式需匹配)。自定義類型需註冊 PropertyEditor (罕用)。 |
| 只讀屬性/無 Setter | setProperty 會跳過無 Setter 的屬性 (不報錯)。getProperty 要求有 Getter。 |
| EL 表達式替代 (JSP 2.0+) | 現代首選:${user.username} 替代 <jsp:getProperty>;<c:set target="${user}" property="status" value="active"/> 替代 setProperty。更簡潔、支持巢狀屬性、空值安全。 |
| 線程安全 | scope="request/page" 每請求一實例,線程安全。session/application 共享實例,Bean **必須線程安全** (無可變狀態或同步)。 |
useBean/setProperty/getProperty 三劍合璧,構成了 JSP 早期「Model 1」架構的核心,實現了請求參數到 JavaBean 的自動綁定與頁面輸出。雖然現代開發推薦使用 EL + JSTL + MVC 框架,但理解這三個標簽的**作用域語義、自動類型轉換、生命週期管理**,對維護老項目、排查 Bean 未生效/屬性未注入/ClassCastException 等問題,仍具不可替代的價值。