struts2 拦截器

Struts 2 token interceptor can be used to handle multiple form submission problem. While designing web application, sometimes we have to make sure that double form submission is treated as duplicate request and not be processed. For example, if user reloads the online payment form and there are not enough checks in place to identify it as duplicate request, customer will be charged twice.

Struts 2令牌拦截器可用于处理多种表单提交问题。 在设计Web应用程序时,有时我们必须确保将重复提交的表单视为重复请求,而不进行处理。 例如,如果用户重新加载在线付款表单,但是没有足够的支票将其识别为重复请求,则将向客户收取两次费用。

Double form submission problem handling needs to be done both at client side and server side. In client side, we can disable the submit button, disable back button but there will always be options through which user can send the form data again. Struts2 provides token interceptors that are designed to deal with this particular problem.

双重表单提交问题处理需要同时在客户端和服务器端进行。 在客户端,我们可以禁用“提交”按钮,“禁用”后退按钮,但是总会有一些选项,用户可以通过这些选项再次发送表单数据。 Struts2提供了旨在解决此特定问题的令牌拦截器。

Struts2令牌拦截器 (Struts2 Token Interceptor)

There are two interceptors defined in struts-default package as:

struts-default软件包中定义了两个拦截器,它们是:

<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>

These interceptors are not part of any predefined interceptor stack because if we add it for any action, the form submitted should have a token parameter else it will throw exception. We will look it’s usage with a simple project. Final project structure will look like below image.

这些拦截器不属于任何预定义的拦截器堆栈,因为如果我们将其添加到任何操作中,则提交的表单应具有token参数,否则它将引发异常。 我们将在一个简单的项目中查看它的用法。 最终的项目结构如下图所示。

Struts2令牌拦截器示例配置文件 (Struts2 Token Interceptor Example Configuration Files)

web.xml

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>Struts2TokenInterceptor</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>

Deployment descriptor is configured to use Struts 2 framework.

部署描述符被配置为使用Struts 2框架。

pom.xml

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>Struts2TokenInterceptor</groupId><artifactId>Struts2TokenInterceptor</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><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><dependencies><dependency><groupId>org.apache.struts</groupId><artifactId>struts2-core</artifactId><version>2.3.15.1</version></dependency></dependencies>
</project>

The web application is configured as maven project where we have added struts2-core dependency.

该Web应用程序被配置为maven项目,在其中添加了struts2-core依赖项。

struts.xml

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 to define result path locations to project root directory --><constant name="struts.convention.result.path" value="/"></constant><package name="user" namespace="/" extends="struts-default"><action name="update"><result>/update.jsp</result></action><action name="UpdateUser" class="com.journaldev.struts2.actions.UpdateUserAction"><interceptor-ref name="token"></interceptor-ref><!--OR <interceptor-ref name="tokenSession"></interceptor-ref>--><interceptor-ref name="defaultStack"></interceptor-ref><result name="success">/update_success.jsp</result><result name="input">/update.jsp</result><result name="invalid.token">/invalid_token.jsp</result></action></package></struts>
  1. We can use either token interceptor or tokenSession interceptor with any action.我们可以对任何动作使用token拦截器或token tokenSession拦截器。
  2. If token interceptor identifies the request as duplicate, then it returns the result invalid.token, that’s why we have a result configured for this.如果token拦截器将请求标识为重复请求,则它将返回结果invalid.token,这就是我们为此配置结果的原因。
  3. If form field validation fails then input result is returned where we are returning the same page from where we get the request.如果表单字段验证失败,那么将在我们返回请求的同一页面上返回输入结果。

We will look into the complete flow once we have seen the implementation and application behavior with duplicate request.

一旦看到重复请求的实现和应用程序行为,我们将研究完整的流程。

Struts2令牌拦截器示例操作类 (Struts2 Token Interceptor Example Action Class)

UpdateUserAction.java

UpdateUserAction.java

