If you are working on Struts 2, you will spent a lot of time developing Struts 2 Actions. This article is aimed to provide you more details about Struts 2 Action classes and different ways to implement them.
Struts 2 Action Overview
Struts 2 Action is at the front of our application that takes care of handling client requests. You will notice that in any struts 2 application, there is an action class associated with different type of client action.
Struts 2 Action class does following tasks:
- Business Logic: Our application business logic resides in action classes. If your application has a lot of business logic, you might have other helper classes to do the actual work but it’s always Action class that integrates them with the application.
- Data Carrier: If you look into any Servlet code, you will notice that it’s our responsibility to get the client request data and process them. Most of the times we get the request data to create a java bean object and then invoke our business logic classes. Struts 2 Action classes makes our life easier with handling the data mapping to action class bean properties or to another java bean internally. It saves a lot of code that we used to write with Servlets. Similarly Struts Action takes care of the process to make sure result pages have access to the data that can be used in generating client response.Actually this task is done by Struts 2 params interceptor defined in struts-default package as:
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
- Determining Result: Struts 2 Action classes are responsible for determining the result pages that will be used for generating client response. It can be simple HTML page, JSP page etc.
There are four ways through which we can create Struts 2 Action classes.
- Simple Action Class: We can use any normal java class as Struts 2 action class, the only requirement is that it should have execute() method returning String. In the simplest form, we can have action class as:
12345678package com.journaldev.struts2.action;public class HomeAction {public String execute(){return "success";}}
Now we can configure this instruts.xml
file as:
1234567891011121314<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""https://struts.apache.org/dtds/struts-2.3.dtd"><struts><constant name="struts.convention.result.path" value="/"></constant><package name="user" namespace="/" extends="struts-default"><action name="home" class="com.journaldev.struts2.action.HomeAction"><result name="SUCCESS">home.jsp</result></action></package></struts>
Now we can access this action with URLhttps://localhost:8080/Struts2ActionExample/home.action
and it will return home.jsp page as response.Struts 2 default location for result pages are WEB-INF/content and we are overriding it with struts.convention.result.path configuration, read more about this at Struts 2 ResultPath.
- Implementing Action interface: We can implement
com.opensymphony.xwork2.Action
interface also to create action classes. Action interface has a single method execute() that we need to implement. The only benefit of using Action interface is that it contains some constants that we can use for result pages, these constants are SUCCESS, ERROR, NONE, INPUT and LOGIN. We can rewrite above HomeAction class by implementing Action interface as shown below.123456789package com.journaldev.struts2.action;import com.opensymphony.xwork2.Action;public class HomeAction implements Action{public String execute(){return SUCCESS;}}Read more about this approach at Struts 2 Beginners Tutorial.
- Using Struts 2 Annotations: Struts 2 supports annotation based configuration and we can use it to create action classes. To use struts 2 annotations, we need to add struts2-convention-plugin library in the classpath and in web.xml struts2 filter configuration provide the java package that contains action classes.
12345678910<filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class><init-param><param-name>actionPackages</param-name><param-value>com.journaldev.struts2.action</param-value></init-param></filter>
We can rewrite HomeAction class using annotation as below.
12345678910111213141516package com.journaldev.struts2.action;import org.apache.struts2.convention.annotation.Action;import org.apache.struts2.convention.annotation.Namespace;import org.apache.struts2.convention.annotation.Result;import org.apache.struts2.convention.annotation.ResultPath;@Action("home")@ResultPath("/")@Namespace("/")@Result(location="home.jsp", name="success")public class HomeAction{public String execute(){return "success";}}Read more about Struts 2 annotations at Struts 2 Annotations Hello World Example.
- Extending ActionSupport Class: ActionSupport class is the default implementation of Action interface and it also implements interfaces related to Validation and i18n support. ActionSupport class implements Action, Validateable, ValidationAware, TextProvider and LocaleProvider interfaces.We can override validate() method of ActionSupport class to include field level validation login in our action classes. For example, if we have a JSP page login.jsp as below.
login.jsp
123456789101112131415161718192021<%@ page language="java" contentType="text/html; charset=US-ASCII"pageEncoding="US-ASCII"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"><%-- Using Struts2 Tags in JSP --%><%@ taglib uri="/struts-tags" prefix="s"%><html><head><meta http-equiv="Content-Type" content="text/html; charset=US-ASCII"><title>Login Page</title></head><body><h3>Welcome User, please login below</h3><s:form action="login"><s:textfield name="name" label="User Name"></s:textfield><s:textfield name="pwd" label="Password" type="password"></s:textfield><s:submit value="Login"></s:submit></s:form></body></html>Then we can have LoginAction class with form fields validation as:
1234567891011121314151617181920212223242526272829303132333435package com.journaldev.struts2.action;import com.opensymphony.xwork2.ActionSupport;public class LoginAction extends ActionSupport {private static final long serialVersionUID = -1273531583006208372L;@Overridepublic String execute(){return SUCCESS;}@Overridepublic void validate(){if("".equals(getName())){addFieldError("name", "UserName can't be empty");}if("".equals(getPwd())){addFieldError("pwd", "Password can't be empty");}}//Java Bean to hold the form parametersprivate String name;private String pwd;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getPwd() {return pwd;}public void setPwd(String pwd) {this.pwd = pwd;}}We can configure this action class as:
123456<action name="login" class="com.journaldev.struts2.action.LoginAction"><result name="SUCCESS">welcome.jsp</result><result name="input">login.jsp</result></action>Now if either of the fields name or pwd will be empty in request, addFieldError() method will add an error message and struts 2 will return the response with result name “input”. You will get the login.jsp as response with error messages mentioned in the page.
Depending on your requirements, you can use any of the approaches to create struts 2 action classes, my favorite is ActionSupport class because it helps in writing validation and i18n logic easily in action classes.