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

Struts 擴展機制深度解析:PlugIn、RequestProcessor、ActionServlet 三大擴展點實戰

     編輯:Java 相關知識

許多團隊因不知 Struts 具備強大擴展機制,而自行開發 MVC 框架。本文深度解析 Struts 三大核心擴展點——PlugIn (啟動/關閉)、RequestProcessor (請求處理流程)、ActionServlet (核心控制器)——並以 Hibernate 整合、權限攔截、動態 Content-Type 為實戰案例,展示如何在框架內優雅滿足業務需求。

Struts 三大擴展點架構定位

擴展點觸發時機適用場景優先順序
PlugIn應用啟動/關閉框架初始化 (Hibernate、Log4j、資源載入)、清理資源最高 (首選)
RequestProcessor每次請求處理流程中權限檢查、編碼設定、動態 Content-Type、自定義 Forward 邏輯次之
ActionServlet啟動/關閉 + 每次請求前兩者無法滿足的極端需求 (如自定義模組載入邏輯)最低 (最後手段)

擴展點一:PlugIn — 生命週期管理

介面契約


public interface PlugIn {
    void init(ActionServlet actionServlet, ModuleConfig config) throws ServletException;
    void destroy();
}

實戰案例:Hibernate PlugIn


public class HibernatePlugIn implements PlugIn {
    private String configFile; // 透過 Setter 注入
    
    public void init(ActionServlet servlet, ModuleConfig config) throws ServletException {
        System.out.println("Initializing Hibernate with config: " + configFile);
        // 實際邏輯:建立 SessionFactory、註冊至 JNDI/ApplicationContext
        // Configuration cfg = new Configuration().configure(configFile);
        // SessionFactory sf = cfg.buildSessionFactory();
        // servlet.getServletContext().setAttribute("HibernateSessionFactory", sf);
    }
    
    public void destroy() {
        System.out.println("Shutting down Hibernate SessionFactory");
        // 關閉 SessionFactory、釋放連線池
    }
    
    // Getter/Setter 供 struts-config.xml 注入
    public String getConfigFile() { return configFile; }
    public void setConfigFile(String configFile) { this.configFile = configFile; }
}

struts-config.xml 宣告


<struts-config>
    <!-- 其他配置 -->
    <plug-in className="com.app.util.HibernatePlugIn">
        <set-property property="configFile" value="/hibernate.cfg.xml" />
    </plug-in>
</struts-config>

PlugIn 進階能力

  • 配置驗證:`init()` 中檢查必要配置檔存在性,缺失拋出 `ServletException` 讓 ActionServlet 標記不可用
  • 修改 ModuleConfig:`init()` 是修改 `ModuleConfig` (靜態配置集合) 的最後機會,Struts 會在所有 PlugIn 處理完後凍結它

擴展點二:RequestProcessor — 請求處理管道定制

預設處理流程 (Template Method 模式)


public void process(HttpServletRequest req, HttpServletResponse res) {
    request = processMultipart(request);           // 1. 檔案上傳包裝
    path = processPath(request, response);         // 2. 解析路徑
    processLocale(request, response);              // 3. Locale 解析
    processContent(request, response);             // 4. Content-Type 設定
    processNoCache(request, response);             // 5. 快取控制
    if (!processPreprocess(request, response)) return; // 6. 前置處理 Hook
    mapping = processMapping(request, response, path); // 7. 尋找 ActionMapping
    if (!processRoles(request, response, mapping)) return; // 8. 角色授權
    form = processActionForm(request, response, mapping);  // 9. FormBean 管理
    processPopulate(request, response, form, mapping);     // 10. 表單資料填充
    if (!processValidate(request, response, form, mapping)) return; // 11. 驗證
    if (!processForward(request, response, mapping)) return; // 12. Forward 導向
    if (!processInclude(request, response, mapping)) return; // 13. Include 包含
    action = processActionCreate(request, response, mapping); // 14. Action 實例化
    forward = processActionPerform(request, response, action, form, mapping); // 15. 執行業務
    processForwardConfig(request, response, forward); // 16. 處理返回 Forward
}

實戰案例:自定義 RequestProcessor

需求:

  1. 全域登入攔截:檢查 Session `userName` 屬性,未登入導向登入頁
  2. 動態 Content-Type:`/contactimage.do` 回傳 `image/gif`,其他 `text/html`

