Some times user may submit the request
twice, (or) refresh the page, in those conditions we shouldn’t let the
application behave in strange way. By using Token interceptor, we can get rid
of these double click kinds of problems. Whenever struts2 find double
submission, token interceptor returns the result invalid.token, which can be
mapped in your action configuration.
How
to set a token in your form?
Use the tag <s:token/> in your
form. This tag is required and must be used in the forms that submit to actions
protected by this interceptor. Any request that does not provide a token (using
the token tag) will be processed as a request with an invalid token.
In brief, following are the action, jsp
files I am going to use.
File
|
Description
|
EntryAction.java
|
Action class that process the form.
|
index.jsp
|
Simple HTML form
|
invalid_token.jsp
|
Request redirect to this page on
double submissions
|
success.jsp
|
You will get the page, after
successful submission of the form (input.jsp).
|
Following step-by-step procedure
explains simple application that uses token interceptor.
Step
1: Create new dynamic
web project ‘struts2_token’ in Eclipse.
File -> New -> Dynamic Web
Project.
Step
2: Mavenize the
project. Right click the project -> Properties -> Configure -> Convert
To Maven Project.
Open pom.xml, update struts2 maven
dependencies. I am going to use following maven dependency.
<dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>2.3.20</version> </dependency>
Step 3: Define index.jsp like below.
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="s" uri="/struts-tags"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>Insert title here</title> </head> <body> <s:form action="addEntry"> <s:textfield label="Name" name="name" /> <s:textfield label="Address" name="address" /> <s:submit value="ADD" /> <s:token /> </s:form> </body> </html>
Step 4: Define success.jsp like below.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!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=UTF-8"> <title>Insert title here</title> </head> <body> <h1>Your details are submitted successfully</h1> </body> </html>
Define invalid_token.jsp
like below.
invalid_token.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>Error Page</title> </head> <body> <h3>User information is not updated, duplicate request detected.</h3> <h4>Possible Reasons are:</h4> <ul> <li>Back button usage to submit form again</li> <li>Double click on Submit button</li> <li>Using "Reload" Option in browser</li> </ul> <br> <s:if test="hasActionErrors()"> <s:actionerror /> </s:if> </body> </html>
Step 5: Define package com.sample, define the class
EntryAction.java like below.
package com.sample; import com.opensymphony.xwork2.ActionSupport; public class EntryAction extends ActionSupport{ public String execute(){ return "success"; } }
Step
6: It is time to create
struts.xml. Since Struts 2 requires struts.xml to be present in classes folder.
Create struts.xml file under the WebContent/WEB-INF/classes folder. Eclipse
does not create the "classes" folder by default, so you need to do
this yourself. To do this, right click on the WEB-INF folder in the project
explorer and select New > Folder. Create struts.xml file inside classes.
struts.xml
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="default" extends="struts-default"> <action name="addEntry" class="com.sample.EntryAction"> <interceptor-ref name="token" /> <interceptor-ref name="defaultStack"></interceptor-ref> <result name="success">/success.jsp</result> <result name="invalid.token">/invalid_token.jsp</result> </action> </package> </struts>
Step 7: Update web.xml like below.
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>struts2_token</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <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>
Following is
the complete project structure.
Run the
application on server, you will get following page.
Fill the
form and submit the data, you will get success page.
Refresh the
success page, you will redirect to invalid_token.jsp.
Note:
While
developing above application, I stuck with below error.
java.lang.NullPointerException
at
com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:638)
at
com.opensymphony.xwork2.util.LocalizedTextUtil.findText(LocalizedTextUtil.java:614)
at com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:210)
at
com.opensymphony.xwork2.TextProviderSupport.getText(TextProviderSupport.java:139)
at
org.apache.struts2.interceptor.TokenInterceptor.getErrorMessage(TokenInterceptor.java:182)
at
org.apache.struts2.interceptor.TokenInterceptor.handleInvalidToken(TokenInterceptor.java:166)
at
org.apache.struts2.interceptor.TokenInterceptor.handleToken(TokenInterceptor.java:151)
at
org.apache.struts2.interceptor.TokenInterceptor.doIntercept(TokenInterceptor.java:142)
at
com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
at
com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:244)
at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
at
org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:564)
at
org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:81)
at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
at
org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at
org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
at
org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
at
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at
org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
at
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at
org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:617)
at
org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:518)
at
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1091)
at
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:668)
at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1521)
at
org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1478)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at
java.lang.Thread.run(Thread.java:745)
Solution for
above error is, Your action class must extend ActionSupport.
I am facing similar issue, i am getting null pointer exception even if i extend the Action class to ActionSupport class, Please help me with it
ReplyDelete