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

Struts 實現 MVC 架構完整指南:從理論到實戰的 Web 應用開發

     編輯:Java 程式設計入門

前言:為什麼需要 MVC?

早期 Servlet 時代,開發者在 out.println() 中拼接 HTML,業務邏輯與視圖渲染強耦合,維護極度困難。JSP 雖分離了表現,但大量 Scriptlet (<% %>) 導致控制流程散落在視圖中。MVC (Model-View-Controller) 模式透過職責分離解決此問題,Struts 1 是 Java Web 史上最成功的 MVC 框架之一,其設計哲學深遠影響後續框架。

MVC 核心概念

三大角色職責

角色職責Struts 對應組件技術實現
Model業務邏輯、資料存取、狀態管理JavaBean、EJB、Hibernate/JPA、Service 層POJO、DAO、Service、Domain Object
View資料呈現、用戶互動介面JSP + Struts Taglib、JSTL、ELHTML、CSS、JavaScript、模板引擎
Controller請求接收、流程控制、視圖分派ActionServlet (核心)、Action、ActionForm、ActionMappingFront Controller 模式、命令模式

請求處理流程

用戶請求 (HTTP)
    │
    ▼
ActionServlet (web.xml 配置的 Front Controller)
    │
    ├─▶ 解析請求路徑 → 查找 ActionMapping
    │
    ├─▶ 建立/取得 ActionForm → 自動填充表單資料 → 驗證 (validate)
    │
    ├─▶ 實例化 Action → 執行 execute() → 業務邏輯處理
    │
    ├─▶ Action 返回 ActionForward (success/failure/自訂)
    │
    ▼
ActionServlet 根據 Forward 轉發至目標 View (JSP/Tiles)
    │
    ▼
View 渲染回應 → 返回用戶瀏覽器

Struts 核心組件深度解析

1. ActionServlet:核心控制器

  • 在 web.xml 中配置為啟動載入 (load-on-startup)
  • 讀取 struts-config.xml 初始化 ActionMapping、FormBean、Forward、DataSource、PlugIn 等
  • 單例模式,多執行緒共享,不處理具體業務

2. ActionForm:表單資料載體

public class LoginForm extends ActionForm {
    private String username;
    private String password;
    // getter/setter 省略

    @Override
    public ActionErrors validate(ActionMapping mapping, HttpServletRequest request) {
        ActionErrors errors = new ActionErrors();
        if (username == null || username.trim().isEmpty()) {
            errors.add("username", new ActionError("error.username.required"));
        }
        if (password == null || password.length() < 6) {
            errors.add("password", new ActionError("error.password.minlength", "6"));
        }
        return errors; // 空集合或 null 表示驗證通過
    }

    @Override
    public void reset(ActionMapping mapping, HttpServletRequest request) {
        username = null;
        password = null; // 重置狀態,避免殘留資料
    }
}

關鍵點:屬性名對應表單欄位名;validate() 回傳 ActionErrors;reset() 清理 Session 範圍 Form 的殘留值。

3. Action:業務流程控制器

public class LoginAction extends Action {
    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
                                 HttpServletRequest request, HttpServletResponse response) 
            throws Exception {
        LoginForm loginForm = (LoginForm) form;
        UserService userService = ServiceLocator.getUserService(); // 取得業務服務

        try {
            User user = userService.authenticate(loginForm.getUsername(), loginForm.getPassword());
            if (user != null) {
                request.getSession().setAttribute("currentUser", user);
                return mapping.findForward("success");
            } else {
                ActionErrors errors = new ActionErrors();
                errors.add("login", new ActionError("error.login.failed"));
                saveErrors(request, errors);
                return mapping.findForward("failure");
            }
        } catch (ServiceException e) {
            log.error("登入服務異常", e);
            return mapping.findForward("systemError");
        }
    }
}

4. struts-config.xml:應用藍圖

<struts-config>
    <!-- Form Bean 定義 -->
    <form-beans>
        <form-bean name="loginForm" type="com.app.struts.LoginForm"/>
    </form-beans>

    <!-- 全域 Forward -->
    <global-forwards>
        <forward name="login" path="/login.jsp"/>
        <forward name="welcome" path="/welcome.jsp"/>
    </global-forwards>

    <!-- Action 映射 -->
    <action-mappings>
        <!-- 直接轉發到登入頁 -->
        <action path="/login" forward="/login.jsp"/>

        <!-- 處理登入提交 -->
        <action path="/doLogin"
                type="com.app.struts.LoginAction"
                name="loginForm"
                scope="request"
                validate="true"
                input="/login.jsp"> <!-- 驗證失敗返回頁面 -->
            <forward name="success" path="/welcome.do"/> <-- 轉發到另一 Action -->
            <forward name="failure" path="/login.jsp"/>
            <forward name="systemError" path="/error.jsp"/>
        </action>

        <!-- 歡迎頁 Action (可做額外邏輯) -->
        <action path="/welcome"
                forward="/welcome.jsp"
                name="loginForm"
                scope="request"/>
    </action-mappings>

    <!-- 國際化資源 -->
    <message-resources parameter="ApplicationResources"/>

    <!-- Tiles 整合 -->
    <plug-in className="org.apache.struts.tiles.TilesPlugin">
        <set-property property="definitions-config" value="/WEB-INF/tiles-defs.xml"/>
    </plug-in>
