圍繞 JSF (JavaServer Faces) 的恐懼、不確定與懷疑 (FUD) 由來已久。本文針對三大主流迷思——「必須用視覺化工具」、「不支援 Model 2」、「開發太難」——逐一拆解,並通過結構概述與計算機範例實戰,展現 JSF 基於組件、事件驅動的 MVC 架構如何簡化 Web 開發。
事實:正如 Swing 開發者多手寫代碼,JSF 同樣不需視覺化工具。純手寫 JSF 代碼比 Struts/WebWork 等傳統 Model 2 框架更簡潔、直觀。工具僅為加速,非必需。
事實:Model 2 是建立在無狀態 HTTP 上的 MVC 簡化版。JSF 提供更豐富、更接近傳統 GUI 應用的完整 MVC 模型:組件維護狀態、事件驅動、驗證/轉換內建。雖框架實現較複雜,但開發者享受「高收益、低投入」。
事實:規範文檔面向工具廠商,包含大量生命週期圖表,嚇退初學者。但 JSF 設計初衷正是「對應用開發者極易用」。其組件模型早存在於 ASP.NET、WebObjects、Tapestry 等技術中,學習曲線實則平緩。
action="#{bean.method}" 一行搞定。JSF 視圖由 JSP 頁面承載,但不內在地綁定 JSP。JSP 標籤僅引用組件樹,首次渲染後組件狀態保留於伺服器。修改 JSP 屬性不會自動更新組件狀態(需控制器代碼修改組件屬性再重渲染)。典型 JSF 應用幾乎無 Java 代碼混入 JSP,極少 JSTL EL。

圖 1 從 MVC 角度看範例應用
Calculator),封裝業務邏輯。viewRoot (UIComponent 樹) + JSP 頁面。組件樹維護狀態,JSP 綁定屬性與事件。CalculatorController) 扮演調停者,轉發請求至 Model,處理導航結果。業務邏輯不應置於 Backing Bean,可委派 Service/DAO。三個頁面:index.jsp (重導向) → calculator.jsp (輸入兩數、驗證、操作) → results.jsp (顯示結果)。一個 Session Scope Backing Bean CalculatorController 支撐兩頁。
<!-- web.xml -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/calc/*</url-pattern>
</servlet-mapping>
<!-- faces-config.xml -->
<managed-bean>
<managed-bean-name>CalcBean</managed-bean-name>
<managed-bean-class>com.arcmind.jsfquickstart.controller.CalculatorController</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/calculator.jsp</from-view-id>
<navigation-case>
<from-outcome>success</from-outcome>
<to-view-id>/results.jsp</to-view-id>
</navigation-case>
</navigation-rule>
public class CalculatorController {
private Calculator calculator = new Calculator();
private int firstNumber, secondNumber, result;
// Getter/Setter 略...
public String add() {
result = calculator.add(firstNumber, secondNumber);
return "success"; // 導航至 results.jsp
}
public String multiply() {
result = calculator.multiply(firstNumber, secondNumber);
return "success";
}
}
<%@ taglib uri="https://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="https://java.sun.com/jsf/core" prefix="f" %>
<f:view>
<h:form id="calcForm">
<h:panelGrid columns="3">
<h:outputLabel value="First Number" for="firstNumber"/>
<h:inputText id="firstNumber" value="#{CalcBean.firstNumber}" required="true"/>
<h:message for="firstNumber"/>
<h:outputLabel value="Second Number" for="secondNumber"/>
<h:inputText id="secondNumber" value="#{CalcBean.secondNumber}" required="true"/>
<h:message for="secondNumber"/>
</h:panelGrid>
<h:panelGroup>
<h:commandButton id="submitAdd" action="#{CalcBean.add}" value="Add"/>
<h:commandButton id="submitMultiply" action="#{CalcBean.multiply}" value="Multiply"/>
</h:panelGroup>
</h:form>
</f:view>

圖 4 驗證和數據轉換錯誤
只需 required="true" + 綁定 int 屬性,JSF 自動完成:空值驗證、字串轉整數、失敗則回顯錯誤訊息於 <h:message>,零代碼量。
同樣功能,Struts 至少雙倍代碼量:兩個 Action 類、多個 ActionMapping、Validator 設定、DynaValidatorForm、全域/局部轉向。JSF 以聲明式導航、內建驗證/轉換、組件狀態管理,大幅降低樣板代碼。學習曲線上,JSF 更直觀、邏輯性更強;Struts 係演化而來,較程序化。JSF 開發生產力顯著高於 Struts。
下一篇將深入 JSF 請求處理生命週期五階段、即時事件處理、內建組件與 JavaScript 整合。