Struts2 Integration with Tiles2 & Spring3

In this tutorial we will discuss about Tiles Framework and its Integration with Struts2. We will add Tiles support to our previous Struts application with Spring 3 that we created in previous parts. I strongly recommend you to go through previous articles and download the source code of our sample application.

Introduction to Tiles 2:
Nowadays, website are generally divided into pieces of reusable template that are being rendered among different web pages. For example a site containing header, footer, menu etc. This items remains same through out the website and give it a common look and feel. It is very difficult to hard code this in each and every webpage and if later a change is needed than all the pages needs to be modified. Hence we use templatization mechanism. We create a common Header, Footer, Menu page and include this in each page.

Tiles Plugin allow both templating and componentization. In fact, both mechanisms are similar: you
define parts of page (a "Tile") that you assemble to build another part or a full page. A part can
take parameters, allowing dynamic content, and can be seen as a method in JAVA language. Tiles is a templating system used to maintain a consistent look and feel across all the web pages of a web application. It increase the reusability of template and reduce code duplication.

A common layout of website is defined in a central configuration file and this layout can be extended across all the webpages of the web application.
Our Application Layout
Our goal is to add Header, Footer, Menu and Body to our Struts2TilesIntegration application. Following will be the layout of the same.
There are following tool we need to create this application.
1. Strus2
2. Spring3
3. STS or Eclipse
4. Tiles 2

In this example we will using the three frameworks Struts2, Spring3 and Tiles2 with Internationalization in one application.
Step 1: Project Structure-
Step 2: There are following jars file need to be add
commons-beanutils-1.8.0.jar
commons-digester-2.0.jar
commons-fileupload-1.2.1.jar
commons-io-1.3.2.jar
commons-lang-2.4.jar
commons-lang3-3.1.jar
commons-logging-1.0.4.jar
commons-logging-api-1.1.jar
freemarker-2.3.18.jar
javassist-3.0.jar
ognl-3.0.4.jar
spring-asm-3.0.1.RELEASE.jar
spring-beans-3.0.1.RELEASE.jar
spring-context-3.0.1.RELEASE.jar
spring-core-3.0.1.RELEASE.jar
spring-expression-3.0.1.RELEASE.jar
spring-jdbc-3.0.1.RELEASE.jar
spring-orm-3.0.1.RELEASE.jar
spring-tx-3.0.1.RELEASE.jar
spring-web-3.0.1.RELEASE.jar
spring-webmvc-3.0.1.RELEASE.jar
struts2-core-2.3.1.2.jar
struts2-dojo-plugin-2.3.15.jar
struts2-spring-plugin-2.3.15.jar
struts2-tiles-plugin-2.3.15.jar
tiles-api-2.0.6.jar
tiles-compat-3.0.1.jar
tiles-core-2.0.6.jar
tiles-jsp-2.0.6.jar
tiles-servlet-3.0.1.jar
xwork-core-2.3.1.2.jar
Step 3: Struts 2 + Spring 3+ Tiles Plugin
To integrate Struts 2 and Spring, get and include the "struts2-spring-plugin-xxx.jar" and "struts2-tiles-plugin-xxx.jar" library into your project classpath. As already added above struts2-spring-plugin-2.3.15.jar and struts2-tiles-plugin-2.3.15.jar.

Step 4: Tiles Listener and Spring Listener
Configure the Spring listener "org.springframework.web.context.ContextLoaderListener" and Tiles Listener "org.apache.struts2.tiles.StrutsTilesListener" in web.xml file.

Configuring Tiles in 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 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
  <display-name>Struts2TilesIntegration</display-name>
  <welcome-file-list>
        <welcome-file>user</welcome-file>
    </welcome-file-list>
    <context-param>
    <param-name>
       org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG
    </param-name>
    <param-value>
       /WEB-INF/tiles-def.xml
    </param-value>
   </context-param>
   <listener>
      <listener-class>
         org.springframework.web.context.ContextLoaderListener
      </listener-class>
   </listener>
   <listener>
       <listener-class>
        org.apache.struts2.tiles.StrutsTilesListener
       </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>
The above code configure Tiles listener in web.xml. An input configuration file /WEB-INF/tiles-def.xml is passed as argument. This file contains the Tiles definition for our web application.
Step 4: Create a file tiles-def.xml in WEB-INF folder and copy following code into it.
<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE tiles-definitions PUBLIC
   "-//Apache Software Foundation//DTD Tiles Configuration 2.0//EN"
   "http://tiles.apache.org/dtds/tiles-config_2_0.dtd">

