Struts Framework – Using Custom Class as Struts Action Controller

**adsense_4x1Block**
Introduction:



In this struts framework tutorial we will customize default Struts Action’s configuration so that it will use our custom java class to process the request and then navigate user back to appropriate page.


Along the way, we will also set folder structure of basic Struts Project so that it can be extended for larger complex projects with ease in future. Also a basic example of Model-View-Controller (MVC) design pattern will be implemented so that you can identify different components of a Struts Project going on forward.


Near the end we will have a taste of Struts Tags library to easily access variables defined within Action handler.


In case at any point during this tutorial you are confused about how things are working, you are highly recommended to read this Hello World! – Struts Framework Tutorial first, to develop an understanding of basic flow of Struts Application.



Tutorial’s Technology Stack:

Struts – 2.2.3
Eclipse – Helios



Download Starting Code:

Tutorial Starting Code: Download

How to Use: create a blank Dynamic Web Project using Eclipse naming “Tut-StrutsWithCustomAction”, and copy contents of this download to it. Refresh project in Eclipse and deploy on tomcat server to run this web application.



Step 1: Understanding Course of Action

The starting code for this tutorial has a simple navigation case implemented having two JSPs and two default Actions defined in strtus.xml against them.

We learned in Hello World tutorial that if ‘class’ attribute is not defined for Action tag in struts.xml, then by default com.opensymphony.xwork2.ActionSupport class is invoked in background which simply returns a success message. This success message is used by ‘result’ tag (default behavior again) to load page defined in it.

1
2
3
<action name="hello">
	<result>/jsp/hello.jsp</result>
</action>

What we will achieve in this tutorial is to override the default behavior of ‘action’ tag in order to use our Custom class. This way we can work with our Model objects, perform action, store information and return a custom View, thus practicing the complete MVC flow.



Step 2: Setting folder structure for Struts Project

We will organize our custom classes so that Struts Project’s folder structure remains maintainable as the project grows. Idea is to separate all Action controllers in action package, and model classes in model package. So let’s create Model and Action classes in next steps, their package names will setup the required folder structure.



Step 3: Creating Model Class

We will create a basic class to mimic a Model object, so that we can see how Model objects are going to be used in custom Action controllers of a Struts based web application.

Create a class (Right click on Project > New > Class) with following lines of code with package ‘sawan.hello.model’ and name ‘MessageStore’, leaving everything else as default. (The class implementation is borrowed from Apache Struts Tutorial written originally by Bruce Phillips).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package sawan.hello.model;
 
/**
 * Model class that stores a message.
 * @author Bruce Phillips
 *
 */
 
 public class MessageStore {
 
	private String message;
 
	public MessageStore() {
 
		setMessage("Hello Struts User");
	}
 
	public String getMessage() {
		return message;
	}
 
	public void setMessage(String message) {
		this.message = message;
	}
}



Step 4: Creating Class for custom Controller

Now will create a simple Java Class which in next step will be promoted to a Struts Action controller, so that we can understand how Struts framework is adding capabilities to plain old java objects (POJOs).

Create a class (Right click on Project > New > Class) with package ‘sawan.hello.action’ and name ‘HelloWorldAction’.

Following lines of code are generated automatically in the blank class by IDE.

1
2
3
4
5
package sawan.hello.action;
 
public class HelloWorldAction {
 
}

This class is going to use an object from our Model i.e. MessageStore class. So let’s create an instance variable within HelloWorldAction.

Add this line of code between curly brackets.

1
private MessageStore messagestore;

IDE will complain for ‘MessageStore’ cannot be resolved to a type, and it will highlight MessageStore type in our variable declaration.

Tip: In Eclipse, Simply click and hover over MessageStore class name and in proposed list of quick fixed select Import sawan.hello.model.MessageStore.

Hint: IDE was able to locate this class because we have Struts jar dependencies in WebContent/WEB-INF/lib folder.

Adding import statement before class definition will resolve this issue.

1
import sawan.hello.model.MessageStore;

Next we need to create getters and setters for this class variable.

Tip: In Eclipse, select Source > Generate Getters and Setters to auto generate them.

Following methods should be added under our variable declaration.

1
2
3
4
5
6
7
	public MessageStore getMessagestore() {
		return messagestore;
	}
 
	public void setMessagestore(MessageStore messagestore) {
		this.messagestore = messagestore;
	}

So far our HelloWorldAction class is a POJO having no Struts capabilities. We’ll add them next.



Step 5: Converting a POJO Class into a custom Struts Action Controller

This transformation needs two changes to our class and we’ll be all set.

Change 1: First of all, our class should inherit from ActionSupport class defined in Struts framework. Extending this class will not only force us to implement some predefined interfaces, but our class will also inherit some methods and properties from ActionSupport class and its parent classes. This is what inheritance does.

So let’s add ‘extends ActionSupport’ next to our class declaration, so it will look like:

1
public class HelloWorldAction extends ActionSupport

Tip: Once again, IDE will complain for unavailable ActionSupport class, so clicking and hovering will propose a quick fix to import import com.opensymphony.xwork2.

Adding this import statement will resolve this issue (if not automatically added for you):

1
import com.opensymphony.xwork2.ActionSupport;

Change 2: Second change to our HelloWorldAction is to provide an entry point for Struts front controller (defined in web.xml). Struts implements this interface by providing a class method named ‘execute’.

Also execute method must return a string.

So let’s add execute method.

1
2
3
4
public String execute()throws Exception
{	
    return SUCCESS;		
}

The variable SUCCESS is inherited from ActionSupport class, which inherited it from Action class, both being part of Struts Framework and are included in package com.opensymphony.xwork2.

