Struts2 Actions

In this section, you will learn about the struts 2 actions with an example.

Struts2 Actions

Struts2 Actions

     

When a client's request matches the action's name, the framework uses the mapping from struts.xml file to process the request. The mapping to an action is usually generated by a Struts Tag. The action tag (within the struts root node of  struts.xml file) specifies the action by name and the framework renders the default extension and other required stuff.

The default entry method to the handler class is defined by the Action interface.
Struts2 Action interface 

All actions may implement this interface, which exposes the execute() method. You are free to create POJOs that maintains the same contract defined by this interface without actually implementing the interface.
package com.opensymphony.xwork2;
public interface Action {
//The action execution was a failure. 
public final static String ERROR;
//The action execution require more input in order to succeed
public final static String INPUT;
//The action could not execute, since the user most was not logged in
public final static String LOGIN;
// The action execution was successful but do not show a view. 
public final static String NONE;
//The action execution was successful. 
public final static String SUCCESS;
//the logic of the action is implemented
public String execute() throws Exception;
}

Implementing the Action interface is optional. If Action is not implemented, the framework will use reflection to look for an execute method. If there is no execute method and no other method is specified in the configuration, the framework will throw an exception.

The Struts2 Action have introduced a simpler implementation approach of the action classes as POJO( Plain Old Java Objects). The most basic usage of an action, is to perform work with a single result always being returned. It looks like:

public class NewAction {
   public String execute() throws Exception {
        // do the work
        return "success";
   }
}

Note that here the action class doesn't extend any other class or interface. The method invoked in the processing of an action is the "execute" method. The "execute" method has no parameter and it returns a String object. However with struts 2 actions you can get different return types other than the string objects, by using helper interfaces available ( Helper interface provides the common results as constants like "success", "none", "error", "input" and "login").

The Action Class usually acts as a Model and executes a particular business logic depending on the Request object and the Input Parameters. In earlier versions of Struts (before Struts 2.0), an Action class is supposed to extend the org.apache.struts.Action class and has to override the Action.execute() method which takes four parameters.

Basically, actions are meant to process various objects like HttpServletRequest, HttpServletResponse. But here, our action class is not processing any object parameter. Here one important issue arises - how do you get access to the objects that you need to work with? The answer lies in the "inversion of control" or "dependency injection" pattern.

To provide a loosely coupled system, Struts2 uses a technique called dependency injection, or inversion of control. Dependency injection can be implemented by constructor injection, interface injection and setter injection. Struts2 uses setter injection. This means that to have objects available to the action, we need only to provide a setter method. There are also objects such as the HttpServletRequest that can be obtained by asking the ActionContext or implementing ServletRequestAware. Implementing ServletRequestAware is preferred. For each of the non-business objects there is a corresponding interface (known as an ?aware? interface) that the action is required to implement.

To understand the inversion of control better, let's look at an example where the processing of the action requires access to the current requests HttpServletRequest object.

The dependency injection mechanism used in this example is interface injection. As the name implies, with interface injection there is an interface that needs to be implemented. This interface contains setter methods, which in turn are used to provide data to the action. In our example we are using the ServletRequestAware interface, here it is:

public interface ServletRequestAware {
  public void setServletRequest(HttpServletRequest request);
}

When we implement this interface, our simple action gets modified a bit but now we have a HttpServerRequest object to use.

public class NewAction implements addDependency {
   private HttpServletRequest request;
   public void setServletRequest(HttpServletRequest request) {
        this.request = request;
   }
   public String execute() throws Exception {
        // do the work using the request
        return "SUCCESS";
   }
}

In Struts2, an action instance is created for each request. It's not shared and it's discarded after the request has been completed.

Action Mappings

The action mapping can specify a set of result types, a set of exception handlers, and an interceptor stack. But, only the name attribute is required. The other attributes can also be provided at package scope. Specified through Struts.xml file.

The  configuration for this action looks like this:

<action name="new" class="NewAction" >
<result>view.jsp</result>
</action>

 

The ?name? attribute  provides the URL information to execute the action  as ?/new.action?. The extension ?.action? is configured in the ?struts.properties? configuration file. 
The ?class? attribute provides the full package and class
name of the action to be executed.

Struts 2 processes an action class as a POJO and enables to return different results depending on the outcome of the logic. To get different results, the class needs to get modified as:

class NewAction {
public void String execute() throws Exception {
if ( its-ok() ) {
return "login";
} 
else {
return "none";
}}}

Here the class provides two different results, we have to configure the action tags of struts.xml file for each case. Modify the configuration as :

<action name="new"  class="NewAction" >
<result>login.jsp</result>
<result name="none">none.jsp</result>
</action>