在 Java EE 開發中,Hibernate、Struts 2 與 Spring 的整合(俗稱 SSH 整合)是經典的企業級應用架構。本文將詳細記錄如何在 Eclipse 環境下,逐步搭建一個基於這三大框架的 Web 專案,涵蓋環境配置、資料源設定、DAO 層實作、Action 整合以及事務管理等核心步驟。
在 Eclipse 中新建一個 Web Project,選擇 Java EE 5.0 作為執行環境。
hibernate.cfg.xml 配置檔,稍後我們將其移除,改由 Spring 統一管理。applicationContext.xml 放置於 WebRoot/WEB-INF/ 目錄下。刪除 hibernate.cfg.xml,修改 applicationContext.xml,配置資料源與 SessionFactory:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<!-- 資料源配置:使用 DBCP 連線池 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@liuweiv3000:1521:ora9"/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
<!-- SessionFactory 配置 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource"><ref bean="dataSource"/></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle9Dialect</prop>
</props>
</property>
<property name="mappingResources">
<list>
<value>cn/com/jobedu/shop/model/Catalog.hbm.xml</value>
</list>
</property>
</bean>
</beans>
別忘了在 Build Path 中加入 commons-dbcp-1.2.2.jar 和 commons-pool-1.3.jar。
使用 MyEclipse 的反向工程向導,根據資料庫表結構自動生成 POJO 類別與對應的 .hbm.xml 映射檔。
將新生成的映射檔加入 applicationContext.xml 的 mappingResources 列表中:
<property name="mappingResources">
<list>
<value>cn/com/jobedu/shop/model/Catalog.hbm.xml</value>
<value>cn/com/jobedu/shop/model/Product.hbm.xml</value>
</list>
</property>
package cn.com.jobedu.shop.dao;
import java.util.List;
import cn.com.jobedu.shop.model.Catalog;
public interface CatalogDao {
void create(Catalog c);
Catalog getCatalog(Long id);
List getCatalogs();
void update(Catalog c);
void remove(Long id);
}
package cn.com.jobedu.shop.dao.hibernate;
import java.util.List;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import cn.com.jobedu.shop.dao.CatalogDao;
import cn.com.jobedu.shop.model.Catalog;
public class CatalogDaoHibernate extends HibernateDaoSupport implements CatalogDao {
@Override public void create(Catalog c) { getHibernateTemplate().save(c); }
@Override public Catalog getCatalog(Long id) { return (Catalog)getHibernateTemplate().get(Catalog.class, id); }
@Override public List getCatalogs() { return getHibernateTemplate().find("from Catalog order by id desc"); }
@Override public void remove(Long id) { getHibernateTemplate().delete(getCatalog(id)); }
@Override public void update(Catalog c) { getHibernateTemplate().update(c); }
}
<bean id="catalogDao" class="cn.com.jobedu.shop.dao.hibernate.CatalogDaoHibernate">
<property name="sessionFactory"><ref bean="sessionFactory"/></property>
</bean>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
將 struts2-spring-plugin-x.x.x.jar 加入專案類別路徑。
<struts>
<constant name="struts.objectFactory" value="spring" />
</struts>
<!-- Spring 容器啟動監聽器 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 解決 LazyInitializationException,支援視圖層延遲載入 -->
<filter>
<filter-name>lazyLoadingFilter</filter-name>
<filter-class>org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>lazyLoadingFilter</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
Action 類別不再繼承特定基類,而是通過 Setter 注入 Service 或 DAO,由 Spring 管理生命週期。
<struts>
<constant name="struts.objectFactory" value="spring" />
<include file="struts-default.xml"/>
<package name="default" extends="struts-default">
<action name="hello" class="helloBean">
<result>hello.jsp</result>
</action>
<!-- 更多 action 配置 -->
</package>
</struts>
<beans default-autowire="byName">
<bean id="helloBean" class="cn.com.jobedu.HelloWorld" scope="prototype" />
<!-- 其他 bean -->
</beans>
設定 default-autowire="byName" 可讓 Spring 自動依名稱注入屬性(如 catalogDao)。
在 applicationContext.xml 中加入事務管理器、通知與 AOP 切面:
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory"><ref local="sessionFactory"/></property>
</bean>
<!-- 事務屬性:增刪改方法需事務,查詢唯讀 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- AOP 切面:套用至 service 包下所有類 -->
<aop:config>
<aop:pointcut id="allManagerMethod" expression="execution(* cn.com.jobedu.crm.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="allManagerMethod"/>
</aop:config>
完成上述配置後,編寫對應的 JSP 視圖,部署至 Tomcat 等容器,啟動專案驗證整合是否成功。
本文完整示範了從零開始搭建 SSH 整合環境的全過程:Spring 管理 Hibernate 的 SessionFactory 與事務,Struts 2 通過 Spring 插件接管 Action 實例化,並配合 OpenSessionInViewFilter 解決延遲載入問題。掌握此流程,可快速建立結構清晰、易於維護的企業級 Java Web 應用。