Once our execute method is available, we need to initialize our ‘messagestore’ class variable so that it will be made available to resulting view.

Add this line of code within execute method to initialize class variable with our Model object.

1
messagestore = new MessageStore();

After both Step 4 and 5, our HelloWorldAction.java class should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package sawan.hello.action;
 
import com.opensymphony.xwork2.ActionSupport;
 
import sawan.hello.model.MessageStore;
 
public class HelloWorldAction extends ActionSupport {
 
	private MessageStore messagestore;
 
	public String execute()throws Exception
	{
		messagestore = new MessageStore();
		return SUCCESS;		
	}
 
	public MessageStore getMessagestore() {
		return messagestore;
	}
 
	public void setMessagestore(MessageStore messagestore) {
		this.messagestore = messagestore;
	}
}



Step 6: Adding custom Action configuration to struts.xml

Our custom Action class is ready to handle requests. But we have not told our web application, which requests should be forwarded to this Action controller.

Open src/struts.xml file. There are couple of actions already defined in downloaded source code. Let’s add our custom action after those.

Add following configuration block between ‘package’ opening and closing tags.

1
2
3
<action name="helloaction" class="sawan.hello.action.HelloWorldAction" method="execute">
	<result name="success">/jsp/helloaction.jsp</result>
</action>

What this Action configuration does is:

1. it defines a name for this action as ‘helloaction’, which will make it searchable by Struts front controller (one defined in web.xml).

2. class attribute sets the class which should be passed the execution.

3. method attribute defines the method name, which should be passed the execution in that class.

4. result tag, declares that when execution method finishes with a returned message, application should return /jsp/helloaction.jsp View.

5. name attribute within result tag, tells that redirect user to said page, only if message returned from execute method is success.

With this configuration we have set enough directions for our front controller defined in web.xml i.e. org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

However there is no ‘helloaction.jsp’ page defined yet, to which we are redirecting the user after successful exection, so we need to do that next.



Step 7: Adding result View for our custom Action

Create a new jsp page in ‘WebContent/jsp/’ folder named ‘helloaction.jsp’.

At this point since all required files and folders are created, so our project hierarchy should look like this when seen in Project Explorer.

Struts With Custom Action - folders and files in Project Explorer view

Folder structure when all required files are created

If we launch our application at this point, it will be launched fine, however there is no way to trigger a request to ‘helloaction’, which when intercepted by front filter, is redirected to our custom Action class.

Thus, we need to make changes to our index.jsp page, so that there is a link which we can hit to trigger all that. Change existing line of html code between body tags of index.jsp, to something like:

1
Index Page | <a href="hello">Struts</a> | <a href="helloaction">Custom Action</a>

Now if we launch our application index.jsp page will be displayed as default entry point.

Struts With Custom Action - default view for our application

Index page for our application

Clicking on ‘Custom Action’ link will generate this url request:

http://localhost:8080/Tut-StrutsWithCustomAction/helloaction

This request will be intercepted by our front filter, and it will look in struts.xml for a matching action name. Since it has truncated everything else, and only looking for ‘helloaction’, it will find it for sure, since we just added it during struts.xml configuration step above.

Front controller will pick the class name from ‘class’ attribute and pass the execution to ‘execute’ method of this class, just as defined in Action configuration. So execution will enter in execute method of our custom Action class’s execute method.

Once there, we have initialized the messagestore class variable with MessageStore, our model class, and simply retuned SUCCESS.

When execution comes back to front controller, it will use ‘result’ tag to determine which page to launch based on the value of returned string. Since we have returned SUCCESS and there is a result tag, with name success, front controller will redirect browser to helloaction.jsp

Hint: It is a common and recommended approach to define class variables within Action class with required values returned by Model. So that resulting view will only have access to values which it needs to display.



Step 8: Using Struts Tag Library to access variables within Action controller

At this point our basic flow is working fine and we have utilized a custom Action controller for processing our page requests.

However the redirected helloaction.jsp page is blank. In real world applications, we will be doing some processing within execute method, and displaying the results on redirected page (helloaction.jsp in our case).

Struts facilities this functionality very elegantly by providing Struts Tag Library. Using struts tags, we can very easily access properties we have set within Action controller for each request.

For making our helloaction.jsp capable of accessing property defined within HelloWorldAction class, we need to make two changes in helloaction.jsp

Change 1: First of all we need to add Tag Library Directive, so that web server knows how to render Struts 2 Tags when generating a response.

Add this line of code on top of helloaction.jsp page right under page directive.

1
<%@ taglib prefix="s" uri="/struts-tags" %>

Change 2: Secondly we need to use one of Struts 2 Tag to access the property within response, which is available to us within our page scope.

Add this line of code between body tag of helloaction.jsp:

1
<h2><s:property value="messagestore.message" /></h2>

After these changes, our helloaction.jsp should look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
<%@ 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>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Hello Struts Tag Library</title>
</head>
<body>
<h2><s:property value="messagestore.message" /></h2>
</body>
</html>

Let’s run our web application once again, this time when helloaction.jsp page is rendered, we will see same message defined in our Model object i.e. MessageStore.java.

Using Struts Tag Library to display property defined in our custom Action

Using Struts Tag Library to display property defined in our custom Action



Download Tutorial Code:

Tutorial Working Code: Download



Exercise:

  • Add another custom Action handler along with its configuration in struts.xml file.

  • Use any other message besides “Success” returned from execute method. Use messages defined in Action interface within Struts 2 API.


    Hint: You will also have to make changes in struts.xml so that result will respond to that returned message.

  • Can we use different method name besides execute in struts.xml ? will that method act as our default entry point if we satisfy the requirement of returning a string from that method?