<tiles-definitions>

   <definition name="mainTemplate" template="/mainTemplate.jsp">
      <put-attribute name="title"  value="User Registration Form"/>
      <put-attribute name="header" value="/header.jsp"/>
      <put-attribute name="menu"   value="/menu.jsp"/>
      <put-attribute name="body"   value="/body.jsp"/>
      <put-attribute name="footer"   value="/footer.jsp"/>
   </definition>

   <definition name="alia" extends="mainTemplate">
      <put-attribute name="title"  value="Alia Bhatt"/>
      <put-attribute name="body"   value="/alia.jsp"/>      
   </definition>

   <definition name="madhuri" extends="mainTemplate">
      <put-attribute name="title"  value="Madhuri Dixit"/>
      <put-attribute name="body"   value="/madhuri.jsp"/>      
   </definition>
   
   <definition name="success" extends="mainTemplate">
      <put-attribute name="title"  value="User Added Successfully"/>
      <put-attribute name="body"   value="/success.jsp"/>      
   </definition>
  
</tiles-definitions>
Here in tiles-def.xml we have define a template mainTemplate. This layout contains attributes such as Header, Title, Body, Menu and Footer. The layout is then extended and new definitions for alia, madhuri and success page is defined. We have override the default layout and changed the content for Body and Title.
Step 5:  Creating JSPs
We will define the template for our web application in a JSP file called mainTemplate.jsp. This template will contain different segments of web page (Header, Footer, Menu etc). Create 4 new JSP files mainTemplate.jsp, header.jsp, menu.jsp, body.jsp, madhuri.jsp, alia.jsp, success.jsp and footer.jsp and copy following content in each of them.
mainTemplate.jsp
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
   "http://www.w3.org/TR/html4/loose.dtd">
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title><tiles:insertAttribute name="title" ignore="true"></tiles:insertAttribute>
</title>
</head>

<body>
  <table border="1">
   <tr>
    <td colspan="2"><tiles:insertAttribute name="header"></tiles:insertAttribute><br/></td>
   </tr>
   <tr>
    <td><tiles:insertAttribute name="menu" /></td>
    <td><tiles:insertAttribute name="body" /></td>
   </tr>
   <tr>
    <td colspan="2"><tiles:insertAttribute name="footer" /></td>
   </tr>
  </table>
</body>
</html>
body.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<style type="text/css">
b{color:navy; background-color: orange;}  
</style>
<title>Struts2-Spring-Tiles integration | dineshonjava.com</title>
</head>
<body>

 <h2>Add User</h2><b>
    <s:form  action="addUsermenu">
    <s:textfield name="userName" key="user.name" />
    <s:textfield name="userAge" key="user.age" value=""/>
    <s:radio name="userGender" key="user.gender" list="{'Male','Female'}" />
    <s:select name="userJob"  key="user.job" list="%{#{'Software':'Software','Hardware':'Hardware','Networking':'Networking','Marketing':'Marketing'}}"/>  
    <s:checkboxlist name="userHobbies" key="user.hobby" list="{'Cricket','Football','Drawing','Cooking','Driving','Movie'}" />  
    <s:submit key="submit" align="center"/>
 </s:form>
 </b>
</body>
</html>
header.jsp
<table>
  <tr>
   <td><img src="http://2.bp.blogspot.com/-rBLnvKuVDO0/UWBnJJ4n1yI/AAAAAAAADCQ/Vh_cVJ34JFw/s1600/new-logo.png" /></td>
    <td><h1><span style="background-color: #FFFFcc">Struts2-Tiles-Spring integration</span></h1></td>
  </tr>
</table>
footer.jsp
<center><p><h2>Copyright &copy; 2013 dineshonjava.com</h2></p> </center>
menu.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
 <a href="<s:url action="usermenu"/>"> <h2>Add User</h2></a><br>
 <a href="<s:url action="aliamenu"/>"><h2>Alia Bhatt</h2></a><br>
    <a href="<s:url action="madhurimenu"/>"><h2>Madhuri Dixit</h2></a><br>

success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
 pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" 
"http://www.w3.org/TR/html4/loose.dtd">

<html>
<head>
<title>Struts2-Spring-Tiles integration | dineshonjava.com</title>
</head>
<body>

 <h2>List of User</h2>
    <ul>
   <li>User Name : <s:property value="userName" /></li>
   <li>User Age : <s:property value="userAge" /></li>
   <li>User Gender : <s:property value="userGender" /></li>
   <li>User Jobs : <s:property value="userJob" /></li>
   <li>User Hobbies : <s:property value="userHobbies" /></li>
 </ul> 
