A Struts 2, Spring, and Hibernate Example Application
Introduction
I was learning Hibernate as another methodology for storing my Java objects' state in a data repository. I wanted to experiment with integrating Hibernate into a Struts 2 and Spring application so I created an example of using the three technologies together. The combination of these three frameworks enables Java developers to create powerful web applications with a minimum of code.
Example Application
Download the example application.
The example application was created using Eclipse 3.5 with the Maven 2 plugin. The JDK used was JVM 1.6 on the Mac. The application uses Maven to manage its Jar dependencies. Please note the example application is partially based on one of the Hibernate examples provided in Cameron McKenzie's excellent Hibernate Made Easy book.
The application uses an in-memory database (HSQL) that is setup by the Spring applicationContext.xml class. See files schema.sql and test-data.sql in src/main/resources for the schema created during the application's startup and the initial records inserted into the table's database. Using the in-memory database means there is no need to setup and run a separate database server for the example application.
You can import this project into Eclipse by using Eclipse's File - Import feature. In the project's root folder is a README.txt file that explains how to run the application.
NOTE the example application was updated in October 2010 to use the latest versions of the Struts and Spring jars and to use Spring 3.0's ability to create an in-memory HSQL database.
If you're not using Eclipse 3.5 with the Maven 2 plugin, you can unzip the archived download and view the source code in any text editor. If you are using a Java IDE that enables importing of Maven projects you should be able to import the unzipped project.
You can also run the application using Maven directly if you have downloaded and installed Maven on your computer. Open a terminal (command) window and navigate to the project's root folder (the folder where pom.xml resides). Then in the terminal window issue these commands:
mvn clean
mvn test (All 7 tests should pass successfully).
mvn jetty:run
When you see [INFO] Started Jetty Server open a web browser and navigate to http://localhost:8080/Struts2_Spring_Hibernate_Example/index.html
To stop the Jetty web server type CTRL-C in the terminal window.
Implementing Hibernate
To implement Hibernate, I use the Java Persistence API (JPA) annotations (@Entity, @Column, @Table, etc) to provide Hibernate the information it needs to map my model object to a table and columns in the database schema. I also have my Data Access Object (DAO) extend Spring's HibernateDaoSupport class so that I can easily inject a Hibernate SessionFactory into the DAO. I also use Spring's @Transactional annotation to mark the methods of my DAO as occurring in a single transaction.
Note there are several different ways to integrate Spring and Hibernate. My example's methodology may not be the best one. Consult the Spring references below for other ways to use Spring and Hibernate together.
Integrating Struts 2, Spring, and Hibernate
The key to effectively using Struts 2 with Hibernate is to properly layer (Presentation, Action, Service, DAO) your application. In my example, the Struts 2 ActionSupport classes are ignorant of how Java objects are provided. The Struts 2 ActionSupport class makes calls to a Service class (injected by Spring). The Service class makes calls to the DAO class (injected by Spring) which uses Hibernate to get data out of and into the data repository and to translate the data into and out of Java objects.
All concrete classes implement an Interface and any class referenced as part of another class is referenced by its Interface type. This makes the overall application easier to maintain, test, and enhance in the future.
The concrete HibernateDaoSupport classes receive their Hibernate SessionFactory objects injected by Spring. The SessionFactory object receives its DataSource object injected by Spring. See the Spring applicationContext.xml for the creation of these Spring-managed beans.
Summary
There is a steep learning curve in becoming comfortable using these complex frameworks. You're not going to learn Struts 2, Spring, and Hibernate overnight. Leveraging these technologies requires studying good books, online references, and example applications. The references I've listed below, are ones I've found useful in learning Struts 2, Spring, and Hibernate.
Of course this blog article is not going to be able to teach anyone everything (anything?) involved in integrating these three technologies. Consult the references below for where to go to learn more. I do hope my example application will be useful to others learning Hibernate and who want to integrate Hibernate into a Struts 2 and Spring application.
References:
- Hibernate Made Easy, Cameron McKenzie, 2008, http://www.hiberbook.com/
- Hibernate Documentation, https://www.hibernate.org/5.html
- Spring Recipes (chapter 9), Gary Mak, 2008 Apress, http://www.apress.com/book/view/9781590599792
- Pro Spring 2.5 (chapter 11), Jan Machacek, Aleksa Vukotic, and others, 2008 Apress, http://www.apress.com/book/view/9781590599211
- Spring Framework - http://www.springsource.org/documentation
- Spring Community Forums - http://forum.springsource.org/
- Introduction to the Spring Framework 2.5 - http://www.theserverside.com/tt/articles/article.tss?l=IntrotoSpring25
- Spring in Action, 2nd Edition, Manning Publishing, August 2007
- Struts 2 Framework - http://struts.apache.org
- Using Struts 2 and Spring Frameworks Together, Bruce Phillips Blog - http://www.brucephillips.name/blog/index.cfm/2008/10/17/Using-Struts-2-and-Spring-Frameworks-Together
- Struts 2 In Practice, Manning Publishing, http://www.manning.com/wannemacher/
- Apache Struts 2 Documentation, Spring Plugin - http://struts.apache.org/2.x/docs/spring-plugin.html
- Struts 2 In Action, Donald Brown, 2008 Manning, http://www.manning.com/dbrown/
- Apache Struts 2 Web Application Development, Dave Newton, 2009 Packt, http://www.packtpub.com/apache-struts-2-web-application-development-beginners-guide/book
- Struts User Forum - http://www.nabble.com/Struts---User-f206.html
- Maven - http://maven.apache.org/
- Maven - http://books.sonatype.com/maven-book/index.html

