雖然 Spring Boot 已成主流,但理解經典 SSH (Struts2 + Spring + Hibernate) 整合原理,對掌握 IOC、AOP、ORM 核心機制極有幫助。本文記錄基於 MyEclipse、註解驅動的完整搭建流程,含 jar 包衝突解決、配置文件詳解、分層代碼實現。
struts2-spring-plugin)antlr,版本可能不一致 → 刪除 Struts2 lib 下的 antlr.jar,保留 Hibernate 的ojdbc6.jar (Oracle)commons-dbcp.jar、commons-pool.jar@Entity
@Table(name = "USERS")
public class Users {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_seq")
@SequenceGenerator(name = "user_seq", sequenceName = "SEQ_USERS_ID", allocationSize = 1)
@Column(name = "ID")
private Long id;
@Column(name = "NAME", nullable = false, length = 50)
private String name;
@Column(name = "PASSWORD", nullable = false, length = 50)
private String password;
// Getter/Setter...
}
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<property name="username" value="root"/>
<property name="password" value="admin"/>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<!-- 掃描實體類包,替代 hbm.xml -->
<property name="packagesToScan">
<list><value>com.entity</value></list>
</property>
</bean>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:context="https://www.springframework.org/schema/context"
xmlns:tx="https://www.springframework.org/schema/tx"
xsi:schemaLocation="...">
<!-- 1. 數據源 & SessionFactory (見上) -->
<!-- 2. 開啟註解支持 -->
<context:annotation-config/>
<!-- 3. 組件掃描 (DAO、Service、Action) -->
<context:component-scan base-package="com.dao.impl"/>
<context:component-scan base-package="com.service.impl"/>
<context:component-scan base-package="com.action"/>
<!-- 4. HibernateTemplate 注入 (供 DAO 使用) -->
<bean id="hibernateTemplate" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 5. 事務管理器 -->
<bean id="txManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 6. 註解驅動事務 -->
<tx:annotation-driven transaction-manager="txManager"/>
</beans>
<struts>
<constant name="struts.devMode" value="true"/>
<!-- 關鍵:Action 由 Spring 創建 -->
<constant name="struts.objectFactory" value="spring"/>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<!-- 無需配置 action,約定優於配置 (約定 Action 名 = 類名首字母小寫) -->
</struts>
<web-app version="3.0" ...>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
public interface UsersDao {
Users loginCheck(Users user);
int addUser(Users user);
}
@Repository("usersDaoImpl")
public class UsersDaoImpl implements UsersDao {
@Resource(name = "hibernateTemplate")
private HibernateTemplate hibernateTemplate;
@Override
public Users loginCheck(Users user) {
List<Users> list = hibernateTemplate.find(
"from Users where name=? and password=?",
user.getName(), user.getPassword());
return list.isEmpty() ? null : list.get(0);
}
@Override
public int addUser(Users user) {
try {
hibernateTemplate.save(user);
return 1;
} catch (DataAccessException e) {
return 0;
}
}
}
public interface UsersService {
Users loginCheck(Users user);
int addUser(Users user);
}
@Service("usersServiceImpl")
@Transactional // 類級事務,所有 public 方法開啟事務
public class UsersServiceImpl implements UsersService {
@Resource(name = "usersDaoImpl")
private UsersDao usersDao;
@Override
public Users loginCheck(Users user) {
return usersDao.loginCheck(user);
}
@Override
@Transactional(readOnly = true) // 查詢優化:只讀事務
public int addUser(Users user) {
return usersDao.addUser(user);
}
}
<!-- login.jsp -->
<form action="loginUser.action" method="post">
用戶名: <input type="text" name="user.name"/>
密碼: <input type="password" name="user.password"/>
<input type="submit" value="登錄"/>
</form>
<!-- register.jsp -->
<form action="addUser.action" method="post">
用戶名: <input type="text" name="user.name"/>
密碼: <input type="password" name="user.password"/>
<input type="submit" value="注冊"/>
</form>
| 問題 | 解決 |
|---|---|
| antlr.jar 衝突 | 刪除 Struts2 lib 下的,保留 Hibernate 版本 |
| Action 注入為 null | 檢查 struts.objectFactory=spring、@Controller、@Resource name 一致 |
| 事務不生效 | 檢查 @Transactional 在 public 方法、tx:annotation-driven、txManager 引用正確 |
| Session 關閉導致 LazyInitializationException | OpenSessionInViewFilter / fetch join / DTO 轉換 |
| 約定 Action 名不匹配 | @Action("xxx") 显式指定,或遵循類名首字母小寫約定 |