</body>
</html>
madhuri.jsp
<img src="http://www.topnews.in/files/Madhuri-Dixit_10.jpg" height="430" width="500" alt="Madhuri Dixit"/>
alia.jsp
<img src="http://cdntopics.onepakistan.com/wp-content/uploads/2012/10/Alia-Bhatt1.jpg" alt="Alia Bhatt"/>
Step 6: Register Spring Bean
Register all the Spring’s Beans in the applicationContext.xml file, the Spring listener will locate this xml file automatically.
applicationContext.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:context="http://www.springframework.org/schema/context"
 xmlns:tx="http://www.springframework.org/schema/tx"
 xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">

 <context:component-scan base-package="com.dineshonjava.struts2.bean" />
 <bean id="user" class="com.dineshonjava.struts2.action.UserAction">
   </bean>
   <bean id="userBean" class="com.dineshonjava.struts2.bean.UserBean">
   </bean>
</beans>
Step 7: Create Action class and User bean.
UserAction.java
package com.dineshonjava.struts2.action;

import org.springframework.beans.factory.annotation.Autowired;

import com.dineshonjava.struts2.bean.UserBean;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

/**
 * @author Dinesh Rajput
 *
 */
public class UserAction extends ActionSupport implements ModelDriven<UserBean>{

 private static final long serialVersionUID = 1L;
 
 @Autowired
 private UserBean userBean;

 public String execute()
 {
  return "user";
 }
 
 public String addUser()
 {
  return "addUser";
 }
 
 @Override
 public UserBean getModel() {
  return userBean;
 }
 public String alia() { 
  return "alia";
 }
 public String madhuri() { 
  return "madhuri"; 
 }
 public String user() { 
  return "user"; 
 }
}

Here userBean property autowired with action class UserAction java it is also powerfull feature of Spring framework.
UserBean.java

package com.dineshonjava.struts2.bean;

/**
 * @author Dinesh Rajput
 *
 */
public class UserBean {
 private String userName;
 private int userAge;
 private String userGender;
 private String userJob;
 private String []userHobbies;
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public int getUserAge() {
  return userAge;
 }
 public void setUserAge(int userAge) {
  this.userAge = userAge;
 }
 public String getUserGender() {
  return userGender;
 }
 public void setUserGender(String userGender) {
  this.userGender = userGender;
 }
 public String getUserJob() {
  return userJob;
 }
 public void setUserJob(String userJob) {
  this.userJob = userJob;
 }
 public String[] getUserHobbies() {
  return userHobbies;
 }
 public void setUserHobbies(String[] userHobbies) {
  this.userHobbies = userHobbies;
 }
 
}
Step 8: Modifications in Struts.xml
In struts.xml we defined result tag which maps a particular action with a JSP page. Now we will modify it and map the result with Tiles. Following will be the content of struts.xml file.
<?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>
    <constant name="struts.enable.DynamicMethodInvocation" value="false" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.custom.i18n.resources" value="myapp" />
 
 <package name="user" extends="struts-default" namespace="/">
        <result-types>
         <result-type name="tiles" class="org.apache.struts2.views.tiles.TilesResult" />
       </result-types>
        <action name="user" class="user" method="execute">
            <result name="user" type="tiles">mainTemplate</result>
        </action>
        <action name="*menu" class="user" method="{1}">
            <result name="user" type="tiles">mainTemplate</result>
            <result name="madhuri" type="tiles">madhuri</result>
            <result name="alia" type="tiles">alia</result>
            <result name="addUser" type="tiles">success</result>
        </action>
    </package>
 </struts>

Let us check what we did in above file. First of all, we declared a new result type called "tiles" as we are now using tiles instead of plain jsp for the view technology. Struts2 has its support for the Tiles View result type, so we create the result type "tiles" to be of the "org.apache.struts2.view.tiles.TilesResult" class.

The struts.xml now defines a new Result type for Tiles. This result type is used in <result> tag for different actions. Also note that we have define a new action user. This is just an empty declaration to redirect user to user form page when she clicks Add User link from menu.

Next, we want to say if the request is for /usermenu.action take the user to the mainTemplate tiles page and if the request is for /madhurimenu.action take the user to the madhuri tiles page.

