Struts 是早期 Java Web 開發的經典 MVC 框架,將 JSP (View)、Servlet (Controller)、JavaBean (Model) 解耦。本文以簡單的登入/登出系統為例,完整示範 Struts 1.1 的專案結構、配置檔、ActionForm、Action、JSP 標籤庫與國際化訊息資源的應用。
logonApp/:
src/ - Java 原始碼WEB-INF/classes/ - 編譯輸出WEB-INF/lib/ - struts.jar, servlet.jarWEB-INF/struts-*.tld - 標籤庫描述檔<web-app>
<!-- ActionServlet: Struts 前端控制器 -->
<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>
<servlet-mapping>
<servlet-name>action</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<welcome-file-list><welcome-file>index.jsp</welcome-file></welcome-file-list>
<!-- 標籤庫宣告 -->
<taglib><taglib-uri>/WEB-INF/struts-bean.tld</taglib-uri><taglib-location>/WEB-INF/struts-bean.tld</taglib-location></taglib>
<taglib><taglib-uri>/WEB-INF/struts-html.tld</taglib-uri><taglib-location>/WEB-INF/struts-html.tld</taglib-location></taglib>
<taglib><taglib-uri>/WEB-INF/struts-logic.tld</taglib-uri><taglib-location>/WEB-INF/struts-logic.tld</taglib-location></taglib>
</web-app>
<struts-config>
<!-- 動態表單 Bean:無需撰寫 ActionForm 類別 -->
<form-beans>
<form-bean name="logonForm" type="org.apache.struts.validator.DynaValidatorForm">
<form-property name="username" type="java.lang.String"/>
<form-property name="password" type="java.lang.String"/>
</form-bean>
</form-beans>
<!-- 全域轉向 -->
<global-forwards>
<forward name="success" path="/main.jsp"/>
<forward name="logoff" path="/logoff.do"/>
</global-forwards>
<!-- Action 映射 -->
<action-mappings>
<action path="/logon"
type="org.monotonous.struts.LogonAction"
name="logonForm"
scope="session"
input="logon"> <!-- 驗證失敗導向 -->
</action>
<action path="/logoff"
type="org.monotonous.struts.LogoffAction">
<forward name="success" path="/index.jsp"/>
</action>
</action-mappings>
<controller>
<set-property property="inputForward" value="true"/> <!-- input 參數視為 forward name -->
</controller>
<message-resources parameter="org.monotonous.struts.ApplicationResources"/>
</struts-config>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html locale="true">
<head>
<title><bean:message key="index.title"/></title>
<html:base/>
</head>
<body>
<html:errors/> <!-- 顯示驗證錯誤 -->
<html:form action="/logon">
<bean:message key="prompt.username"/>
<html:text property="username"/><br/>
<bean:message key="prompt.password"/>
<html:password property="password"/><br/>
<html:submit><bean:message key="index.logon"/></html:submit>
</html:form>
</body>
</html:html>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<html:html>
<head><title><bean:message key="main.title"/></title><html:base/></head>
<body>
<html:link forward="logoff"><bean:message key="main.logoff"/></html:link>
</body>
</html:html>
index.title=Struts Homepage
prompt.username=Username
prompt.password=Password
index.logon=Log on
main.title=Struts Main page
main.logoff=Log off
error.password.mismatch=Invalid username and/or password.
package org.monotonous.struts;
public final class LogonAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
Locale locale = getLocale(request);
MessageResources messages = getResources(request);
ActionErrors errors = new ActionErrors();
// 從 DynaValidatorForm 取值
String username = (String) PropertyUtils.getSimpleProperty(form, "username");
String password = (String) PropertyUtils.getSimpleProperty(form, "password");
// 簡單驗證 (實務應查詢資料庫/服務)
if (!"foo".equals(username) || !"bar".equals(password)) {
errors.add(ActionErrors.GLOBAL_ERROR, new ActionError("error.password.mismatch"));
}
if (!errors.isEmpty()) {
saveErrors(request, errors);
return mapping.getInputForward(); // 返回 input="logon" 對應的 forward
}
// 登入成功:存入 Session
HttpSession session = request.getSession();
session.setAttribute("user", username); // 實務存入 User 物件
// 移除舊的 Form Bean (scope=session 時需手動清理)
if (mapping.getAttribute() != null) {
if ("request".equals(mapping.getScope())) request.removeAttribute(mapping.getAttribute());
else session.removeAttribute(mapping.getAttribute());
}
return mapping.findForward("success"); // global-forwards success → /main.jsp
}
}
package org.monotonous.struts;
public final class LogoffAction extends Action {
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
session.removeAttribute("user");
session.invalidate(); // 銷毀 Session
return mapping.findForward("success"); // action-mappings logoff success → /index.jsp
}
}
| 概念 | 說明 |
|---|---|
| ActionServlet | 前端控制器,攔截 *.do 請求,委派給對應 Action |
| DynaValidatorForm | 動態表單,XML 定義屬性,免寫 ActionForm 類別,整合 Validator 框架 |
| ActionMapping | struts-config.xml |
| ActionForward | 邏輯視圖名稱對應實際路徑,支援全域與區域轉向 |
| ActionErrors/ActionError | 驗證錯誤收集器, |
| MessageResources | 國際化訊息資源管理, |
| PropertyUtils | Commons BeanUtils 元件,動態存取 Form Bean 屬性 |
Struts 1.x (2000-2008) 確立了 Java Web MVC 模式,但有侵入性強 (繼承 Action)、表單處理繁瑣、靠攏 Servlet API 等缺點。現代專案建議遷移至:
理解 Struts 1 核心概念 (前端控制器、Action 對應、Form Bean、轉向、標籤庫、國際化) 有助於快速掌握後續框架的同源設計思想。