Model 是處理用戶請求、執行業務邏輯、保存處理結果的核心層。在 Struts 架構中,Model 具體表現為:
典型對應關係:一個請求頁面 ↔ 一個 Model 組件(ActionForm + Action),但也支援一個 Model 對應多個頁面請求。若 struts-config.xml 未指定 Action,控制器直接將封裝好資料的 ActionForm 轉向視圖。
Web 應用中 JavaBean 透過「作用域」定義生命週期與可見範圍:
| 作用域 | 生命週期 | 可見範圍 | Servlet API 對應 |
|---|---|---|---|
| page | 單一 JSP 請求期間 | 當前 JSP 頁面 | service 方法區域變數 |
| request | 單一 HTTP 請求期間 | 當前請求(含 forward/include) | Request 屬性 |
| session | 用戶會話期間 | 同一用戶所有請求 | Session 屬性 |
| application | Web 應用生命週期 | 所有用戶、所有請求 | ServletContext 屬性 |
// Servlet 中儲存
MyBean bean = new MyBean(...);
request.setAttribute("beanKey", bean);
// JSP 中取用
<jsp:useBean id="bean" scope="request" class="com.example.MyBean" />
在 struts-config.xml 定義 Form Bean 後,Controller Servlet 自動執行:
execute() 方法public class MyForm extends ActionForm {
// 屬性 getter/setter...
// 1. 驗證方法:回傳 ActionErrors,非 null/非空則轉向 input 頁面
public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
ActionErrors errors = new ActionErrors();
if (getUsername() == null || getUsername().trim().isEmpty()) {
errors.add("username", new ActionMessage("error.username.required"));
}
return errors;
}
// 2. 重置方法:將屬性恢復預設值
public void reset(ActionMapping mapping, HttpServletRequest request) {
setUsername(null);
setAge(0);
}
}
<action> 元素 validate="true" 時觸發 validate()input 指定頁面execute() 方法(舊版為 perform())// 通用請求
public ActionForward execute(ActionMapping mapping, ActionForm form,
ServletRequest request, ServletResponse response)
throws IOException, ServletException;
// HTTP 專用(常用)
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException;
Action 實例被多執行緒共享,嚴禁使用實例/靜態變數儲存請求相關狀態。
| 錯誤做法 | 正確做法 |
|---|---|
| private String userName; // 實例變數 | 從 request/ActionForm 取得資料 |
| static int counter; // 靜態變數 | 使用 ThreadLocal 或請求屬性 |
| 非同步存取共享資源 | 同步區塊保護共享資源存取 |
getLocale(request) / setLocale(request, locale):國際化支援getResources():取得訊息資源isCancelled(request):檢測用戶點擊「取消」saveErrors(request, errors):儲存錯誤訊息供視圖顯示代表應用當前狀態的資料容器:
小型系統可全記憶體驻留;大型系統對應資料庫實體,常用 Entity EJB 或 JPA 實體類別。
public class OrderAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) {
// 1. 從 ActionForm 取得資料
OrderForm orderForm = (OrderForm) form;
// 2. 轉換為商業邏輯層參數
OrderDTO dto = new OrderDTO();
dto.setUserId(orderForm.getUserId());
dto.setItems(orderForm.getItems());
// 3. 呼叫商業邏輯 Bean
OrderService service = ServiceLocator.getOrderService();
OrderResult result = service.placeOrder(dto);
// 4. 處理結果、設定導向
if (result.isSuccess()) {
request.setAttribute("orderId", result.getOrderId());
return mapping.findForward("success");
} else {
saveErrors(request, result.getErrors());
return mapping.findForward("failure");
}
}
}
| 分類 | 代表類別 | 職責 | 典型技術 |
|---|---|---|---|
| ActionForm Bean | extends ActionForm | 表單資料封裝、簡單驗證 | Struts 原生 |
| 系統狀態 Bean | POJO / Entity Bean | 業務資料持久化狀態 | JPA / Hibernate / EJB |
| 商業邏輯 Bean | POJO / Session Bean | 核心業務規則、工作流程 | Spring Bean / EJB |
| Action Bean | extends Action | 請求協控、視圖導向 | Struts 原生 |
Struts Model 層設計核心在於「分層解耦」:ActionForm 處理表現層資料綁定,Action 處理流程控制,商業邏輯 Bean 專注領域邏輯。嚴守執行緒安全、環境無關性、單一職責原則,才能構建可維護、可測試、可擴充的企業級應用。