Struts 2 Action classes doesn’t provide any methods to get Servlet API Request, Response, Session and attributes. But sometimes we need to access these in action classes, for example checking HTTP method or to work with session attributes or to set cookies or headers in response.
That’s why Struts 2 API provides a bunch of interfaces that we can implement in action classes to inject these objects in Action classes. All of these interfaces end with “Aware” and defined in org.apache.struts2.interceptor
package.
All of these interfaces declares setter methods through which Struts 2 API injects Servlet API components in action classes. It’s a great example of Dependency Injection in Java EE frameworks.
These *Aware interfaces are:
- SessionAware: This interface provides access to session attributes in action classes and declare a single method
setSession(Map<String, Object> sessionAttributes)
. Note that we can’t get HttpSession by implementing this interface, this is just to get access to the session attributes. - ApplicationAware: This interface provides access to context attributes in action classes as Map. We can add attributes to application context by putting values in the context map. This interface declares single method
setApplication(Map<String, Object> applicationAttributes)
. - RequestAware: This interface provides access to request attributes in action classes, it contains single method
setRequest(Map<String, Object> requestAttr)
. This interface is only applicable if Action classes are used in Servlet environment. Since this interface makes the Action tied to a servlet environment, so it should be avoided if possible since things like unit testing will become more difficult. - ServletRequestAware: We can implement this interface in action classes to get access to HttpServletRequest object. This interface is only relevant if the Action is used in a servlet environment. It defines a single method as
setServletRequest(HttpServletRequest request)
. - ServletResponseAware: Struts 2 action classes can implement this interface to get access to the HttpServletResponse object. We can then use response object to add headers or cookies. It defines a single method as
setServletResponse(HttpServletResponse response)
. - CookiesAware: This interface is intended to provide access to cookies in request in the form of Map. It contains single method
setCookiesMap(Map<String,String> cookies)
. To work with this interface, there are two interceptors defined in struts-default package as:<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/> <interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
But they are not part of defaultStack interceptors stack, so we need to include them for action class like below.
<action name="home" class="com.journaldev.struts2.actions.HomeAction"> <interceptor-ref name="cookie"></interceptor-ref> <interceptor-ref name="cookieProvider"></interceptor-ref> <interceptor-ref name="defaultStack"></interceptor-ref> <result name="success">/home.jsp</result> </action>
However these interceptors are very new and in my testing with Struts 2 version 2.3.15.1, I didn’t find it to be working. I looked into Struts 2 API docs but didn’t find any help on this. I will update the post if I find anything or if you know what is missing, please let us know through comments. The workaround is to use ServletRequestAware and ServletResponseAware interface to get the request cookies or to set cookies in response.
- PrincipalAware: We can implement this interface in action class to get Principal information from HttpServletRequest object. This interface works with
PrincipalProxy
to provide user id, principal details.
Let’s see all these interfaces in action with a simple Struts 2 project. Our final project structure looks like below image.
Struts2 Configuration Files
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns="https://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>Struts2Example</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>
</web-app>
pom.xml
<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Struts2Example</groupId>
<artifactId>Struts2Example</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.15.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<warSourceDirectory>WebContent</warSourceDirectory>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
</project>
struts.xml
<?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="login">
<result>/login.jsp</result>
</action>
<action name="home" class="com.journaldev.struts2.actions.HomeAction">
<interceptor-ref name="cookie"></interceptor-ref>
<interceptor-ref name="cookieProvider"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
<result name="success">/home.jsp</result>
</action>
</package>
</struts>
The configuration files are self explanatory and easy to understand.
Struts2 JSP Pages
login.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Login Page</title>
</head>
<body>
<s:form action="home" method="post">
<s:textfield label="User Name" name="user"></s:textfield>
<s:textfield label="Password" name="password"></s:textfield>
<s:submit label="Login"></s:submit>
</s:form>
</body>
</html>
home.jsp
<%@ page language="java" contentType="text/html; charset=US-ASCII"
pageEncoding="US-ASCII"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Home Page</title>
</head>
<body>
<h3>Welcome <s:property value="user"/></h3>
</body>
</html>
JSP pages are also very simple and just used to send some data in request and then use them in result page.
Struts2 Action Class
HomeAction.java
package com.journaldev.struts2.actions;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.interceptor.ApplicationAware;
import org.apache.struts2.interceptor.CookiesAware;
import org.apache.struts2.interceptor.PrincipalAware;
import org.apache.struts2.interceptor.PrincipalProxy;
import org.apache.struts2.interceptor.RequestAware;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.interceptor.SessionAware;
import com.opensymphony.xwork2.ActionSupport;
public class HomeAction extends ActionSupport implements SessionAware,
ApplicationAware, CookiesAware, RequestAware, ServletRequestAware,
ServletResponseAware, PrincipalAware {
private static final long serialVersionUID = 1L;
@Override
public String execute() {
System.out.println("Request Method: " + request.getMethod());
System.out.println("Using HTTPS?: " + principalProxy.isRequestSecure());
System.out.println("Request Cookies:" + requestCookies);
// add a cookie to response
response.addCookie(new Cookie("user", "Pankaj"));
if (requestCookies == null)
requestCookies = new HashMap<String, String>();
requestCookies.put("test", "test");
System.out.println("Session Attributes: " + sessionAttributes);
// add session attribute
HttpSession mySession = request.getSession();
mySession.setAttribute("user", "Pankaj");
//OR
sessionAttributes.put("test", "Test");
System.out.println("Context Attributes: "
+ contextAttributes.get("user"));
// add context attribute
contextAttributes.put("user", "Pankaj");
System.out.println("Request Attributes: " + requestAttributes);
return SUCCESS;
}
// variables for *Aware interfaces
private PrincipalProxy principalProxy = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
private Map<String, Object> requestAttributes = null;
private Map<String, Object> sessionAttributes = null;
private Map<String, Object> contextAttributes = null;
private Map<String, String> requestCookies = null;
@Override
public void setPrincipalProxy(PrincipalProxy principalProxy) {
this.principalProxy = principalProxy;
}
@Override
public void setServletResponse(HttpServletResponse httpServletResponse) {
this.response = httpServletResponse;
}
@Override
public void setServletRequest(HttpServletRequest httpServletRequest) {
this.request = httpServletRequest;
}
@Override
public void setRequest(Map<String, Object> requestAttr) {
this.requestAttributes = requestAttr;
}
@Override
public void setCookiesMap(Map<String, String> cookies) {
this.requestCookies = cookies;
}
@Override
public void setApplication(Map<String, Object> applicationAttributes) {
this.contextAttributes = applicationAttributes;
}
@Override
public void setSession(Map<String, Object> sessionAttr) {
this.sessionAttributes = sessionAttr;
}
// java bean properties to hold request attributes
private String user;
private String password;
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
A single action class implementing all the *Aware interfaces and using them to log some data in server log files.
Once we execute the login action and then hit home action multiple times, we get following logs.
Request Method: POST
Using HTTPS?: false
Request Cookies:{}
Session Attributes: {}
Context Attributes: null
Request Attributes: {struts.valueStack=com.opensymphony.xwork2.ognl.OgnlValueStack@662fe032, __cleanup_recursion_counter=1, struts.actionMapping=ActionMapping{name='home', namespace='/', method='null', extension='action', params=null, result=null}}
Request Method: POST
Using HTTPS?: false
Request Cookies:{}
Session Attributes: {test=Test, user=Pankaj}
Context Attributes: Pankaj
Request Attributes: {__cleanup_recursion_counter=1, struts.valueStack=com.opensymphony.xwork2.ognl.OgnlValueStack@749cd006, struts.actionMapping=ActionMapping{name='home', namespace='/', method='null', extension='action', params=null, result=null}}
Notice that request cookies are NULL, however I checked request and response in browser and it’s sending cookies in request.
That’s all for accessing Servlet API core components in Struts 2 Action classes. It’s simple and elegant to use.
Hi,
I want to populate an image from an action class as like captcha. I created the image from the action class using awt functions. The problem is that i couldn’t populate it to the desired jsp page. Could you please help me….
I am trying to modify one request attribute by Implementing servletRequestAware.
Below is the code where I am tring to change the value of “name” attribute of request,but it remains same.
@Override
public void setServletRequest(HttpServletRequest request) {
System.out.println(“inside setServletRequest name–>”+(String)request.getParameter(“name”));
request.setAttribute(“name”, “modified”);
System.out.println(“inside setServletRequest name111–>”+(String)request.getParameter(“name”));
}
actually sir i am a beginner in java . i want to show the details of first html page to last jsp page . so what can i do for this ?
Dear Sir,
I am beginner of learning JSP and Servlets,actually iam from CCNA background. Now i would like to learn Android development. Can you please suggest me what i should do for becoming an Android developer..
just do it! 🙂
Hey great article.
Can you please write about best practices to use struts2+db connection?
How to implement db crud operations without using ServletRequestAware ?
Thanks in advance.