We achieve this using a bit of regular expression. In our action definition, we say anything that matches the pattern "*menu" will be handled by this action. The matching method will be invoked in the UserAction class. That is, aliamenu.action will invoke alia() and madhurimenu.action will invoke madhuri(). We then need to map the outcome of the result to the appropriate tiles pages.

myapp.properties

user.name=User Name
user.age=User Age
user.gender=Gender
user.job=Job Type
user.hobby=Hobbies
submit=Add User

Now right click on the project name and click Export > WAR File to create a War file. Then deploy this WAR in the Tomcat's webapps directory. Finally, start Tomcat server and try to access

URL http://localhost:8080/doj/user

This will give you following screen:


Fill the user form and click on "Add User" button we will get the following page.
http://localhost:8080/doj/addUsermenu.action


Click on the Madhuri Dixit link from menu then we will get the following screen.
http://localhost:8080/doj/madhurimenu.action


Click on the Aalia Bhatt link from menu then we will get the following screen.
http://localhost:8080/doj/aliamenu.action




Download Source Code + Libs
Struts2Tiles2Spring3Integration.zip



<<Previous <<   || Index ||   >>Next >>



4 comments:

  1. That is really great!!!!! thank you so much for the source!!! cheers!!!!!!
    -Dhirajkumar Rameshchand Jaiswal
    +919867460266

    ReplyDelete
  2. why i run this sample it has error like this?

    Unable to load configuration. - action - file:/D:/jeeproject/.metadata/.me_tcat/webapps/S2S3T2Integrate/WEB-INF/classes/struts.xml:15:58

    how could i solve it?

    ReplyDelete
    Replies
    1. Raise error like this:

      Unable to load configuration. - action - file:/D:/jeeproject/.metadata/.me_tcat/webapps/S2S3T2Integrate/WEB-INF/classes/struts.xml:15:58
      at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:428)
      at org.apache.struts2.dispatcher.ng.InitOperations.initDispatcher(InitOperations.java:69)
      at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(StrutsPrepareAndExecuteFilter.java:51)
      at org.apache.catalina.core.ApplicationFilterConfig.getFilter(ApplicationFilterConfig.java:275)
      at org.apache.catalina.core.ApplicationFilterConfig.setFilterDef(ApplicationFilterConfig.java:397)
      at org.apache.catalina.core.ApplicationFilterConfig.(ApplicationFilterConfig.java:108)
      at org.apache.catalina.core.StandardContext.filterStart(StandardContext.java:3693)
      at org.apache.catalina.core.StandardContext.start(StandardContext.java:4340)
      at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:791)
      at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:771)
      at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:525)
      at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:920)
      at org.apache.catalina.startup.HostConfig.deployDirectories(HostConfig.java:883)
      at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:492)
      at org.apache.catalina.startup.HostConfig.start(HostConfig.java:1138)
      at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:311)
      at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1053)
      at org.apache.catalina.core.StandardHost.start(StandardHost.java:719)
      at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
      at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
      at org.apache.catalina.core.StandardService.start(StandardService.java:516)
      at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
      at org.apache.catalina.startup.Catalina.start(Catalina.java:566)
      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:288)
      at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
      Caused by: Unable to load configuration. - action - file:/D:/jeeproject/.metadata/.me_tcat/webapps/S2S3T2Integrate/WEB-INF/classes/struts.xml:15:58
      at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:69)
      at org.apache.struts2.dispatcher.Dispatcher.init_PreloadConfiguration(Dispatcher.java:371)
      at org.apache.struts2.dispatcher.Dispatcher.init(Dispatcher.java:415)
      ... 29 more
      Caused by: Action class [user] not found - action - file:/D:/jeeproject/.metadata/.me_tcat/webapps/S2S3T2Integrate/WEB-INF/classes/struts.xml:15:58
      at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.verifyAction(XmlConfigurationProvider.java:420)
      at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addAction(XmlConfigurationProvider.java:365)
      at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.addPackage(XmlConfigurationProvider.java:479)
      at com.opensymphony.xwork2.config.providers.XmlConfigurationProvider.loadPackages(XmlConfigurationProvider.java:275)
      at org.apache.struts2.config.StrutsXmlConfigurationProvider.loadPackages(StrutsXmlConfigurationProvider.java:111)
      at com.opensymphony.xwork2.config.impl.DefaultConfiguration.reloadContainer(DefaultConfiguration.java:204)
      at com.opensymphony.xwork2.config.ConfigurationManager.getConfiguration(ConfigurationManager.java:66)

      Delete