Struts 2 Interceptor Example

Filed Under: Struts 2

Welcome to Struts 2 Interceptor Example. While working on Struts 2, most of the time you will spend on Action Classes but Interceptors are the backbone of Struts 2 Framework.

Struts 2 Interceptor

Struts 2 interceptors are responsible for most of the processing done by the framework. For example, passing request params to action classes, making Servlet API request, response, session available to Action classes, validation, i18n support etc.

Struts 2 provides a bunch of interceptors and most of them are defined in struts-default package and used in defaultStack interceptor stack. Interceptors are the power of Struts 2 framework that plays a crucial role in achieving high level of separation of concerns.

In our Struts 2 Beginners Tutorial, we looked at the Struts 2 architecture and saw that every request and response passes through interceptors. Hence interceptors can inject different objects, perform specific operations on request and response and do some cross cutting tasks for the application.

ActionInvocation is responsible to incapsulate Action classes and interceptors and to fire them in order. The most important method for use in ActionInvocation is invoke() method that keeps track of the interceptor chain and invokes the next interceptor or action. This is one of the best example of Chain of Responsibility pattern in Java EE frameworks.

Struts 2 API reads the interceptors defined for an action in the order it’s declared. So if interceptor1 and interceptor2 are defined for action1 then ActionInvocation will invoke them in following chain.

interceptor1 -> interceptor2 -> action1 -> interceptor2 -> interceptor1

If any of the interceptor intercept() method decides that action should not get executed, it can return a string value and response will be created from global result with that name from struts configuration file.

Struts 2 Interceptors and Global Results configuration

We can define global results in struts.xml file as:


<global-results>
	<result name="login" type="redirect">/login.action</result>
</global-results>

These results can be used by any of the action classes.

Defining interceptors for a package includes several steps and we need to define them with interceptors, interceptor, interceptor-stack and default-interceptor-ref elements. They should be the first elements of the package or else you will get error message as

The content of element type “package” must match “(result-types?,interceptors?,default-
interceptor-ref?,default-action-ref?,default-class-ref?,global-results?,global-exception-
mappings?,action*)”.

Struts 2 Interceptor Example

A simple example of interceptor configuration is:


<package name="user" namespace="/" extends="struts-default">
	<interceptors>
		<interceptor name="authentication"
			class="com.journaldev.struts2.interceptors.AuthenticationInterceptor"></interceptor>
		<interceptor-stack name="authStack">
			<interceptor-ref name="authentication"></interceptor-ref>
			<interceptor-ref name="defaultStack"></interceptor-ref>
		</interceptor-stack>
	</interceptors>

	<default-interceptor-ref name="authStack"></default-interceptor-ref>
</package>

Note that defaultStack is already configured in struts-default package, that’s why we don’t need to define that in above example.

Let’s create a simple application where we will use custom interceptor class to provide authentication for our application. Using interceptor will make our application loosely coupled, flexible and configurable. Our final project will look like below image.

Struts2 interceptor example, struts 2 interceptor

Struts2 Interceptor Example Project configuration Files

web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="WebApp_ID" version="3.0">
	<display-name>Struts2InterceptorExample</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="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>Struts2InterceptorExample</groupId>
	<artifactId>Struts2InterceptorExample</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>

pom.xml and web.xml configuration files are self understood.

struts.xml


<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
	<constant name="struts.convention.result.path" value="/"></constant>

	<package name="user" namespace="/" extends="struts-default">
		<interceptors>
			<interceptor name="authentication"
				class="com.journaldev.struts2.interceptors.AuthenticationInterceptor"></interceptor>
			<interceptor-stack name="authStack">
				<interceptor-ref name="authentication"></interceptor-ref>
				<interceptor-ref name="defaultStack"></interceptor-ref>
			</interceptor-stack>
		</interceptors>

		<default-interceptor-ref name="authStack"></default-interceptor-ref>

		<global-results>
			<result name="login" type="redirect">/home.action</result>
		</global-results>

		<action name="home">
			<interceptor-ref name="defaultStack"></interceptor-ref>
			<result>/login.jsp</result>
		</action>

		<action name="login" class="com.journaldev.struts2.actions.LoginAction">
			<interceptor-ref name="defaultStack"></interceptor-ref>
			<result name="success">/welcome.jsp</result>
			<result name="input">/login.jsp</result>
		</action>
		<action name="welcome" class="com.journaldev.struts2.actions.WelcomeAction">
			<result name="success">/welcome.jsp</result>
		</action>

	</package>

</struts>

Notice that I am declaring an interceptor authentication which is referring to class com.journaldev.struts2.interceptors.AuthenticationInterceptor.

Also notice that authStack is the default interceptor-stack for the package. I am not using this stack for login.jsp because it’s used for login and at that time user will not have session to authenticate.

