Struts 2 is a second generation framework used to develop Enterprise web applications by using Model-View-Controller design pattern as its base. More specifically, it works on Pull-MVC design. This is one of the many standard frameworks that help the developers to develop applications from the point of development to building to deployment and testing. Struts 2 have very nice features such as Interceptors, annotation based processing, powerful Object Graph Navigation Language to traverse the framework and taglib support for UI which makes developers life very easy in developing web applications.
Struts 2 framework is developed by apache group. During the initial days of struts, there are many drawbacks of struts which made it to loose attention of many of the developers. In order to make this more elegant for usage, apache struts group joined with Webwork 2 in order to bring Struts 2 into picture. Since webwork 2 was with motto to have a more reliable framework for web developers at the time, combination of webwork 2 with apache struts group gave rise to Struts 2.
Difference between Struts and Struts 2
- Many of the design patterns recommends to program to interfaces rather than abstract classes. Struts 1 main disadvantage lies here. It requires users to program to abstract classes. Struts 2 gained advantage over struts 1 in this area by supporting users to program to interfaces rather than abstract classes. This provided developers to develop applications that can be extended more easily.
- When considering the concurrent programming, Struts 1 is a bad choice. Because, Struts 1 demands action classes to be thread safe as at one time only one action will be available to deal with requests. Struts 2 improved in this aspect as it allows multiple action objects to be created to handle different requests. In this way, struts 2 is more efficient for multi-thread programming.
- The other area where struts 2 is preferred over Struts 1 is in testing the application. If we want to test Struts 1 application through execute method, there is a problem that it exposes the servlets API. But this is not the case with Struts 2 where it can be tested more easily just by instantiating the Action class, setting the required parameters and making the method calls. Additional feature of dependency injection in Struts 2 is an additional attraction.
- Providing input for the Struts 1 applications differ from that of Struts 2 application. In Struts 1 applications, input can be provided to application only through action forms and these action forms also should be subclassed from a base class. This restricts the users to create many different forms to capture different inputs. But in Struts 2, this process is changed such that input can be supplied to the application through configurations called input properties. For example, in Struts 2 application, to supply input, one can make use of taglibs which is more popular in JSP terminology. This is one way and there are many other ways to provide input which is not available in Struts 1 framework
- In order to support the object graph traversal, Struts 1 uses JSTL as tool. JSTL has its own disadvantages which are out of the scope of this article. But Struts 2 make use of OGNL which is particularly designed for object graph traversal and this notation has more advantages than that of JSTL.
- In order to access objects from the application, they should first be binded to the application. This binding happens in Struts 1 directly through the JSP pagecontext. This makes it tightly coupled with the view such that if you want to change it across the application to support multiple views, it becomes difficult. But in Struts 2, the binding of objects happens through ValueStack technology so that objects will be binded through taglibs. This provides less coupling with multiple views thereby allowing developers to provide various input properties which will have same name but different properties and this difference will be identified through taglibs.
- For type conversion, Struts 1 uses bean utils which are fixed for each action class whereas in struts 2 type conversion will be taken care by OGNL which by default contains converters for basic object types as well as primitives.
- Manual validation is supported using validate method of ActionForm which allows to have different validation contexts for same class in Struts 1 but chaining of sub-object validations is not possible. In Struts 2, this validations are supported using validate() method as well as XWork validation framework. This helps to get the chaining of sub-object validations as well as having different validation contexts.
- Even though, Struts 1 supports various different request processors in each module, all the actions present in the module must share the same action lifecycle but in Struts 2, for each action class, different life cycle will be present which is supported by interceptors.
- For viewing purposes, only JSP can be used in Struts 1 but in Struts 2, you can make use of various different view technologies. For example, velocity, FreeMarker can be used to display the results in Struts 2.
Struts Workflow
As we discusses earlier, Struts 2 is built on Model-View-Controller design pattern where the maintenance of data, representation of data and controller are separated apart to make ease of the application maintenance. In Struts 2, these three components of MVC are represented by the following
- Model —– Action
- View —— Result
- Controller —- FilterDispatcher
So, in brief, Struts 2 MVC is represented by three core components Action, Result and FilterDispatcher and the interactions between these three core components are shown in below picture.
Controller
In Struts 2, generally controller is always called as Front Controller as it is the first component that is invoked whenever there is a request. Front controller maps all the requests to actions in the application. In Struts 2, FilterDispatcher acts the role of the Front Controller. This FilterDispatcher is nothing but a Servlet Filter which inspects each of the incoming requests and identify the associated actions of that particular request and then dispatching the request to that particular action class. FilterDispatcher identifies which actions needs to be invoked for requests based on the url pattern of the requests. The mappings of the actions and the url mappings are maintained in the configuration files and FilterDispatcher requests the configuration files to identify the actions that needs to be invoked when a request arrives the application. These configuration files can be both XML files and annotations.
model
In general sense, a model is used to represent the internal state of an application where the business logic as well as data transfer is maintained. This is the heart of any web application and the controller and the view depends completely on the model in order to perform their activities properly.
In Struts 2, Action will play the role of a model. In Action, we will make calls to various methods that constitutes of business logic. Along with maintaining the business logic, the data transfer also is handled by Actions. There can be multiple Action classes present in the application to perform the business logic as promised to the end users.
View
When Front Controller receives the request, identifies appropriate action, and forwards the request to the model (Action). Once the action is executed, action will send its result to the view component. This view component can be anything which is developed using JSP or velocity or FreeMarker etc. The main work of a view involves with converting the state of the application presented to it from action class into the form which is human readable.
The view component in Struts 2 is Result component where the Action will presents its results of execution to the view through this result component. Then the presentation logics will be applied on this result component in order to render result to the end user. This means, the data can be retrieved from result component by JSP or velocity or FreeMarker and then can render to end users in their own way.
Now, with the above background, we can see how the request flow happens in Struts 2
- First, when the request is made to the application, FilterDispatcher is invoked and handed over the request
- FilterDispatcher in turn interacts with AcionMapper to identify which action to invoke for this particular request and dispatches the request to the action
- Before executing the action, the interceptors that are configured on the application will be executed. And then the action is executed.
- Once the action is executed, the result will be sent back through the request in the form of result component
- The request traverses back through the interceptors in the reverse order allowing us to do cleanup activities.
- Finally, the result is sent back to the servlet container which makes use of the result component to render the final output for the user.
- Container can make use of any viewing technology to apply on the result component to render it’s output to the end user.
Setting the environment
Following steps are involved in setting up the environment to run a Struts 2 application
- Setup the Java environment
- Download latest JDK and JRE and install the same
- Set the path of Java in Environment variables. Create JAVA_HOME in environment variable and point it to the JDK home
- Add java path into path system variable
- Setup the tomcat server
- Download latest Tomcat server from here
- Once the server is downloaded and installed, make sure server is running. In services.msc, check for apache tomcat service and if not started, start it
- Check the installation by checking the local url
- If the server is successfully installed and is running, above url will display the welcome page of apache tomcat
- Install Eclipse
- Download the latest eclipse from eclipse official download page
- Install Eclipse and open Eclipse application
- Setup the Struts 2 Framework in eclipse
- Download latest Struts 2 framework from ,<a href=”http://struts.apache.org”>here</a>
- Extract the zip file to any location of your wish
- Add the location of the struts 2 zip file in your environment variable and path system variable
- Inside Struts 2 folder, under lib folder, you will find the jars required for the Struts 2 framework.
- These Struts 2 related jar files needs to be copied in each of the web application you create in Struts 2 using eclipse
- Create a dynamic web project in eclipse
- Choose the option to create the deployment descriptor by default
- Copy all the Struts 2 jars from the Struts 2/lib folder into the WEB-INF/lib folder. This makes the Struts 2 framework available for Eclipse. In these files, make sure the following jar files are present.
- asm.jar
- asm commons
- asm tree
- commons fileupload
- commons io
- commons lang
- freemarker
- javaassist
- ognl
- struts2 core
- xwork core
Struts 2 application components
In this section, we will discuss about various components involved in developing the Strut2 application. A Struts 2 application comprises of two major components i.e., Struts 2 workflow files and configuration files.
Struts 2 work flow Files
Struts 2 work flow files deals with the files for the Model, View and Controller components of the application. Filters also come as part of the application and these filters in Struts 2 application is nothing but the interceptors.
Action
This component represents the Model in the framework. This contains the Business logic as well the logic for data manipulations. There can be many numbers of actions available in an application and the invocation of actions depends on the requirement. For a particular request, a particular action will be mapped through the configuration files and the container is responsible for invoking the appropriate actions through FilterDispatcher. This FilterDispatcher is managed by the servlet container.
Interceptors
Interceptors represent the Filters in a Struts 2 application. These are separate java files that are managed by the application. FilterDispatcher will invoke the Interceptors before executing the action logic. The information of the Interceptors will be configured in the configuration files and will be invoked in the order defined in the configuration files. This separation of Interceptors or filters from the business logic enables the developers to develop any number of filters they want and allows them to specify the order in which they are invoked. The order is ensured by chaining concept.
Results and Result Types
This is the component that represents the result of the execution to the end user. When the action execution is completed, the information that needs to be communicated to the end user will be moulded as result component and this component is communicated back to the container through the request object itself. Once the container receives the request back once the action is executed, it retrieves the result component and then make use of various viewing technologies such as JSP or velocity or FreeMarker to parse the result component and then render the result to the end user.
Static files to represent view
These can be the static files such as JSP pages or Velocity templates or FreeMarker templates which manipulate the result component, retrieve the required information from the result object, build the result pages for the user and then these result pages are communicated back to the end user.
Configuration Files.
While developing a Struts 2 application, following configuration files are involved. Each configuration file serves a particular purpose. We will discuss about each of the configuration files and their uses and how they will be used in developing a Struts 2 application.
Web.xml
This is the main deployment descriptor file for entire web application. If any input needs to be provided to the application before executing any of the application, this is the place to specify those input parameters through initialization tags. Apart from providing the input parameters for startup, we will specify the mapping of the interceptors of the application through filter tag. This is the location where will map the filters to their appropriate interceptor classes and also to specify the url patterns for those interceptors. Also this is the location where will specify about the welcome files and the error pages as well.
Struts.xml
In order to initialize the initial resources of a struts application such as packages, actions and interceptors, in Struts.xml file we will specify the configurations. This is the place where will write the action mappings. We will write the connections between the view components and actions in this file. That is, we will specify which view file needs to be used to display the result of a particular action here. The specification includes the action class name through the tag “action” and we will specify the view file name through the tag “result”. These two tags goes together under the package tag. Struts.xml file is the configuration file used for all the action mappings and is used in Strut 2 framework. Struts-config.xml file is the one which is used for the same purpose but is used by Struts 1 framework. Latest struts 2 framework is not using this file anymore. But as simple note to remind, Struts.xml and Struts-config.xml both are same. This file will be placed under WEB-INF/classes folder of your web application.
Struts.properties
This is the file where we will define some of the struts properties. If we want to create customized configurations for our struts 2 application, then we can override the default configuration properties in this file. This is the place where you can set your locale as well as encoding scheme. We can specify the autowiring property for SpringObjectFactory in this file. Object type determiner can also be specified in Struts.properties file. We can specify the parser for the HTTP post requests. MIME types also can be configured in this properties file. Even we can load the custom property files by configuring them in this properties file. Sample properties that can be configured through this file are specified below. There are sample properties only and many more can be configured. This file will be placed under WEB-INF/classes folder of your web application.
struts.configuration.xml.reload=false struts.i18n.reload=true struts.custom.i18n.resources=global struts.enable.DynamicMethodInvocation=false
log4j.xml
This is the file which is used to configure the logger properties for your application. This file will be placed under WEB-INF/classes directory. The sample code of this file will be as follows.
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration PUBLIC "-//log4j/log4j Configuration//EN" "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="STDOUT" class="org.apache.log4j.ConsoleAppender" > <layout class="org.apache.log4j.PatternLayout" > <param name="ConversionPattern" value="%d %-5p %c.%M:%L - %m%n" /> </layout> </appender> <!-- specify the logging level for loggers from other libraries --> <logger name="logger" > <level value="DEBUG" /> </logger> <logger name="org.apache.struts2" > <level value="DEBUG" /> </logger> <!-- for all other loggers log only debug and above log messages --> <root> <priority value="INFO" /> <appender-ref ref="STDOUT" /> </root> </log4j:configuration>
Sample application
To illustrate the topics we discussed so far, we will develop a sample application to maintain the Online Book library. In this application, we will have the interface for adding a new book into online book library, updating the information of the existing information of a book in the library, and deleting a particular book available in the Online book library. In the process of developing the application, first we will develop the struts 2 work flow files and then develop the static pages and then the configuration files. Once all the components are developed, they are clubbed together into a web application, deploy it and test the application. In this application, we mainly focus on illustrating the DispathAction Functionality since we can differentiate it’s usage between Struts 1 and Struts 2 frameworks.
Before starting to develop the application, first create a dynamic web project as specified earlier and select the option of creating the default deployment descriptor that is web.xml and specify tomcat server as the target run time platform to run the application.
Create a package called StrutsApplication and maintain all your source files under this package. Maintain all your configuration files as specified in the above sections. Add all the required struts 2 framework jars files in the WEB-INF/lib folder of your application. Now you are set to develop the application.
Develop business logic files
In our application, we will have only one class that represents the Model of the framework. Create a class file and name it as “OnlineBookAction”. For this class to implement, we need ActionSupport class and this class will come by default in the Struts 2 core jar files. Copy below code into this class.
package StrutsApplication; import com.opensymphony.xwork2.ActionSupport; public class OnlineBookAction extends ActionSupport{ private String message; public String addBook() { // Logic involved to insert the information of book into the Online library // message represents the result of this action. If book is added successfully, message says // Book added or else message says Book is not added as it already is there in the library message = "Book added"; or message = "Book already exists" return SUCCESS; } public String updateBook() { // Logic involved to update the information of book into the Online library // message represents the result of this action. If book is updated successfully, message says //Book info updated or else message says Book is not available in the library message = "Book updated"; or message = "Book doesn't exists" return SUCCESS; } public String deleteBook() { // Logic involved to remove book from the Online library // message represents the result of this action. If book is deleted successfully, message says //Book removed or else message says Book is not available in the library message = "Book removed"; or message = "Book doesn't exists" return SUCCESS; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
In the above application, all the functions of the application are coded in the same action class and based on the configurations; the appropriate methods will be invoked as per the configuration. Here we define different methods to add the book, update the book and delete the book. These method names will be configured in the configuration file such that required methods will be invoked based on the request made. In Struts 1 application, this DynamicDispatch functionality is used to group all the required methods in one action class and we need to specify them manually but in Struts 2 application, once it is defined in the configuration file, then those methods will be provided by the framework by default. Developer just has to provide their implementations in the appropriate methods. In Struts 2 application, even we can have executed method apart from all other methods which is not the case in Struts 1 application.
Develop static files to represent view
In this application, we need two static pages one for the main page where user will see controls for interacting with the application and the other page to display the results. Main interaction page is index.jsp and the result page is success.jsp
index.jsp
Create a jsp page under webContent folder and paste the following code into it.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <%@taglib uri="/struts-tags" prefix="s" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Insert title here</title> </head> <body> <s:form action="Book" > <s:submit /> <s:submit action="addBook" value="Add Book" /> <s:submit action="updateBook" value="Update Book" /> <s:submit action="deleteBook" value="Delete Book" /> </s:form> </body> </html>
success.jsp
Create a jsp file under WebContent folder and name it as success.jsp and then copy below code into it.
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!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=ISO-8859-1"> <title>Online book library</title> </head> <body> ${message} </body> </html>
Once we develop the Struts 2 work flow files and view files, we need to create the configuration files to connect these files. Create the following files in the project.
Web.xml
This file will be automatically created when the project is created. Modify this file to have the following content. Here we will map the filters to the urls of the incoming requests. This is the place where we will configure the interceptors also.
<?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_2_5.xsd" id="WebApp_ID" version="2.5"> <display-name>Struts Applicatiom</display-name> <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> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
Struts.xml
This is the main file where we will configure the action mappings. Create the Struts.xml file and place it under WEB-INF/classes folder. Copy below content into this file.
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts> <package name="default" extends="struts-default"> <action name="addBook" method="addBook" class="StrutsApplication.OnlineBookAction"> <result name="success">/success.jsp</result> </action> <action name="updateBook" method="updateBook" class="StrutsApplication.OnlineBookAction"> <result name="success">/success.jsp</result> </action> <action name="deleteBook" method="deleteBook" class="StrutsApplication.OnlineBookAction"> <result name="success">/success.jsp</result> </action> </package> </struts>
Now, we are set with all the components of the application. Build the complete application and build the WAR file.
Deploy
When build in the Eclipse, the WAR file will be created automatically. When the application is selected to run, this WAR file will be automatically deployed and is used for the execution.
Execute the application
To run the application in eclipse, select the project, rightclick and select the run as option. Under this option, select the Tomcat server where application needs to be executed. If tomcat is not running, this action will start the server automatically, WAR will be deployed and then application will run.