SpringMVC 作為一款優雅的 Web 框架,與 Struts2 並駕齊驅。雖然 Struts2 出世較早佔據一定優勢,但 SpringMVC 憑藉其註解驅動、靈活的控制器設計以及與 Spring 生態無縫整合的特性,逐漸成為企業級開發的主流選擇。本文將通過一個完整的用戶增刪改查(CRUD)實例,詳細演示 Spring、SpringMVC 與 Hibernate 的整合過程,幫助開發者快速掌握 SSH 框架的核心配置與開發模式。
首先創建一個名為 test_ssh 的 Web 項目,確保引入以下核心 JAR 包:
項目採用標準 Maven 目錄結構,配置文件統一放置在 src/main/resources/config/spring/ 目錄下。
創建 User 實體類,使用 JPA 註解進行 ORM 映射,採用 UUID 作為主鍵生成策略:
package com.tgb.entity;
import javax.persistence.*;
import org.hibernate.annotations.GenericGenerator;
@Entity
@Table(name = "T_USER")
public class User {
@Id
@GeneratedValue(generator = "system-uuid")
@GenericGenerator(name = "system-uuid", strategy = "uuid")
@Column(length = 32)
private String id;
@Column(length = 32)
private String userName;
@Column(length = 32)
private String age;
// Getter/Setter 方法省略...
}
關鍵點解析:
@Entity:標識該類為持久化實體@Table:指定對應的數據庫表名@Id + @GeneratedValue:主鍵生成策略,此處使用 Hibernate 的 UUID 生成器@Column:定義列屬性,如長度、是否為空等負責數據源、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"
xmlns:context="https://www.springframework.org/schema/context"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 數據源配置:使用 Spring 內置 DriverManagerDataSource -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost/test_ssh"/>
<property name="username" value="root"/>
<property name="password" value="1"/>
</bean>
<!-- SessionFactory 配置:整合 Hibernate 4 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
<property name="annotatedClasses">
<list><value>com.tgb.entity.User</value></list>
</property>
</bean>
<!-- 事務管理器 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- 事務代理模板:定義事務傳播屬性 -->
<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,-myException</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
<prop key="*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
</beans>
專注於 Web 層組件掃描、註解驅動、靜態資源映射及視圖解析:
<?xml version="1.0" encoding="UTF-8"?>
<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:mvc="https://www.springframework.org/schema/mvc"
xsi:schemaLocation="https://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
https://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context-3.2.xsd
https://www.springframework.org/schema/mvc
https://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- 掃描控制器包 -->
<context:component-scan base-package="com.tgb"/>
<!-- 啟用註解驅動 -->
<mvc:annotation-driven/>
<!-- 靜態資源訪問配置 -->
<mvc:resources location="/js/" mapping="/js/**"/>
<!-- 視圖解析器:JSP 模式 -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
配置 Spring 容器啟動、SpringMVC 前端控制器、字符編碼過濾器及 OpenSessionInView 過濾器:
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee">
<display-name>ssh_demo</display-name>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
<!-- 載入所有 Spring 配置 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring/spring-*.xml</param-value>
</context-param>
<!-- Spring 容器監聽器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- SpringMVC DispatcherServlet -->
<servlet>
<servlet-name>springMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:config/spring/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springMVC</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- 字符編碼過濾器 -->
<filter>
<filter-name>encodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- Hibernate OpenSessionInView 過濾器:解決懶加載問題 -->
<filter>
<filter-name>openSession</filter-name>
<filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>openSession</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
項目包含以下核心頁面:
index.jsp 關鍵代碼片段:
<%@ taglib prefix="c" uri="https://java.sun.com/jsp/jstl/core" %>
<script type="text/javascript" src="../js/jquery-1.7.1.js"></script>
<script>
function del(id) {
$.get("/test_ssh/user/delUser?id=" + id, function(data) {
if ("success" == data.result) {
alert("刪除成功");
window.location.reload();
} else {
alert("刪除失敗");
}
});
}
</script>
<h6><a href="/test_ssh/user/toAddUser">添加用戶</a></h6>
<table border="1">
<tr><th>姓名</th><th>年齡</th><th>操作</th></tr>
<c:if test="${!empty userList}">
<c:forEach items="${userList}" var="user">
<tr>
<td>${user.userName}</td>
<td>${user.age}</td>
<td>
<a href="/test_ssh/user/getUser?id=${user.id}">編輯</a>
<a href="javascript:del('${user.id}')">刪除</a>
</td>
</tr>
</c:forEach>
</c:if>
</table>
使用 @Controller 和 @RequestMapping 註解定義 REST 風格的 URL 映射:
package com.tgb.web;
@Controller
@RequestMapping("/user")
public class UserController {
@Resource(name = "userManager")
private UserManager userManager;
@RequestMapping("/getAllUser")
public String getAllUser(HttpServletRequest request) {
request.setAttribute("userList", userManager.getAllUser());
return "/index";
}
@RequestMapping("/getUser")
public String getUser(String id, HttpServletRequest request) {
request.setAttribute("user", userManager.getUser(id));
return "/editUser";
}
@RequestMapping("/toAddUser")
public String toAddUser() {
return "/addUser";
}
@RequestMapping("/addUser")
public String addUser(User user, HttpServletRequest request) {
userManager.addUser(user);
return "redirect:/user/getAllUser";
}
@RequestMapping("/delUser")
public void delUser(String id, HttpServletResponse response) throws IOException {
String result = "{\"result\":\"error\"}";
if (userManager.delUser(id)) {
result = "{\"result\":\"success\"}";
}
response.setContentType("application/json");
response.getWriter().write(result);
}
@RequestMapping("/updateUser")
public String updateUser(User user, HttpServletRequest request) {
if (userManager.updateUser(user)) {
return "redirect:/user/getAllUser";
}
return "/error";
}
}
定義業務邏輯契約,實現類委託 DAO 層執行具體操作:
// 接口定義
public interface UserManager {
User getUser(String id);
List<User> getAllUser();
void addUser(User user);
boolean delUser(String id);
boolean updateUser(User user);
}
// 實現類
public class UserManagerImpl implements UserManager {
private UserDao userDao;
public void setUserDao(UserDao userDao) { this.userDao = userDao; }
@Override public User getUser(String id) { return userDao.getUser(id); }
@Override public List<User> getAllUser() { return userDao.getAllUser(); }
@Override public void addUser(User user) { userDao.addUser(user); }
@Override public boolean delUser(String id) { return userDao.delUser(id); }
@Override public boolean updateUser(User user) { return userDao.updateUser(user); }
}
使用 Hibernate 的 SessionFactory 進行數據庫操作,採用 HQL 查詢:
// 接口定義
public interface UserDao {
User getUser(String id);
List<User> getAllUser();
void addUser(User user);
boolean delUser(String id);
boolean updateUser(User user);
}
// 實現類
public class UserDaoImpl implements UserDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
@Override
public User getUser(String id) {
String hql = "from User u where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return (User) query.uniqueResult();
}
@Override
public List<User> getAllUser() {
return sessionFactory.getCurrentSession().createQuery("from User").list();
}
@Override
public void addUser(User user) {
sessionFactory.getCurrentSession().save(user);
}
@Override
public boolean delUser(String id) {
String hql = "delete User u where u.id = ?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, id);
return query.executeUpdate() > 0;
}
@Override
public boolean updateUser(User user) {
String hql = "update User u set u.userName=?, u.age=? where u.id=?";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setString(0, user.getUserName());
query.setString(1, user.getAge());
query.setString(2, user.getId());
return query.executeUpdate() > 0;
}
}
將各層組件裝配起來,並為 Service 層應用事務代理:
<?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.xsd">
<!-- DAO 層 -->
<bean id="userDao" class="com.tgb.dao.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<!-- Service 層基礎實現 -->
<bean id="userManagerBase" class="com.tgb.manager.UserManagerImpl">
<property name="userDao" ref="userDao"/>
</bean>
<!-- 事務代理:為 Service 應用事務屬性 -->
<bean name="userManager" parent="transactionProxy">
<property name="target" ref="userManagerBase"/>
</bean>
</beans>
test_ssh 數據庫https://localhost:8080/test_ssh/hbm2ddl.auto=update 控制)本示例展示了經典 SSH 框架的完整整合流程。實際項目中建議關注以下優化點:
@Repository、@Service、@Transactional 等註解簡化配置@ControllerAdvice 實現全局異常捕獲隨著 Spring Boot 的普及,現代開發更傾向於「約定優於配置」的模式,但理解傳統 SSH 整合原理對於排查疑難雜症、閱讀老項目代碼仍具重要價值。