Result Pages

login.jsp


<%@ page language="java" contentType="text/html; charset=US-ASCII"
    pageEncoding="US-ASCII"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://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="user" label="User Name"></s:textfield>
	<s:textfield name="password" label="Password" type="password"></s:textfield>
	<s:submit value="Login"></s:submit>
</s:form>
</body>
</html>

welcome.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" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Welcome Page</title>
</head>
<body>
<h3>Welcome <s:property value="userName"></s:property></h3>
</body>
</html>

JSP result pages are easy to understand and nothing related to interceptors.

Model Class

User.java


package com.journaldev.struts2.models;

public class User {

	private String user;
	private String password;
	private String userName;
	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;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	
}

A simple java bean with properties that are used in result pages. We will use this java bean in action class to hold properties.

Custom Interceptor

UserAware.java


package com.journaldev.struts2.interceptors;

import com.journaldev.struts2.models.User;


public interface UserAware {

	public void setUser(User user);
}

An interface similar to Struts 2 API *Aware interface, we will use it in our custom interceptor to inject values in action class. To learn more about Struts 2 API *Aware interface, please read:

How to get Servlet Session, Request, Response, Context Attributes in Struts 2 Action

AuthenticationInterceptor.java


package com.journaldev.struts2.interceptors;

import java.util.Map;

import com.journaldev.struts2.models.User;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.Interceptor;

public class AuthenticationInterceptor implements Interceptor {

	private static final long serialVersionUID = -5011962009065225959L;

	@Override
	public void destroy() {
		//release resources here
	}

	@Override
	public void init() {
		// create resources here
	}

	@Override
	public String intercept(ActionInvocation actionInvocation)
			throws Exception {
		System.out.println("inside auth interceptor");
		Map<String, Object> sessionAttributes = actionInvocation.getInvocationContext().getSession();
		
		User user = (User) sessionAttributes.get("USER");
		
		if(user == null){
			return Action.LOGIN;
		}else{
			Action action = (Action) actionInvocation.getAction();
			if(action instanceof UserAware){
				((UserAware) action).setUser(user);
			}
			return actionInvocation.invoke();
		}
	}

}

This is our custom interceptor class that is implementing com.opensymphony.xwork2.interceptor.Interceptor interface. init() and destroy() are interceptor lifecycle methods that we can implement to initialize and destroy some resources used in interceptor intercept() method.

intercept() is the method invoked by ActionInvocation class, so this is where our interceptor code goes. We can get session attributes from ActionInvocation reference and use it to make sure session is valid. If we don’t find the attribute, we are returning global result “login” that will redirect user to login page. If session is valid, then we are injecting user into action class. instanceof keyword is used to make sure that action class is implementing UserAware interface. Finally we are calling ActionInvocation invoke() method that will call the next interceptor or action class in the chain.

Action Classes

LoginAction.java


package com.journaldev.struts2.actions;

import java.util.Map;

import org.apache.struts2.interceptor.SessionAware;

import com.journaldev.struts2.models.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class LoginAction extends ActionSupport implements SessionAware, ModelDriven<User>{

	private static final long serialVersionUID = -3369875299120377549L;

	@Override
	public String execute(){
		System.out.println("inside execute");
		if("pankaj".equals(user.getUser()) && "admin".equals(user.getPassword())){
			user.setUserName("Pankaj Kumar");
			sessionAttributes.put("USER", user);
			return SUCCESS;
		}
		return INPUT;
	}
	
	private User user = new User();
	private Map<String, Object> sessionAttributes = null;

	@Override
	public void setSession(Map<String, Object> sessionAttributes) {
		this.sessionAttributes = sessionAttributes;
	}
	
	@Override
	public User getModel() {
		return user;
	}
	
}

Notice that LoginAction is implementing SessionAware interface to get session attributes and if user is validated, then putting user attribute in session to be used in authentication interceptor for validation. Notice that LoginAction is not implementing UserAware interface.

WelcomeAction.java


package com.journaldev.struts2.actions;

import com.journaldev.struts2.interceptors.UserAware;
import com.journaldev.struts2.models.User;
import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;

public class WelcomeAction extends ActionSupport implements UserAware, ModelDriven<User> {

	private static final long serialVersionUID = 8111120314704779336L;

	@Override
	public String execute(){
		return SUCCESS;
	}
	
	private User user;
	@Override
	public void setUser(User user) {
		this.user=user;
	}
	
	public User getUser(User user){
		return this.user;
	}

	@Override
	public User getModel() {
		return this.user;
	}

}

Notice that WelcomeAction is implementing UserAware interface and our AuthenticationInterceptor is injecting it to the action class behind the scene. Notice that action class is simple and there is no code for validating the user session or to set the user bean.

