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:
1234<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.
12345678<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
<?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
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 26 27 28 29 30 31 32 33 34 35 36 37 38 |
<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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
<?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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
<%@ 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<%@ 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
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 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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.