Struts 2 Tutorial – Interceptors
Interceptors are my favorite aspect of Struts 2. They inspect and/or act on a user’s request. There are three main uses cases that I’ll discuss here: intercepting before the action, between the action and view, and after the view. At the end, I’ll show you how to add your brand spankin’ new interceptor to your struts.xml file so that it is called on each request.
Intercepting Before the Action:
package org.lumidant.tutorial.struts2.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.ValidationAware;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class AuthorizationInterceptor extends AbstractInterceptor {
private static final String USER_KEY = "user";
public String intercept(ActionInvocation invocation) throws Exception {
Map session = invocation.getInvocationContext().getSession();
if(session.get(USER_KEY) == null) {
addActionError(invocation, "You must be authenticated to access this page");
return Action.ERROR;
}
return invocation.invoke();
}
private void addActionError(ActionInvocation invocation, String message) {
Object action = invocation.getAction();
if(action instanceof ValidationAware) {
((ValidationAware) action).addActionError(message);
}
}
}
You can see that we check to see if the user is authorized and present an error message if he/she is not logged in. We do this by adding an ActionError, which can be displayed on your view. If the user is logged in, then he/she proceeds normally.
Intercepting Between the Action and Generation of View:
package org.lumidant.tutorial.struts2.interceptor;
import java.util.Map;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.interceptor.PreResultInterceptor;
import org.apache.struts2.ServletActionContext;
public class WirelessInterceptor extends AbstractInterceptor {
private static final String RESULT_CODE_SUFFIX_WIRELESS = "Wireless";
private static final String REQUEST_HEADER_ACCEPT = "Accept";
private static final String ACCEPT_HEADER_WIRELESS = "vnd.wap";
public String intercept(ActionInvocation invocation) throws Exception {
invocation.addPreResultListener()(new PreResultListener() {
public void beforeResult(ActionInvocation invocation, String resultCode) {
// check if a wireless version of the page exists
// by looking for a wireless action mapping in the struts.xml
Map results = invocation.getProxy().getConfig().getResults();
if(!results.containsKey(resultCode + RESULT_CODE_SUFFIX_WIRELESS)) {
return;
}
// send to wireless version if wireless device is being used
final String acceptHeader = ServletActionContext.getRequest().getHeader(REQUEST_HEADER_ACCEPT);
if(acceptHeader != null && acceptHeader.toLowerCase().contains(ACCEPT_HEADER_WIRELESS)) {
invocation.setResultCode(resultCode + RESULT_CODE_SUFFIX_WIRELESS);
}
}
});
return invocation.invoke();
}
}
In this example, the action has already been taken, but we have not generated the view that the user will see yet. This allows us to send the user to a separate page if he/she is using a Blackberry. We check the Accept HTML header to see if the string “vnd.wap” is present and if so then we append “Wireless” to the result code. So if the action was going to send the user to the result “Success” then we will instead show them the result “SuccessWireless”. We could easily adopt this technique for a Google Android or an iPhone as well.
Intercepting after View Creation:
package org.lumidant.tutorial.struts2.interceptor;
import java.util.Map;
import org.hibernate.Transaction;
import org.marketcharts.data.dao.util.HibernateSessionFactory;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
public class HibernateInterceptor extends AbstractInterceptor {
public String intercept(ActionInvocation invocation) throws Exception {
try {
return invocation.invoke();
} catch(Exception e) {
Transaction tx = HibernateSessionFactory.getSession().getTransaction();
if(tx != null && tx.isActive()) {
tx.rollback();
}
return Action.ERROR;
} finally {
HibernateSessionFactory.getSession().close();
}
}
}
This example uses Hibernate, an Object Relational Mapper (ORM), which is library for easy database access. Hibernate needs an open session when the view is created (Open Session in View Pattern) because it lazily accesses the database. If the session is closed and we go to access the database, then Hibernate will throw an Exception. So this interceptor provides a method to close the session after the view has already been created and all the database calls have been made.
Adding an Interceptor to your struts.xml:
<package name="example" extends="struts-default">
<interceptors>
<!--
One possible use of an interceptor is to send the user to special version of the .jsp
view if they are using a Blackberry as shown above.
-->
<interceptor name="wireless" class="com.lumidant.tutorial.struts2.interceptor.WirelessInterceptor"/>
<interceptor-stack name="wirelessStack">
<interceptor-ref name="exception" />
<interceptor-ref name="servlet-config" />
<interceptor-ref name="i18n" />
<interceptor-ref name="chain" />
<interceptor-ref name="params" />
<interceptor-ref name="wireless" />
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="wirelessStack" />
</package>
In this example, we’ve change the default interceptor stack to be a custom stack which we’ve created. You can also extend existing stacks.
[…] struts.xml file defines the relationship between actions and .jsp views, the inclusion of interceptors, and possible result types. It’s essential that you be able to handle at least basic […]
Hi,
your example is very interesting and i understand what the interceptors are from this simple example.
Thanks a lot!!!
Realy interesting! I read book “struts2 in action” but did not find any example about
Intercepting after View Creation and Intercepting Between the Action and Generation of View:
Straight forward and clear example! Here’s a follow up:
You may add parameters to the interceptor-definition in struts.xml like this
something
How do you retrieve that parameter in the interceptor’s java code?
Please do NOT use the “Open Session in View-Pattern”. This should only be an example to unerstand how interceptors works. The “Open Session in View Pattern” makes the View dependend on persistence layer aspects…
Hi..,
This information good and stight forward to the beginers.
I really enjoyed while reading this article.
Thak you.
This is one of the best example I have ever read for interceptor…Really fantastic example…..It helped me a lot..Thanks a lot
It is very good for beginners Struts2….
I dint know about this. Thanks for the idea. But I wanted to know how struts.xml will look in the last case: Intercepting after View Creation. plz help me and thanks in advance.
Praveen, the struts.xml file will look the same regardless.
Hi Benjamin,
Nice to see your blog,
we are using interceptor, now we want that only one can login with the same usename, can we do it by using interceptor, how? pls guide me.
Tanx
Kamlesh
Kamlesh, I’m afraid I don’t understand your question entirely.
Hi Benjamin
Actually we are already using interceptor in our web portal, But in this web portal one user can login more than once simultaneously with the same username and password(username is unique).
It means if i logged in with username “kamlesh” and pw “123456” even though other can login with username “kamlesh” ane pw “123456” (the username is unique). I want to restrict this.
At a time Only one can login with one username. No one can login with username which is already logged in.
If you have faced this problem then pls help out me.
Regard
Kamlesh
Kamlesh, what you are talking about is tying a login to an IP address. You can invalidate the session ID if the IP address changes or ignore all new session requests while there is an active session under an old IP address. This can present usability problems to some users if their IP address changes. Another option would be to present an alert to the user that the IP address logged in has changed. For example, GMail lists the last account activity on the page. You should log these instances as well in case they present a security incident. You’ll likely want to put a decent portion of this logic in your login Action.
@Arnie: OSIV is a valid pattern. Arnie, it may have caused you grief, but to advise everyone NOT TO USE IT is a little cocky, no? There are use cases when OSIV may work just fine, like a backoffice application where the need to break out the layers into tiers with some kind of facade separating concerns is not doable due to project timelines and costs.
good example .
Fantastic example. Very much simplified difficult topic.
This is really a nice peace of code regarding interceptor……..its very helping…..
I want to know …can this example is useful incase of that case when we use strut2 and hibernate at the same time….plz repply on my emailid….
thanks in advance…
Hi, I need help with a situation with my struts2 project.
I try to read a numerical value using the following code:
the parameter numeroCedula it will be passed to the my action…
but, I write into the textbox by example “9978222” and when i submitted the value, I receive in the action the value “9978222,” , why the struts2, I don’t know if some interceptors change the value, adding this coma after the numerical value.
Could somebody help me?
thanks you
Thank you for the post and examples. It did solved my problem.
I was having problem handle logic between action and result until I know about the PreResultListener.
Such a great help!
i need struts2 configuration and how interceptors work with struts can any one help me?
nice example
How can I redirect user request coming from mobile or desktop users to different views. Can I use the interceptor or is there any easy way.
Very good!…helps me a lot!
Really helpful..
now i get what intercept is…
Thanks again.
really helpful..
thansax alot..!!!
i have got very help from this…
Hi, this is exactly what i was looking for, i have question though. Will this affects performance or it causes delay as these are invoked for every single action. If yes then does it worth it?
Thanks again.
Hi Benjamin
First,Thanks your good example.
I want to know how can i set strutes.xml when applies intercreptor Between the Action and Generation of View.
I have known the answer.Thranks