From above action classes code, it’s clear that if we use interceptors smartly, we can reduce a lot of code redundancy for common tasks that we need to do for multiple actions.

When we execute above project, we get following response pages.

Struts2 interceptor example login, struts 2 interceptor

Struts2 interceptor example success, struts 2 interceptor

If you are not logged in and you will try to invoke login.action, our authentication interceptor will forward you to login page and action class will never be invoked.

That’s all for Struts 2 interceptors tutorial, it’s one of the important features of Struts 2 and you should try to use it for reusability.

Comments

  1. Mahesh Dey says:

    hii pankaj my session is not work in AuthenticationInterceptor, So what can I do

  2. jagannath says:

    Hi,I used login application and it is validating form if userName and password is blank.
    Now I am sending userName and password like this
    http://localhost:8080/LoginApp/loginAction.action?userName=jagannath&password=123 then also logged in successfully instead of filling login.jsp form page. In this case user should not logged in. How can avoid it using struts2.

  3. Lakesh says:

    I Have a doubt regarding interceptor and SSL google plugin, i used @secured annotation for customerprofile command which will give customer details, but i integrated customized login interceptor to check whether customer is logged in. Since i added interceptor page is going to http(https or https based on current page- not redirecting to https) instead of https call. Is there way to get out of this issue?

  4. Karthik says:

    Awesome article! Have gone through most of your articles and it help a lot to understand things well!! Thank you for these and keep up the good work..

    Have lots of questions:

    1. How AuthenticationInterceptor is called before action? Is it because it is declared as default interceptor for the package?

    2. If that is the case then should it not be called for all the actions coming under the package?

    3. If so, default-stack is included in the custom interceptor stack – authstack and also in login action , so is it not redundant?!

  5. Naresh says:

    Hi, i am working migration project, i have a doubt regarding migrating struts1.x f/w to struts2.x f/w, in struts1.x there is struts-nested tags are available , to extends the functionality, how to achive in struts2.x, mean i want equal tags in struts2.x ..

    ex: , , ,…

  6. Michel says:

    When I do your example i cannot print the “inside auth interceptor” which you were put in you authentication interceptor. How to make sure it is going via the interceptor??

    1. Pankaj says:

      Check your struts2 configuration, seems like some issue in configuring the interceptors.

      1. Krishna says:

        In struts.xml for the action login you have given interceptor ref as default stack. I think it should be authStack

  7. Vishal Kotecha says:

    Hello Pankaj,

    It was really helpful description about struts 2 for initials and later such code could be very useful for a beginner. You are doing a great job . Keep it up!

    In support,
    Vishal

  8. Rohan says:

    Hello,

    I get the session as null in authentication interceptor only during first load of the application. Second time it works fine. Can you help.

    1. Pankaj says:

      Yes it’s because session cookie was sent in second and further requests.

      1. Rohan says:

        Thanks Pankaj for quick reply.

        My problem is in my welcome.action I set userBean in session. When I click other action which implements LoginInterceptor, the below line is NULL i.e. sessionAttribute is NULL only for the first load of the browser. Second time if I login, it works fine. I am not sure why it behaves like this for 1st load of browser. Any help would be great

        Map sessionAttributes = actionInvocation.getInvocationContext().getSession();

  9. Cristiao Lee says:

    Hello, Pankaj, I’m know little about Struts2, so I want to ask whtther the pom.xml is necessary for the example?

    1. Pankaj says:

      pom.xml is there because it’s Maven project. If you are using any other build mechanism such as Ant, Gradle then you will have other configuration files.

      If you are not using any build mechanism, you will have to add all the required dependencies jar files manually.

  10. Ravi says:

    I am a newbie to struts2. I was going through the example and had a question as interceptor will be called before the login.action is called when user is logging in first time wont this user = (User) sessionAttributes.get(“USER”); in the interceptor be always returning null as sessionAttributes.put(“USER”, user); is called only after intereceptor has executed please suggest.

    1. Pankaj says:

      Check the struts configuration file, I have made default-interceptor-ref to authStack that contains our authentication interceptor. For login action, interceptor-ref is defaultStack and our authentication interceptor wont be invoked.

  11. SVKumar says:

    Cool example. Also please write about authentication (Action class calling another internal site) over https passing the credential as parameters and getting the sessionId (a string) response. And I guess that would be using EJB injection and EJB using @Asynchrnization

    Thank you

  12. Thanh says:

    Nice tutorial.
    But it checks only when you type in login.action. If I type in welcome.jsp, it returns “Welcome”.

    1. Pankaj says:

      yes thats true but you can block direct access to JSP files by putting them inside WEB-INF directory.

  13. Amit Bhatnagar says:

    Dude.. I like it.. 🙂
    But i wanted to use it with A****Connect

Leave a Reply

Your email address will not be published. Required fields are marked *

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages