Tapestry 將 HTML 頁面作為模板,與 Java 組件類、部署描述符緊密綁定。缺乏整體規劃直接編碼,極易陷入「模板與類不同步、導航斷鏈、業務邏輯滲透視圖層」的泥潭。本文梳理一套「三步走」規劃法與組件開發標準流程。
拒絕「先選技術、後找需求」。核心問題:應用程序要解決什麼業務問題? 只有明確核心目的,Tapestry 組件才能圍繞「與數據源交互」與「向模板提供數據」兩大職責精準設計。
以虛構的 BurgerDome 廚房系統為例:
// Tapestry 組件:負責頁面交互,調用業務對象
public abstract class Order extends BasePage {
private Order order; // 業務對象,非 Tapestry 類
public void placeOrder(int burgerType, int doneness) {
Burger burger = new Burger(burgerType, doneness); // 業務邏輯
Order order = new Order();
order.addBurger(burger);
setOrder(order);
OrderQueue.getInstance().add(order); // 業務隊列
}
}
原則:Tapestry 類僅作膠水,業務邏輯零滲透。
用紙筆或流程圖工具畫出所有頁面與跳轉關係。提前發現:
規劃不是一次性凍結,而是基線+增量調整。預留變更空間,應對需求漂移與技術發現。
清單 2 展示一個無 CSS、無 JS、僅語義化標籤的銷售報表原型。優勢:
拒絕 "foo"、"99.95" 等佔位符。根據需求文檔確定:
Tapestry 獨特優勢:原型即模板,無需像 JSP/Servlet 那樣重寫,直接在原型上疊加 Tapestry 標記即可進入開發。
嚴禁在組件中寫業務邏輯。所有 Service、DAO、Domain Model 應獨立打包、單元測試通過,組件僅調用。
package com.burgerdome.display;
import org.apache.tapestry.annotations.*;
import org.apache.tapestry.html.BasePage;
public abstract class Status extends BasePage {
// 持久屬性:跨請求保留(存於 Session,非數據庫)
@Persist
public abstract int getOrderNumber();
public abstract void setOrderNumber(int orderNumber);
// 非持久業務對象:每次請求重新查詢,避免臟讀
public abstract Order getOrder();
public abstract void setOrder(Order order);
// 動作方法:響應頁面事件
public void getStatus() {
OrderQueue queue = OrderQueue.getInstance();
Order order = queue.getOrder(getOrderNumber());
setOrder(order); // 更新模板綁定對象
}
}
要點:
Status.html ↔ Status.java)BasePage,類聲明 abstract 讓 Tapestry 生成實現@Persist 僅用於用戶輸入類不變數據(如訂單號),業務對象勿標註導航鏈接轉換:
<!-- 原始 --> <a href="Home.html">返回</a>
<!-- Tapestry --> <a page="Home" jwcid="@PageLink" href="#">返回</a>
動態數據注入:
<span jwcid="@Insert" value="ognl:totalSales" id="total-sold">1012</span>
jwcid="@Insert":標記插入點value="ognl:totalSales":OGNL 表達式綁定頁面屬性 getTotalSales()id、樣式、佔位文本,設計師可繼續在瀏覽器預覽WEB-INF/app.application:
<application>
<meta key="org.apache.tapestry.page-class-packages" value="com.burgerdome.display"/>
</application>
WEB-INF/web.xml:
<servlet>
<servlet-name>app</servlet-name>
<servlet-class>org.apache.tapestry.ApplicationServlet</servlet-class>
<load-on-startup>0</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>app</servlet-name>
<url-pattern>/app</url-pattern>
</servlet-mapping>
Tapestry 開發的核心節奏:規劃 → 原型 → 綁定 → 配置。嚴守「業務邏輯不入組件、原型即模板、導航預先圖譜」三大鐵律,配合標準化頁面類模板與 OGNL 綁定,即可實現極低樣板代碼、極高設計師協作友好度的組件化 Web 開發。這套流程思維同樣適用於現代 Wicket、Vaadin 乃至前端組件化框架(React/Vue)的工程化實踐。