I hope to have a web someday and to be able to give at least a small part o what I've learned.
Thank you! maintain that attitude! Sorry if my english sucks!
I downloaded it from http://download.java.net/maven/2/javax/transaction..., made mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B -Dpackaging=jar -Dfile=/download_path/jta-1.0.1B.jar, and now is working from command line.
Thank you very much.
If anyone has any issues with the download please let me know.
Bruce
first of all thank you for sharing knowledge.
I'm curious, how would u implement localization in this example?
I'm asking because afaik this is only way to getText() method working properly, but
on expense of localization via request_locale parameter.
On other hand i might be missing something due to being newbie to spring and i'd be glad to get some hints.
Thank you & Best regards
Miha
wrong with the spring imp on applicationContext.xml. would be good
if someone can help fixing it.
Thanks very much for your example. I have downloaded it but when I run it on Tomcat by Run As -> Run on Server. I got this exception. Would you like to have a look at this one? Thanks very much.
2011-08-05 20:08:55,097 ERROR org.springframework.web.context.ContextLoader.initWebApplicationContext:220 - Context initialization failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0' defined in class path resource [applicationContext.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IncompatibleClassChangeError: Implementing class
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:527)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.context.support.AbstractApplicationContext.registerBeanPostProcessors(AbstractApplicationContext.java:710)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:410)
at org.springframework.web.context.ContextLoader.createWebApplicationContext(ContextLoader.java:276)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:197)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:47)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4205)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4704)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.IncompatibleClassChangeError: Implementing class
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1420)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:291)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:288)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:398)
at org.springframework.beans.factory.BeanFactoryUtils.beansOfTypeIncludingAncestors(BeanFactoryUtils.java:275)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.detectPersistenceExceptionTranslators(PersistenceExceptionTranslationInterceptor.java:122)
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.<init>(PersistenceExceptionTranslationInterceptor.java:78)
at org.springframework.dao.annotation.PersistenceExceptionTranslationAdvisor.<init>(PersistenceExceptionTranslationAdvisor.java:70)
at org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor.setBeanFactory(PersistenceExceptionTranslationPostProcessor.java:96)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeAwareMethods(AbstractAutowireCapableBeanFactory.java:1439)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1408)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519)
... 25 more
Caused by: java.lang.IncompatibleClassChangeError: Implementing class
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:632)
at java.lang.ClassLoader.defineClass(ClassLoader.java:616)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at org.apache.catalina.loader.WebappClassLoader.findClassInternal(WebappClassLoader.java:2818)
at org.apache.catalina.loader.WebappClassLoader.findClass(WebappClassLoader.java:1159)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1647)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2389)
at java.lang.Class.getConstructor0(Class.java:2699)
at java.lang.Class.getDeclaredConstructor(Class.java:1985)
at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:104)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.newConfiguration(LocalSessionFactoryBean.java:779)
at org.springframework.orm.hibernate3.LocalSessionFactoryBean.buildSessionFactory(LocalSessionFactoryBean.java:561)
at org.springframework.orm.hibernate3.AbstractSessionFactoryBean.afterPropertiesSet(AbstractSessionFactoryBean.java:134)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1477)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1417)
... 40 more
I then ran mvn package to create the war file. I moved the war file to Tomcat webapps and started up Tomcat. I get the same error as you.
I updated the Hibernate dependency to 3.5.6-Final, re-ran mvn clean package. I deployed the new war file to tomcat and everything worked.
So I think the previous version may have caused a class-loader issue with Tomcat but not Jetty.
I uploaded a new zip so download that one and give it a try.
Bruce
I ran mvn package to create a war file and deploy it to Tomcat 6. There was no problem.
But when I tried to run in Eclipse with Debug As -> Debug on Server, I got below errors. It seemed the classes/lib could not be deployed to Tomcat in this way. Do you have any idea? Thanks.
Oct 1, 2011 3:00:24 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Error configuring application listener of class org.springframework.web.context.ContextLoaderListener
java.lang.ClassNotFoundException: org.springframework.web.context.ContextLoaderListener
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4149)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
Oct 1, 2011 3:00:24 AM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Error configuring application listener of class org.springframework.web.context.request.RequestContextListener
java.lang.ClassNotFoundException: org.springframework.web.context.request.RequestContextListener
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1680)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1526)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4149)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4705)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:840)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1057)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:463)
at org.apache.catalina.core.StandardService.start(StandardService.java:525)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:754)
at org.apache.catalina.startup.Catalina.start(Catalina.java:595)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:289)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:414)
mvn -e eclipse:eclipse -Dwtpversion-1.5
Then open the project up in an Eclipse workspace. By default there are problems between Eclipse's Web Tools Project and Maven.
BTW, there was a typo that the sign after -Dwtpversion should be '=' instead of '-'.
Eric
thanks for the tutorial. Can you please let me know how to configure this to connect to a MYSQL DB?
thanks
See section 12.3. Controlling database connections and if you want to use a JNDI reference see C.2.3. The jee schema.