之前,我介绍了spring 3 + hibernate 集成 示例和struts 2 hello world 示例。在本教程中,我将讨论在将 spring 框架与 struts 与 hibernate 结合使用时要牢记的所有要点。另外,请注意,本教程使用了其他次要但重要的概念,例如日志记录、TLD 的使用和事务,这些概念也集成在本教程中。所以记得也要检查他们的详细信息。
在本教程中,我正在构建具有简单功能(如全部获取、添加和删除)的员工管理屏幕。它看起来像这样:
我将按以下步骤讨论集成过程:
1) Integration Overview 2) Spring + Struts Integration 3) Spring + Hibernate Integration 4) Other Integrated Functionalities a) Log4j b) TLDs c) Transactions 5) Important Points to Keep Remember 6) Database Schema Used in Tutorial 7) Download Sourcecode
在进入集成细节之前,让我们首先确定为什么我们需要此集成。与 Struts 一样,Spring 也可以充当 MVC 实现。这两种框架都有其优点和缺点,但仍有许多人会同意 Spring 更好并提供更广泛的功能。对我来说,只有两种情况需要本教程中提供的信息:
i) 您有一个用 struts 编写的旧应用程序,并且想使用 spring 将应用程序的功能提高很多倍。
ii) 您真的想自己学习它原因。
否则我不知道为什么有人会选择 struts 而不是 spring。如果您知道其他一些好的理由,请与我们所有人分享。那挺棒的。
继续,在本教程中,我将 Action 管理从 Struts 委托给 Spring。这种委托的原因是,Action 类在由 spring 上下文实例化时,可以使用 spring 在其自己的 MVC 实现中为其控制器类提供的所有其他功能。因此,您可以获得所有 spring 功能以及 struts Action 类以具有控制器逻辑,包括它的 ActionForm 概念。
这是核心逻辑,从在 web.xml 中注册 ContextLoaderListener
和 StrutsPrepareAndExecuteFilter
开始。 ContextLoaderListener
采用初始化参数 contextConfigLocation 并负责设置和启动 Spring WebApplicationContext
。现在 struts 将在 spring 相关服务中利用这个上下文,特别是在 dependency injection 中。
StrutsPrepareAndExecuteFilter
在类路径中查找 struts.xml 文件并配置 strut 的特定内容,例如 Action 映射、全局转发和 struts 中定义的其他内容。 xml 文件。
web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee https://www.oracle.com/java/technologies/; id="WebApp_ID" version="2.5"> <display-name>Spring+Struts+Hibernate Integration Example</display-name> <welcome-file-list> <welcome-file>/WEB-INF/index.jsp</welcome-file> </welcome-file-list> <!-- Specify the spring context information location; Default location is applicationContext.xml file in classpath --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:beans.xml</param-value> </context-param> <!-- Bootstrap listener to start up and shut down Spring's root WebApplicationContext. --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- Handles both the preparation and execution phases of the Struts dispatching process. --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>detail</param-name> <param-value>0</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <!-- Struts Tag Library Descriptors --> <jsp-config> <taglib> <taglib-uri>/tags/struts-bean</taglib-uri> <taglib-location>/WEB-INF/struts-bean.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-html</taglib-uri> <taglib-location>/WEB-INF/struts-html.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-logic</taglib-uri> <taglib-location>/WEB-INF/struts-logic.tld</taglib-location> </taglib> <taglib> <taglib-uri>/tags/struts-nested</taglib-uri> <taglib-location>/WEB-INF/struts-nested.tld</taglib-location> </taglib> </jsp-config> </web-app>
在第二步中,您将在 struts.xml 文件中拥有您的操作映射,如下所示:
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <!-- devMode is helpful when you want some extra logs for debugging --> <constant name="struts.devMode" value="false" /> <!-- Global message resource; Otherwise you will have seperate message resource for each Action --> <constant name="struts.custom.i18n.resources" value="messages" /> <!-- This is important if you are planning to have slashes in Action URLs e.g. In this demo, employee is deleted using URL /delete/10 This this is set to false; then struts will try to find mapping for URL "/10" instaed of "/delete/10" --> <constant name="struts.enable.SlashesInActionNames" value="true"/> <!-- Normal Action mappings are defined here --> <package name="default" namespace="" extends="struts-default"> <!-- Two things to Notice: 1) class is set to 'editEmployeeAction' which is bean defined by Spring context 2) We have given the method to be called here as well; --> <action name="list" class="editEmployeeAction" method="listEmployees"> <result>/view/editEmployeeList.jsp</result> </action> <action name="add" class="editEmployeeAction" method="addEmployee"> <result type="redirect">/list</result> </action> <action name="delete/*" class="editEmployeeAction" method="deleteEmployee"> <param name="employee.id">{1}</param> <result type="redirect">/list</result> </action> <action name="*" class="editEmployeeAction" method="listEmployees"> <result>/view/editEmployeeList.jsp</result> </action> </package> </struts>
Spring 上下文文件 beans.xml 是典型的 spring 独立上下文文件,具有 Web 应用程序工作所需的所有内容,包括 struts 正在寻找的 bean 定义 editEmployeeAction
。
beans.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop/ http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context/ http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee/ http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/lang/ http://www.springframework.org/schema/lang/spring-lang.xsd http://www.springframework.org/schema/tx/ http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/util/ http://www.springframework.org/schema/util/spring-util.xsd"> <!-- This bean has been referred fron struts.xml file; So type it correctly; --> <!-- Make scope prototype; This is really important. --> <bean name="editEmployeeAction" class="com.cundage.controller.EditEmployeeAction" scope="prototype"> <property name="employeeManager"> <ref bean="employeeManager"/> </property> </bean> <!-- These beans are injected automatically by spring context --> <bean id="employeeDAO" class="com.cundage.dao.EmployeeDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="employeeManager" class="com.cundage.service.EmployeeManagerImpl"> <property name="employeeDAO" ref="employeeDAO"/> </bean> <!-- Configure jdbc.properties --> <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:location="/WEB-INF/jdbc.properties" /> <!-- Data Source configuration --> <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" p:driverClassName="${jdbc.driverClassName}" p:url="${jdbc.databaseurl}" p:username="${jdbc.username}" p:password="${jdbc.password}" /> <!-- Configure hibernate session factory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <property name="configLocation"> <value>classpath:hibernate.cfg.xml</value> </property> <property name="configurationClass"> <value>org.hibernate.cfg.AnnotationConfiguration</value> </property> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">${jdbc.dialect}</prop> <prop key="hibernate.show_sql">true</prop> </props> </property> </bean> <!-- Run SQL queries in transactions --> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> </beans>
这就是我们将 struts 与 spring 集成 框架所需要做的全部工作。现在你的动作类看起来像这样:
EditEmployeeAction.java
package com.cundage.controller; import java.util.List; import org.apache.log4j.Logger; import com.cundage.entity.EmployeeEntity; import com.cundage.service.EmployeeManager; import com.opensymphony.xwork2.ActionSupport; import com.opensymphony.xwork2.Preparable; public class EditEmployeeAction extends ActionSupport implements Preparable { private static final long serialVersionUID = 1L; //Logger configured using log4j private static final Logger logger = Logger.getLogger(EditEmployeeAction.class); //List of employees; Setter and Getter are below private List<EmployeeEntity> employees; //Employee object to be added; Setter and Getter are below private EmployeeEntity employee; //Employee manager injected by spring context; This is cool !! private EmployeeManager employeeManager; //This method return list of employees in database public String listEmployees() { logger.info("listEmployees method called"); employees = employeeManager.getAllEmployees(); return SUCCESS; } //This method will be called when a employee object is added public String addEmployee() { logger.info("addEmployee method called"); employeeManager.addEmployee(employee); return SUCCESS; } //Deletes a employee by it's id passed in path parameter public String deleteEmployee() { logger.info("deleteEmployee method called"); employeeManager.deleteEmployee(employee.getId()); return SUCCESS; } //This method will be called before any of Action method is invoked; //So some pre-processing if required. @Override public void prepare() throws Exception { employee = null; } //Getters and Setters hidden }
Spring 还将 DAO 引用注入到 Manager 类。
EmployeeManagerImpl.java
package com.cundage.service; import java.util.List; import org.springframework.transaction.annotation.Transactional; import com.cundage.dao.EmployeeDAO; import com.cundage.entity.EmployeeEntity; public class EmployeeManagerImpl implements EmployeeManager { //Employee dao injected by Spring context private EmployeeDAO employeeDAO; //This method will be called when a employee object is added @Override @Transactional public void addEmployee(EmployeeEntity employee) { employeeDAO.addEmployee(employee); } //This method return list of employees in database @Override @Transactional public List<EmployeeEntity> getAllEmployees() { return employeeDAO.getAllEmployees(); } //Deletes a employee by it's id @Override @Transactional public void deleteEmployee(Integer employeeId) { employeeDAO.deleteEmployee(employeeId); } //This setter will be used by Spring context to inject the dao's instance public void setEmployeeDAO(EmployeeDAO employeeDAO) { this.employeeDAO = employeeDAO; } }
现在我们必须将休眠集成到应用程序中。最好的地方是使用 Spring 的广泛功能进行集成,以使用依赖注入的出色使用来与不同的 ORM 一起工作。
上面的 beans.xml 文件中已经给出了 spring 所需的 hibernate 依赖项。您需要的其他文件是:
休眠.cfg.xml
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <mapping class="com.cundage.entity.EmployeeEntity" /> </session-factory> </hibernate-configuration>
jdbc.properties
jdbc.driverClassName=com.mysql.jdbc.Driver jdbc.dialect=org.hibernate.dialect.MySQLDialect jdbc.databaseurl=jdbc:mysql://127.0.0.1:3306/test jdbc.username=root jdbc.password=password
EmployeeDaoImpl.java
package com.cundage.dao; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.stereotype.Repository; import com.cundage.entity.EmployeeEntity; @Repository public class EmployeeDaoImpl implements EmployeeDAO { //Session factory injected by spring context private SessionFactory sessionFactory; //This method will be called when a employee object is added @Override public void addEmployee(EmployeeEntity employee) { this.sessionFactory.getCurrentSession().save(employee); } //This method return list of employees in database @SuppressWarnings("unchecked") @Override public List<EmployeeEntity> getAllEmployees() { return this.sessionFactory.getCurrentSession().createQuery("from EmployeeEntity").list(); } //Deletes a employee by it's id @Override public void deleteEmployee(Integer employeeId) { EmployeeEntity employee = (EmployeeEntity) sessionFactory.getCurrentSession() .load(EmployeeEntity.class, employeeId); if (null != employee) { this.sessionFactory.getCurrentSession().delete(employee); } } //This setter will be used by Spring context to inject the sessionFactory instance public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } }
作为参考,EmployeeEntity 类如下所示:
EmployeeEntity.java
package com.cundage.entity; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="EMPLOYEE") public class EmployeeEntity { @Id @Column(name="ID") @GeneratedValue private Integer id; @Column(name="FIRSTNAME") private String firstname; @Column(name="LASTNAME") private String lastname; @Column(name="EMAIL") private String email; @Column(name="TELEPHONE") private String telephone; //Setters and Getters }
除了 struts + spring + hibernate 之外,我们还使用了以下组件来构建应用程序。
Spring 通过扫描类路径中的 log4j
自动配置日志记录。我们使用 pom.xml
文件添加了 log4j 依赖项。现在您只需在类路径中放置一个 log4j.xml 或 log4j.properties 文件。
log4j.properties
log4j.rootLogger=info, stdout, R log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n log4j.appender.R=org.apache.log4j.RollingFileAppender log4j.appender.R.File=c:/log/demo.log log4j.appender.R.MaxFileSize=100KB log4j.appender.R.MaxBackupIndex=1 log4j.appender.R.layout=org.apache.log4j.PatternLayout log4j.appender.R.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
如果您查看 web.xml
文件,我们会在其中包含一些 TLD。我们可以随时在视图层中使用它们,如下所示:
编辑员工列表.jsp
<%@ taglib prefix="s" uri="/struts-tags"%> <%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <html> <head> <title>Spring-4 + Struts-3 + Hibernate Integration Demo</title> <style> table.list { border-collapse:collapse; width: 40%; } table.list, table.list td, table.list th { border:1px solid gray; padding: 5px; } </style> </head> <body> <h2>Spring-4 + Struts-3 + Hibernate Integration Demo</h2> <s:form method="post" action="add"> <table> <tr> <td><s:textfield key="label.firstname" name="employee.firstname"/></td> </tr> <tr> <td><s:textfield key="label.lastname" name="employee.lastname"/></td> </tr> <tr> <td><s:textfield key="label.email" name="employee.email"/></td> </tr> <tr> <td><s:textfield key="label.telephone" name="employee.telephone"/></td> </tr> <tr> <td> <s:submit key="label.add"></s:submit> </td> </tr> </table> </s:form> <h3>Employees</h3> <c:if test="${!empty employees}"> <table class="list"> <tr> <th align="left">Name</th> <th align="left">Email</th> <th align="left">Telephone</th> <th align="left">Actions</th> </tr> <c:forEach items="${employees}" var="emp"> <tr> <td>${emp.lastname}, ${emp.firstname} </td> <td>${emp.email}</td> <td>${emp.telephone}</td> <td><a href="delete/${emp.id}">delete</a></td> </tr> </c:forEach> </table> </c:if> </body> </html>
EmployeeManagerImpl.java 在getAllEmployees() 和deleteEmployee() 等方法中使用注解@Transactional。这实质上是在单个事务中运行在此方法下执行的所有数据库查询。您像这样在 beans.xml
上下文文件中声明事务依赖性。
<!-- Run SQL queries in transactions --> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
a) 如果运行时无法在 lib 文件夹中找到类,则将项目依赖项中的 jar 文件添加到项目部署程序集中。
b) 使在bean.xml 中定义的Action 类的作用域为“原型”。 Spring 提供的 bean 的默认范围是单例,并且必须为每个请求创建新的 struts Action 类,因为它包含用户会话特定数据。为了适应两者,将 Action 类 bean 标记为原型。
c) 在运行此应用程序之前不要忘记设置数据库。如果设置不正确,它会导致你出现几个异常。
d) 此外,请在项目运行时依赖项中包含 struts2-spring-plugin
。
下表已在名为“test”的数据库中的 MySQL 中创建。
CREATE TABLE EMPLOYEE ( ID INT PRIMARY KEY AUTO_INCREMENT, FIRSTNAME VARCHAR(30), LASTNAME VARCHAR(30), TELEPHONE VARCHAR(15), EMAIL VARCHAR(30), CREATED TIMESTAMP DEFAULT NOW() );
如果您打算自己构建应用程序,那么下面给出的此应用程序中使用的直接结构 将对您有所帮助。
该项目中使用的具有所有项目依赖项(一些额外的)的 pom.xml
文件如下:
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.cundage.app</groupId> <artifactId>Spring4Struts2HibernateIntegration</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>Spring4Struts2HibernateIntegration Maven Webapp</name> <url>http://maven.apache.org</url> <!-- JBoss repository for Hibernate --> <repositories> <repository> <id>JBoss repository</id> <url>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> <properties> <org.springframework.version>4.0.3.RELEASE</org.springframework.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.16.2</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-spring-plugin</artifactId> <version>2.3.16.2</version> </dependency> <!-- Core utilities used by other modules. Define this if you use Spring Utility APIs (org.springframework.core.*/org.springframework.util.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework.version}</version> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework.version}</version> <scope>runtime</scope> </dependency> <!-- Bean Factory and JavaBeans utilities (depends on spring-core) Define this if you use Spring Bean APIs (org.springframework.beans.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Application Context (depends on spring-core, spring-expression, spring-aop, spring-beans) This is the central artifact for Spring's Dependency Injection Container and is generally always defined --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Aspect Oriented Programming (AOP) Framework (depends on spring-core, spring-beans) Define this if you use Spring AOP APIs (org.springframework.aop.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjtools</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> <!-- Transaction Management Abstraction (depends on spring-core, spring-beans, spring-aop, spring-context) Define this if you use Spring Transactions or DAO Exception Hierarchy (org.springframework.transaction.*/org.springframework.dao.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- JDBC Data Access Library (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you use Spring's JdbcTemplate API (org.springframework.jdbc.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework.version}</version> </dependency> <!-- Object-to-Relation-Mapping (ORM) integration with Hibernate, JPA, and iBatis. (depends on spring-core, spring-beans, spring-context, spring-tx) Define this if you need ORM (org.springframework.orm.*) --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework.version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.15</version> <exclusions> <exclusion> <groupId>javax.mail</groupId> <artifactId>mail</artifactId> </exclusion> <exclusion> <groupId>javax.jms</groupId> <artifactId>jms</artifactId> </exclusion> <exclusion> <groupId>com.sun.jdmk</groupId> <artifactId>jmxtools</artifactId> </exclusion> <exclusion> <groupId>com.sun.jmx</groupId> <artifactId>jmxri</artifactId> </exclusion> </exclusions> <scope>runtime</scope> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>3.6.3.Final</version> </dependency> <dependency> <groupId>javassist</groupId> <artifactId>javassist</artifactId> <version>3.12.1.GA</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>taglibs</groupId> <artifactId>standard</artifactId> <version>1.1.2</version> <scope>runtime</scope> </dependency> <dependency> <groupId>commons-dbcp</groupId> <artifactId>commons-dbcp</artifactId> <version>1.4</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.9</version> </dependency> </dependencies> <build> <finalName>Spring3Struts2HibernateIntegration</finalName> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.6</source> <target>1.6</target> </configuration> </plugin> </plugins> </build> </project>
下载上述示例的源代码或获取 .war 文件。
这就是本spring 4 + struts 2 + hibernate 集成 教程的全部内容。让我知道您的想法和疑问。
快乐学习!!
地址:https://www.cundage.com/article/spring-4-struts-2-hibernate-integration-tutorial.html