Previously, I have covered spring 3 + hibernate integration example and struts 2 hello world example. In this tutorial, I am discussing all important points to keep in mind when integration spring framework with struts in conjunction with hibernate. Also, please note that this tutorial uses other minor yet important concepts such as logging, use of TLDs and transactions as well integrated in this tutorial. So remember to check their details as well.
In this tutorial, I am building Employee management screen with simple capabilities like get all, add and delete. It will look like this:
I will discuss the integration process in following steps:
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
1) Integration Overview
Before jumping into integration details, let’s identify why we need this integration in first place itself. Like Struts, Spring can also function as an MVC implementation. Both frameworks have their merits and drawbacks, still many will agree that Spring is much better and provides wider range of functionalities. For me there are only two scenarios, where you will need information given in this tutorial:
i) You have a old application written in struts and want to use spring to enhance application’s capability many folds.
ii) You really want to learn it for your own reasons.
Otherwise I am not ware of any good reason why somebody will choose struts over spring. If you know some other good reasons, please share with all of us. That will be great.
Moving on, in this tutorial I am delegating the Action management from Struts to Spring. The reason for this delegation is that, Action class when instantiated by spring context, can use all of the other features which spring provides to it’s Controller classes in it’s own MVC implementations. So you get all spring features as well as struts Action class to have controller logic including it’s ActionForm concept.
2) Spring + Struts Integration
This is core logic and starts from registering ContextLoaderListener
and StrutsPrepareAndExecuteFilter
in web.xml. ContextLoaderListener
takes init parameter contextConfigLocation and is responsible for setup and start Spring WebApplicationContext
. Now struts will take advantage of this context in spring related services specially in dependency injection.
StrutsPrepareAndExecuteFilter
look up struts.xml file in classpath and configure strut’s specific things like Action mappings, global forwards and other things defined in struts.xml file.
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>
In second step, you will have your action mappings in struts.xml file like this:
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 context file beans.xml is typical spring alone context file having all required thing for a web application to work, INCLUDING a bean definition editEmployeeAction
which struts is looking for.
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.howtodoinjava.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.howtodoinjava.dao.EmployeeDaoImpl"> <property name="sessionFactory" ref="sessionFactory"/> </bean> <bean id="employeeManager" class="com.howtodoinjava.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>
This is all we need to do to integrate struts with spring framework. Now you action class look like this:
EditEmployeeAction.java
package com.howtodoinjava.controller; import java.util.List; import org.apache.log4j.Logger; import com.howtodoinjava.entity.EmployeeEntity; import com.howtodoinjava.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 also inject the DAO references to Manager class.
EmployeeManagerImpl.java
package com.howtodoinjava.service; import java.util.List; import org.springframework.transaction.annotation.Transactional; import com.howtodoinjava.dao.EmployeeDAO; import com.howtodoinjava.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; } }
3) Spring + Hibernate Integration
Now we have to integrate hibernate into application. Best place is to integrate using Spring’s extensive capabilities to work with different ORMs using excellent use of dependency injection.
Required hibernate dependencies for spring have already been given in above beans.xml file. Other files you will need are:
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.howtodoinjava.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.howtodoinjava.dao; import java.util.List; import org.hibernate.SessionFactory; import org.springframework.stereotype.Repository; import com.howtodoinjava.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; } }
For your reference, the EmployeeEntity class looks like this:
EmployeeEntity.java
package com.howtodoinjava.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 }
4) Other Integrated Functionalities
Apart from struts + spring + hibernate we have used following components to build the application.
a) Log4j
Spring configure logging automatically by scanning log4j
in classpath. We have added the log4j dependency using pom.xml
file. Now all you have to place a log4j.xml or log4j.properties file in classpath.
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
b) TLDs
If you look at web.xml
file, the we have included some TLDs in there. We can use them anytime in view layer like this:
editEmployeeList.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>
c) Transactions
EmployeeManagerImpl.java uses annotation @Transactional in method such as getAllEmployees() and deleteEmployee(). This essentially run all the database queries executed under this method in single transaction. You declared transaction dependencies in beans.xml
context file like this.
<!-- Run SQL queries in transactions --> <tx:annotation-driven /> <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean>
5) Important Points to Keep Remember
a) Add the jar files from project dependencies into project deployment assembly if runtime is unable to find classes present in lib folder.
b) Make scope of Action class defined in bean.xml as “prototype”. Default scope of Spring’s provided beans are singleton and struts Action class must be created new for each request because it contain user session specific data. To accommodate both, mark Action class bean as prototype.
c) Do not forget to setup the database before running this application. It will cause you several exceptions if not setup correctly.
d) Also, please include struts2-spring-plugin
as well in project runtime dependencies.
6) Database Schema Used in Tutorial
Following table has been created in MySQL in database named “test”.
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() );
If you are planning to build the application yourself then below given directly structure used in this application will help you.

And the pom.xml
file used in this project having all project dependencies (some extra) is as below:
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.howtodoinjava.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>
7) Download Sourcecode
Download sourcecode of above example or go for .war file.
That’s all for this spring 4 + struts 2 + hibernate integration tutorial. Let me know of your thoughts and queries.
Happy Learning !!