package com.journaldev.struts2.actions;import java.util.Date;import com.opensymphony.xwork2.ActionSupport;public class UpdateUserAction extends ActionSupport {@Overridepublic String execute() {System.out.println("Update Request Arrived to Action Class");//setting update time in action classsetUpdateTime(new Date());return SUCCESS;}@Overridepublic void validate(){if(isEmpty(getName())){addActionError("Name can't be empty");}if(isEmpty(getAddress())){addActionError("Address can't be empty");}}//java bean variablesprivate String name;private String address;private Date updateTime;public String getName() {return name;}public void setName(String name) {this.name = name;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Date getUpdateTime() {return updateTime;}public void setUpdateTime(Date updateTime) {this.updateTime = updateTime;}private boolean isEmpty(String str) {return str == null ? true:(str.equals("") ? true:false);}}

A simple action class with basic form fields validation and some java bean properties. Notice that update time is set by action class, it has been added to show the application behavior when we use tokenSession interceptor.

一个具有基本表单域验证和一些Java bean属性的简单操作类。 请注意,更新时间是由操作类设置的,已添加它以显示当我们使用tokenSession拦截器时的应用程序行为。

Struts2令牌拦截器示例JSP页面 (Struts2 Token Interceptor Example JSP Pages)

update.jsp

update.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>Update User Request Page</title>
</head>
<body>
<s:if test="hasActionErrors()">
<s:actionerror/>
</s:if>
<br>
<s:form action="UpdateUser">
<s:textfield name="name" label="User Name"></s:textfield>
<s:textfield name="address" label="Address"></s:textfield>
<s:submit name="submit" value="Update"></s:submit>
<%-- add token to JSP to be used by Token interceptor --%>
<s:token />
</s:form>
</body>
</html>

The entry point of the application from where user will submit form to update some information. We are using actionerror tag to show any validation errors added by the application. The most important point to note is s:token tag that will be used by token interceptors in making sure duplicate requests are not getting processed.

用户从此处提交表单以更新某些信息的应用程序的入口点。 我们正在使用actionerror标记来显示应用程序添加的任何验证错误。 要注意的最重要的一点是s:token标记,令牌拦截器将使用s:token标记来确保未处理重复的请求。

update_success.jsp

update_success.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>Update User Success Page</title>
</head>
<body>
<h3>User information updated successfully.</h3>Name: <s:property value="name"/><br>
Address: <s:property value="address"/><br>
Update Time: <s:date name="updateTime"/><br><h4>Thank You!</h4>
</body>
</html>

Simple JSP page showing action class java bean properties.

简单的JSP页面显示了操作类Java bean属性。

invalid_token.jsp

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" "https://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=US-ASCII">
<title>Update Duplicate Request 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>

Simple JSP page showing different methods that can cause multiple form submissions, notice the actionerror tag usage.

简单的JSP页面显示了可能导致提交多个表单的不同方法,请注意actionerror标记的用法。

Now when we will run our application, we will see following pages as response in the same order.

现在,当我们运行应用程序时,我们将以相同的顺序看到以下页面作为响应。

If you will look into the source of input page, you will see that Struts2 API has converted token tag to following HTML snippet.

如果您查看输入页面的源,您将看到Struts2 API已将令牌标记转换为以下HTML代码段。

<input type="hidden" name="struts.token.name" value="token" />
<input type="hidden" name="token" value="HGWQI7ZGP7KFGJLDPNTSFHLUX5RF26IK" />

Also you will notice following logs snippet.

您还会注意到以下日志片段。

Update Request Arrived to Action Class
WARNING: Form token HGWQI7ZGP7KFGJLDPNTSFHLUX5RF26IK does not match the session token null.

Notice that duplicate request doesn’t even reach to action class and token interceptor returns the invalid.token page as response.

请注意,重复请求甚至没有到达动作类,并且令牌拦截器返回invalid.token页面作为响应。

If you will use tokenSession interceptor, you will notice that it returns the same response as the first request. You can confirm this by going back and edit form fields and then submitting form again. The response update time and field values will be old values as sent in the first request.

如果您将使用tokenSession拦截器,则会注意到它返回的响应与第一个请求相同。 您可以通过返回并编辑表单字段,然后再次提交表单来确认。 响应更新时间和字段值将是在第一个请求中发送的旧值。

Struts2令牌拦截器如何工作 (How Struts2 Token Interceptor Works)

Now let’s see how token interceptor works to handle multiple form submissions.

现在,让我们看看令牌拦截器如何处理多种表单提交。

  1. When a request is made to the update action, Struts2 tags API generates a unique token and set it to the session. The same token is sent in the HTML response as hidden field.当请求更新操作时,Struts2标签API会生成一个唯一令牌并将其设置为会话。 在HTML响应中将相同的令牌作为隐藏字段发送。
  2. When the form is submitted with token, it is intercepted by token interceptor where it tries to fetch the token from the session and validate that it’s same as the token received in the request form. If token is found in session and validated then the request is forwarded to the next interceptor in the chain. Token interceptor also removes the token from the session.当表单与令牌一起提交时,它会被令牌拦截器拦截,在此尝试从会话中获取令牌并验证其是否与请求表单中接收的令牌相同。 如果在会话中找到令牌并对其进行了验证,则该请求将转发到链中的下一个拦截器。 令牌拦截器还会从会话中删除令牌。
  3. When the same form is submitted again, token interceptor will not find it in the session. So it will add an action error message and return invalid.token result as response. You can see this message in above image for invalid_token.jsp response. This way token interceptor make sure that a form with token is processed only once by the action.当再次提交相同的表单时,令牌拦截器将在会话中找不到它。 因此,它将添加操作错误消息并返回invalid.token结果作为响应。 您可以在上图中看到此消息,以获取invalid_token.jsp响应。 这样,令牌拦截器可确保带有令牌的表单仅被该操作处理一次。
  4. If we use tokenSession interceptor, rather than returning invalid token response, it tries to return the same response as the returned by the first action with same token. This implementation is done in the TokenSessionStoreInterceptor class that saves the response for each token in the session.如果我们使用tokenSession拦截器,而不是返回无效的令牌响应,它将尝试返回与第一个具有相同令牌的操作所返回的响应相同的响应。 此实现是在TokenSessionStoreInterceptor类中完成的,该类保存会话中每个令牌的响应。
  5. We can override the action error message sent by token interceptor through i18n support with key as “struts.messages.invalid.token”.我们可以使用i18n支持覆盖令牌拦截器通过i18n支持发送的操作错误消息,密钥为“ struts.messages.invalid.token”。

Thats all for the usage of Struts2 token interceptor to handle multiple form submission problem in web application. Download the application from below link and play around with it for better understanding.

多数民众赞成使用Struts2令牌拦截器来处理Web应用程序中的多种表单提交问题。 从下面的链接下载该应用程序,并进行试用以更好地理解。

Download Struts2 Token Interceptor Example Project下载Struts2令牌拦截器示例项目

翻译自: https://www.journaldev.com/2281/struts2-token-interceptor-example

struts2 拦截器

struts2 拦截器_Struts2令牌拦截器示例相关推荐

  1. struts2 拦截器_Struts2 execAndWait拦截器示例,用于长时间运行的动作

    struts2 拦截器 Sometimes we have long running actions where user will have to wait for final result. In ...

  2. 开关变压器绕制教程_教程:如何将变压器权重和令牌化器从AllenNLP上传到HuggingFace

    开关变压器绕制教程 This is the first of a series of mini-tutorials to help you with various aspects of the Al ...

  3. struts2模型驱动和令牌拦截器

    模型驱动: *要从页面中获取表单元素的值,需要在动作类中声明与页面元素同名的属性.导致动作类中既有javabean又有业务方法. *将javabean和业务方法进行分离: *将重新创建一个javabe ...

  4. struts2 拦截器_Struts 2拦截器示例

    struts2 拦截器 Welcome to Struts 2 Interceptor Example. While working on Struts 2, most of the time you ...

  5. struts2教程(7)--拦截器

    Struts2拦截器 一.拦截器介绍 拦截器 的使用 ,源自Spring AOP(面向切面编程)思想 拦截器 采用 责任链 模式 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链 ...

  6. 从struts2拦截器到自定义拦截器

    http://www.cnblogs.com/withyou/p/3170440.html 拦截器可谓struts2的核心了,最基本的bean的注入就是通过默认的拦截器实现的,一般在struts2.x ...

  7. Struts2内置拦截器和自定义拦截器

    内置拦截器 Struts2中内置类许多的拦截器,它们提供了许多Struts2的核心功能和可选的高级特性.这些内置的拦截器在struts-default.xml中配置.只有配置了拦截器,拦截器才可以正常 ...

  8. 使用struts2中默认的拦截器以及自定义拦截器

    转自:http://blog.sina.com.cn/s/blog_82f01d350101echs.html 如何使用struts2拦截器,或者自定义拦截器.特别注意,在使用拦截器的时候,在Acti ...

  9. Struts2拦截器实例-权限拦截器

    查看本例之前首先要大概了解struts2的理论知识(点击查看) 本例实现了一个权限拦截器! 需求:要求用户登录,且必须为指定用户名才可以查看系统中的某个视图资源,如果不满足这两个条件,系统直接转入登录 ...

最新文章

  1. 系统高可用设计与实践
  2. php iis mysql windows2003,Windows Server 2003 IIS6.0+PHP5(FastCGI)+MySQL5环境搭建教程 | 系统运维...
  3. (C语言版)栈和队列(二)——实现顺序存储栈和顺序存储队列的相关操作
  4. java 蓝桥杯 基础练习 FJ的字符串
  5. SVG 与 HTML5 的 canvas 相比较:
  6. java发送文本邮件_1、java实现发送纯文本邮件
  7. 团队编程项目作业1-成员简介及分工
  8. 闲来无事,画个佩奇可好?
  9. golang中tcp socket粘包问题和处理
  10. 日志打印longging模块(控制台和文件同时输出)
  11. Atititv2需求文档模板大纲目录 attilax总结
  12. 测量学5_测量误差理论的基本知识
  13. win7+VS2008安装QT、环境配置以及简单实例演示
  14. 微信小程序的组件传值
  15. Teraterm 脚本
  16. 微信小程序 渲染层网络错误_渲染层网络层错误 微信小程序开发 - 云计算资讯 - 服务器之家...
  17. 生物信息_odds_ratios、Likelihood_Ratios、发病率、frequency
  18. 电脑dns服务器未响应啥意思,电脑诊断出DNS服务器未响应是什么意思
  19. oracle 数据库 ORA-28000错误的原因及解决办法
  20. redis工具redis Desktop Manager使用

热门文章

  1. 关于python+django操作数据库中的表
  2. VisualSVN https 钩子失效 关闭服务器信任
  3. [转载收藏]三层式开发中的层次划分
  4. 保存页面的滚动条的位置
  5. 裴蜀(贝祖)定理及其证明
  6. 《phrack》黑客杂志
  7. 二叉树的基本操作(C)
  8. .Net 的 Web 项目中 关于TreeView 的 checkBox 的操作……
  9. python---subplot函数
  10. 数据结构上机实践第14周项目1 - 验证算法(折半查找)