HTTP Request
│
▼
Struts ActionServlet (Controller)
│
├──► ActionForm (表單資料綁定/驗證)
│
└──► Action (Struts Action 子類)
│
▼ (透過 Spring 取得 Bean)
Spring Business Service (交易、邏輯)
│
▼
Spring DAO / ORM (Hibernate/MyBatis/JPA)
│
▼
Database
│
▼
Return ActionForward → JSP View
在 struts-config.xml 中註冊 ContextLoaderPlugIn,指定 Spring 設定檔位置:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.1//EN"
"https://jakarta.apache.org/struts/dtds/struts-config_1_1.dtd">
<struts-config>
<!-- 既有 form-beans、global-forwards、action-mappings 略 -->
<!-- Validator 外掛 -->
<plug-in className="org.apache.struts.validator.ValidatorPlugIn">
<set-property property="pathnames"
value="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml"/>
</plug-in>
<!-- ★ 關鍵:Spring 容器載入外掛 -->
<plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
<set-property property="contextConfigLocation"
value="/WEB-INF/applicationContext.xml"/> <!-- Spring Bean 定義檔 -->
</plug-in>
</struts-config>
/WEB-INF/applicationContext.xml:
<beans>
<bean id="creditcardService"
class="com.infotek.Creditcard.business.CreditcardServiceImpl">
<property name="dao" ref="creditcardDao"/>
</bean>
<bean id="creditcardDao"
class="com.infotek.Creditcard.persistence.CreditcardDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- dataSource、sessionFactory、transactionManager 等基礎設施 Bean 略 -->
</beans>
package com.infotek.Creditcard.actions;
import org.springframework.web.struts.ActionSupport;
import org.springframework.context.ApplicationContext;
import com.infotek.Creditcard.business.CreditcardService;
import com.infotek.Creditcard.beans.Creditcard;
import org.apache.struts.action.*;
public class SearchSubmit extends ActionSupport { // ★ 繼承 ActionSupport
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
DynaActionForm searchForm = (DynaActionForm) form;
String cardNo = (String) searchForm.get("cardno");
// 1. 取得 Spring WebApplicationContext
ApplicationContext ctx = getWebApplicationContext();
// 2. 從容器取得 Service Bean(依賴查找)
CreditcardService service = (CreditcardService) ctx.getBean("creditcardService");
// 3. 呼叫業務邏輯
Creditcard card = service.read(cardNo.trim());
if (card == null) {
ActionErrors errors = new ActionErrors();
errors.add(ActionErrors.GLOBAL_ERROR,
new ActionError("message.notfound"));
saveErrors(request, errors);
return mapping.findForward("failure");
}
request.setAttribute("creditcard", card);
return mapping.findForward("success");
}
}
| 類別/介面 | 角色 | 備註 |
|---|---|---|
ContextLoaderPlugIn | Struts 啟動時初始化 Spring 容器,綁定至 ServletContext | 對應 WebApplicationContextUtils.getWebApplicationContext(servletContext) |
ActionSupport | Spring 提供的 Struts Action 基類,內建 getWebApplicationContext() | 避免在 Action 中硬編碼 WebApplicationContextUtils |
DelegatingActionProxy | 另一種整合方式:Action 交由 Spring 管理,Struts 只持有 Proxy | 更純粹的 IoC,但需額外配置,本文採用 ActionSupport 簡單直接 |
ActionSupport 導致難以單元測試 Action(需模擬 Spring 容器)。ctx.getBean(),不如注入優雅。<!-- struts-config.xml -->
<action path="/searchSubmit"
type="org.springframework.web.struts.DelegatingActionProxy"> <!-- Proxy -->
<set-property property="delegateAction" value="searchSubmitAction"/> <!-- Spring Bean 名稱 -->
<forward name="success" path="/WEB-INF/pages/detail.jsp"/>
<forward name="failure" path="/WEB-INF/pages/search.jsp"/>
</action>
<!-- applicationContext.xml -->
<bean name="searchSubmitAction" class="com.infotek.Creditcard.actions.SearchSubmit">
<property name="creditcardService" ref="creditcardService"/> <!-- 真正的 DI -->
</bean>
此時 SearchSubmit 可改為普通 POJO 或繼承 Action,由 Spring 完整管理,支援 AOP、@Transactional、單元測試注入 Mock。
本文示範的 ContextLoaderPlugIn + ActionSupport 是 Struts 1.x 整合 Spring 最經典、門檻最低的方式,適合快速遷移既有專案。若追求純粹 IoC、AOP 支援與測試性,建議升級為 DelegatingActionProxy 模式,甚至考慮遷移至 Spring MVC 或 Spring Boot 現代架構。