| 維度 | Struts (Action-based MVC) | JSF (Component-based Event-driven) |
|---|---|---|
| 事件模型 | Application Event:整個表單提交對應一個 Action,粗粒度 | Component Event:每個組件 (輸入框、按鈕) 獨立觸發 ValueChange/Action 事件,細粒度 |
| 編程風格 | Web 化:Command 模式 + Action.execute(),類 PHP/Perl 表單處理習慣 | 語言化/桌面化:Observer 模式 + Listener,類 Swing/AWT 事件驅動習慣 |
| 表單綁定 | ActionForm 對應整個表單,字段級驗證/事件處理需靠 JavaScript 繞道 | UIComponent 樹 + Managed Bean 屬性綁定 (#{bean.prop}),原生支援字段級事件 |
| 導航控制 | struts-config.xml 全局定義 Action → Forward 映射 | faces-config.xml 定義 Navigation Rule:from-view-id → outcome → to-view-id,邏輯更清晰 |
<!-- 字段級值變更事件 -->
<h:inputText id="userId" value="#{login.userId}">
<f:valueChangeListener type="logindemo.UserLoginChanged" />
</h:inputText>
<!-- 按鈕動作事件 -->
<h:commandButton id="login" value="Login">
<f:actionListener type="logindemo.LoginActionListener" />
</h:commandButton>
UserLoginChanged.processValueChanged(ValueChangeEvent) 可在用戶修改單個字段時即時觸發業務邏輯 (如即時驗證、聯動查詢),無需提交整個表單。
<managed-bean>
<managed-bean-name>user</managed-bean-name>
<managed-bean-class>com.corejsf.UserBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<!-- Setter 注入初始值 -->
<managed-property>
<property-name>name</property-name>
<value>me</value>
</managed-property>
<managed-property>
<property-name>password</property-name>
<value>secret</value>
</managed-property>
</managed-bean>
#{sessionScope.visit} 等作用域鏈接<navigation-rule>
<from-view-id>/index.jsp</from-view-id>
<navigation-case>
<from-outcome>login</from-outcome> <!-- 對應 commandButton action="login" -->
<to-view-id>/welcome.jsp</to-view-id>
</navigation-case>
</navigation-rule>
事件結果 (outcome) 與頁面跳轉解耦,支持動態導航決策。
兩者 web.xml 配置幾乎相同:核心 Servlet (FacesServlet/ActionServlet) + URL 映射 (*.faces/*.do) + 配置文件 (faces-config.xml/struts-config.xml)。JSF 額外需 JSTL 標簽庫與 Apache Commons 依賴。
<!-- Struts: 大量 logic 標簽導致 JSP 混亂 -->
<logic:present name="auth" property="inboxAuthorized">
<html:link action="inbox"><img src="/images/inbox.gif"/>InBox</html:link>
</logic:present>
<!-- JSF: 聲明式渲染控制,極簡優雅 -->
<jia:navigatorItem name="inbox" label="InBox"
icon="/images/inbox.gif" action="inbox"
disabled="#{!authenticationBean.inboxAuthorized}"/>
JSF 組件模型將渲染邏輯、狀態管理、事件綁定封裝在組件內部,JSP 僅作為模板,業務邏輯零滲透。
| 場景 | 推薦框架 | 理由 |
|---|---|---|
| 團隊習慣 Web 表單思維、項目簡單、需快速交付 | Struts 2 / Spring MVC | 學習曲線平、生態成熟、Action 粒度適合傳統 CRUD |
| 富交互頁面、字段級即時驗證/聯動、組件復用需求高 | JSF (PrimeFaces/OmniFaces) / Vaadin | 組件模型原生支援細粒度事件、狀態保持、組件庫豐富 |
| 現代化單頁應用 (SPA) | React/Vue/Angular + REST API | 前後端分離,JSF/Struts 服務端渲染模式已非主流 |
JSF 代表了 Java EE 將桌面開發體驗 (Swing 模式) 引入 Web 的嘗試,雖未成主流,但其組件模型、事件驅動、聲明式配置、IoC 整合思想深刻影響了後續框架 (Spring Web Flow、Wicket、Tapestry、甚至現代前端組件化思想)。理解 JSF,是理解「組件化 Web 框架」演進史的關鍵一環。