</struts-config>

完整實戰範例:用戶登入與歡迎頁

目錄結構

src/
├── com/app/struts/
│   ├── LoginForm.java
│   ├── LoginAction.java
│   └── User.java (Model)
├── ApplicationResources.properties
└── ApplicationResources_zh_TW.properties

WebContent/
├── WEB-INF/
│   ├── struts-config.xml
│   ├── web.xml
│   └── tiles-defs.xml
├── login.jsp
└── welcome.jsp

login.jsp (View)

<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html:html locale="true">
<head><title><bean:message key="login.title"/></title></head>
<body>
    <html:errors header="<div class='error'>" footer="</div>"/>
    
    <html:form action="/doLogin">
        <table>
            <tr>
                <td><bean:message key="label.username"/>:</td>
                <td><html:text property="username" size="20"/></td>
            </tr>
            <tr>
                <td><bean:message key="label.password"/>:</td>
                <td><html:password property="password" size="20"/></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <html:submit value="<bean:message key='btn.login'/>"/>
                </td>
            </tr>
        </table>
    </html:form>
</body>
</html:html>

welcome.jsp (View)

<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<html>
<body>
    <h1><bean:message key="welcome.heading"/>, 
        <bean:write name="loginForm" property="username" filter="true"/>!</h1>
    <p><bean:message key="welcome.desc"/></p>
</body>
</html>

ApplicationResources.properties

login.title=系統登入
label.username=用戶名
label.password=密碼
btn.login=登入
error.username.required=請輸入用戶名
error.password.minlength=密碼長度至少 {0} 字元
error.login.failed=用戶名或密碼錯誤
welcome.heading=歡迎
welcome.desc=您已成功登入系統

進階主題

Tiles 版面佈局整合

參考 Struts Taglib 指南 的 Tiles 章節,實現 Header/Menu/Body/Footer 重用佈局,ActionForward 指向 Tiles 定義名而非具體 JSP。

Validator 框架:聲明式驗證

<!-- validator-rules.xml 內建規則 -->
<form-validation>
    <formset>
        <form name="loginForm">
            <field property="username" depends="required">
                <msg name="required" key="error.username.required"/>
            </field>
            <field property="password" depends="required,minlength">
                <msg name="minlength" key="error.password.minlength"/>
                <arg0 key="label.password"/>
                <var><var-name>minlength</var-name><var-value>6</var-value></var>
            </field>
        </form>
    </formset>
</form-validation>

ActionForm 繼承 ValidatorForm,struts-config.xml 配置 ValidatorPlugIn,即可移除 Java 驗證代碼。

異常處理整合

<global-exceptions>
    <exception type="com.app.exception.BusinessException"
               handler="com.app.exception.BusinessExceptionHandler"
               key="error.business"
               path="/error.jsp"/>
    <exception type="java.lang.Exception"
               handler="com.app.exception.SystemExceptionHandler"
               key="error.system"
               path="/error.jsp"/>
</global-exceptions>

遷移建議:從 Struts 1 邁向現代框架

Struts 1 概念Spring MVC 對應關鍵差異
ActionServletDispatcherServletSpring 更輕量、支援 REST、非侵入式
ActionForm@ModelAttribute / Command ObjectPOJO 即可,無需繼承基類
Action@Controller + @RequestMapping方法級映射、支援多種返回類型
struts-config.xmlJava Config / 註解類型安全、IDE 重構友善
TilesThymeleaf / FreeMarker / JSP + Tiles 3模板引擎功能更強
ValidatorBean Validation (JSR-380) + @Valid標準化、聲明式、跨層複用

總結

Struts 1 以 ActionServlet 為核心,配合 ActionForm、Action、struts-config.xml 實現經典 MVC 模式。其標籤庫、Tiles、Validator、國際化、異常處理等機制構建了完整的企業級 Web 開發框架。雖已停止維護,但理解其架構設計(Front Controller、命令模式、聲明式配置)對掌握 Spring MVC、Spring Boot 等現代框架極有幫助。存量系統建議採用漸進式遷移:新模組用 Spring Boot,舊模組穩定運行,透過 API 或資料庫整合共存。

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