public class CustomRequestProcessor extends RequestProcessor {
    
    // 覆寫前置處理 Hook:登入攔截
    @Override
    protected boolean processPreprocess(HttpServletRequest req, HttpServletResponse res) {
        // 登入頁面自身放行
        String path = req.getServletPath();
        if ("/loginInput.do".equals(path) || "/login.do".equals(path)) {
            return true;
        }
        
        HttpSession session = req.getSession(false);
        if (session != null && session.getAttribute("userName") != null) {
            return true; // 已登入
        }
        
        // 未登入:導向登入頁並短路流程
        try {
            req.getRequestDispatcher("/Login.jsp").forward(req, res);
        } catch (Exception e) {
            // log error
        }
        return false; // 關鍵:返回 false 終止後續處理
    }
    
    // 覆寫 Content-Type 設定:動態圖片回應
    @Override
    protected void processContent(HttpServletRequest req, HttpServletResponse res) {
        if ("/contactimage.do".equals(req.getServletPath())) {
            res.setContentType("image/gif");
            return;
        }
        super.processContent(req, res); // 其他路徑走預設邏輯
    }
}

struts-config.xml 啟用


<controller>
    <set-property property="processorClass" value="com.app.util.CustomRequestProcessor" />
</controller>

設計建議

  • 少數 Action 需特殊 Content-Type → 覆寫 `processContent()` 可行
  • 大量非 HTML 回應 → 建立子應用 (Sub-application) 獨立配置 `processorClass`
  • Tiles 框架即透過自定義 `TilesRequestProcessor` 裝飾輸出

擴展點三:ActionServlet — 核心控制器完全接管

web.xml 原始宣告


<servlet>
    <servlet-name>action</servlet-name>
    <servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    <init-param><param-name>config</param-name><param-value>/WEB-INF/struts-config.xml</param-value></init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

擴展策略


public class CustomActionServlet extends ActionServlet {
    @Override
    public void init() throws ServletException {
        super.init(); // 必須呼叫父類初始化
        // 自定義啟動邏輯:載入自定義模組、註冊 MBean...
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse res) 
            throws ServletException, IOException {
        // 自定義請求預處理...
        super.doPost(req, res); // 委派父類處理
    }
    
    @Override
    public void destroy() {
        // 自定義關閉邏輯...
        super.destroy();
    }
}

web.xml 切換


<servlet-class>com.app.CustomActionServlet</servlet-class>

歷史演進

  • Struts 1.0:Tiles 基於 ActionServlet 裝飾回應
  • Struts 1.1+:Tiles 遷移至 `TilesRequestProcessor`,ActionServlet 擴展需求大幅減少

擴展決策流程圖

業務需求
    │
    ├─ 應用啟動/關閉初始化資源? → 是 → PlugIn
    │
    ├─ 請求處理流程中特定邏輯? → 是 → RequestProcessor (覆寫具體 processXxx 方法)
    │       │
    │       ├─ 權限/登入攔截 → processPreprocess
    │       ├─ 編碼/Content-Type → processContent/processNoCache
    │       ├─ ActionMapping 查找邏輯 → processMapping
    │       ├─ FormBean 管理 → processActionForm/processPopulate/processValidate
    │       └─ Forward/Include 邏輯 → processForward/processInclude
    │
    └─ 以上皆無法滿足? → ActionServlet (極少見)

經典擴展框架參考

  • Validator 框架:`ValidatorPlugIn` 初始化驗證規則、`RequestProcessor` 整合驗證流程
  • Tiles 框架:`TilesPlugIn` 載入定義、`TilesRequestProcessor` 裝飾輸出合成
  • Spring 整合:`ContextLoaderPlugIn` (Struts 1.1+) 或 `DelegatingActionProxy`

總結

Struts 擴展機制遵循「配置優於繼承、專用優於通用」原則:

  1. 優先用 PlugIn 處理生命週期資源管理
  2. 請求流程定制用 RequestProcessor,精準覆寫單一 `processXxx` 方法
  3. ActionServlet 為最終手段,慎用

掌握三大擴展點,配合 `struts-config.xml` 宣告式配置,即可在不修改框架核心代碼前提下,滿足 95% 以上的企業級定制需求。這正是 Struts 作為成熟框架的架構韌性所在。

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