首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Struts 1 DispatchAction 詳解:單類多方法分發機制、配置與源碼流程分析

     編輯:Java 相關知識

痛點:Action 類爆炸

傳統 Action 一個業務操作一個類(UserAddAction、UserDelAction、UserModifyAction...),導致類數量膨脹、維護困難。DispatchAction 允許將相關操作合併到一個類,根據請求參數分發到不同方法。

完整實戰示例

Action 類

public class UserAction extends DispatchAction {
  // 無參數時的默認入口
  @Override
  protected ActionForward unspecified(ActionMapping mapping, ActionForm form,
                                      HttpServletRequest request, HttpServletResponse response) throws Exception {
    List userList = UserManager.getInstance().findAllUserList();
    request.setAttribute("userlist", userList);
    return mapping.findForward("list_success");
  }

  public ActionForward del(ActionMapping mapping, ActionForm form,
                           HttpServletRequest request, HttpServletResponse response) throws Exception {
    UserActionForm uaf = (UserActionForm) form;
    String[] userIdList = uaf.getSelectFlag();
    UserManager.getInstance().deleteUsers(userIdList);
    return mapping.findForward("del_success");
  }

  public ActionForward add(ActionMapping mapping, ActionForm form,
                           HttpServletRequest request, HttpServletResponse response) throws Exception {
    UserActionForm uaf = (UserActionForm) form;
    User user = new User();
    BeanUtils.copyProperties(user, uaf);
    user.setCreateDate(new Date());
    UserManager.getInstance().addUser(user);
    return mapping.findForward("add_success");
  }

  public ActionForward modify(ActionMapping mapping, ActionForm form,
                              HttpServletRequest request, HttpServletResponse response) throws Exception {
    UserActionForm uaf = (UserActionForm) form;
    User user = new User();
    BeanUtils.copyProperties(user, uaf);
    UserManager.getInstance().modifyUser(user);
    return mapping.findForward("modify_success");
  }

  public ActionForward find(ActionMapping mapping, ActionForm form,
                            HttpServletRequest request, HttpServletResponse response) throws Exception {
    UserActionForm uaf = (UserActionForm) form;
    String userId = uaf.getUserId();
    User user = UserManager.getInstance().findUserById(userId);
    request.setAttribute("user", user);
    return mapping.findForward("find_success");
  }
}

ActionForm(多表單共用)

public class UserActionForm extends ActionForm {
  private String userId, userName, password, contactTel, email;
  private Date createDate;
  private String[] selectFlag;  // 批量刪除勾選框
  // getter/setter 省略
}

struts-config.xml 關鍵配置

<form-beans>
  <form-bean name="userForm" type="com.tgb.drp.web.forms.UserActionForm"/>
</form-beans>

<action-mappings>
  <action path="/user/user_maint"
          type="com.tgb.drp.web.actions.UserAction"
          name="userForm"
          scope="request"
          parameter="command">  <!-- 關鍵:指定分發參數名 -->
    <forward name="list_success" path="/user/user_list.jsp"/>
    <forward name="del_success" path="/user/user_maint.do" redirect="true"/>
    <forward name="add_success" path="/user/user_maint.do" redirect="true"/>
    <forward name="modify_success" path="/user/user_maint.do" redirect="true"/>
    <forward name="find_success" path="/user/user_modify.jsp"/>
  </action>
  
  <action path="/user/show_add" forward="/user/user_input.jsp"/>
</action-mappings>

頁面調用方式

<a href="user/user_maint.do?command=add">新增用戶</a>
<a href="user/user_maint.do?command=del">刪除用戶</a>
<form action="user/user_maint.do" method="post">
  <input type="hidden" name="command" value="modify"/>
  ...
</form>

根據 command 參數值(add/del/modify/find)自動調用同名方法。

源碼流程分析

DispatchAction 執行流程

核心方法:execute → dispatchMethod

// DispatchAction.execute()
public ActionForward execute(ActionMapping mapping, ActionForm form,
                             HttpServletRequest request, HttpServletResponse response) throws Exception {
  String parameter = mapping.getParameter();  // 獲取 "command"
  if (parameter == null) {
    return unspecified(mapping, form, request, response);
  }
  // 防止遞歸調用 execute/perform
  if ("execute".equals(parameter) || "perform".equals(parameter)) {
    throw new ServletException("DispatchAction parameter cannot be 'execute' or 'perform'");
  }
  return dispatchMethod(mapping, form, request, response, parameter);
}

// DispatchAction.dispatchMethod()
protected ActionForward dispatchMethod(ActionMapping mapping, ActionForm form,
                                       HttpServletRequest request, HttpServletResponse response,
                                       String parameter) throws Exception {
  String name = request.getParameter(parameter);  // 獲取 command 值
  if (name == null) {
    return unspecified(mapping, form, request, response);
  }
  // 反射調用同名方法
  Method method = getMethod(name);
  return (ActionForward) method.invoke(this, mapping, form, request, response);
}

關鍵規則

  1. parameter 屬性不能為 "execute" 或 "perform",否則拋異常防遞歸。
  2. 請求參數值為空 → 調用 unspecified()(可覆寫作為默認入口)。
  3. 方法簽名必須與 execute 完全一致:(ActionMapping, ActionForm, HttpServletRequest, HttpServletResponse)。
  4. 方法必須為 public,返回 ActionForward,拋出 Exception。

優缺點權衡

優點缺點
大幅減少 Action 類數量單類職責過重,違反單一職責原則
相關邏輯聚合,便於協調耦合度升高,修改一個方法可能影響其他
配置簡潔,減少 struts-config 體積擴展性降低,新增操作需修改同一類
共享 ActionForm,減少表單類團隊並行開發衝突概率增加

進階變體

  • LookupDispatchAction:getKeyMethodMap() 返回鍵值對映射,支持國際化(按鍵值而非方法名分發)。
  • MappingDispatchAction:根據 ActionMapping 的 parameter 屬性值直接分發,無需請求參數。

最佳實踐建議

  1. 僅用於高內聚的 CRUD 操作集(如用戶/訂單/產品的增刪改查)。
  2. 業務邏輯下沉到 Service/Manager 層,Action 僅做參數綁定、調用、結果導航。
  3. 複雜/獨立業務流程仍用獨立 Action 類,避免上帝類。
  4. 考慮遷移至 Struts 2 / Spring MVC:註解驅動、攔截器、REST 支持更現代化。

總結

DispatchAction 是 Struts 1 時代解決「Action 類爆炸」的經典模式,通過 parameter 指定分發參數、反射調用同名方法,實現單類多入口。理解其源碼流程(execute → dispatchMethod → 反射調用)與配置約束,有助於在維護老項目時快速定位問題。但隨著項目規模增長,其耦合副作用會顯現,適時重構為細粒度 Action 或遷移現代框架才是長久之計。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved