struts2 防止重复提交 与 进入等待画面

演示重复提交的错误:

相关文件:


struts.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN""http://struts.apache.org/dtds/struts-2.0.dtd"><struts><package name="strutsqs" extends="struts-default"><action name="Login" class="com.gq.LoginAction"><result name="error">/error.jsp</result><result name="success">/success.jsp</result></action></package>
</struts>
login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>My JSP 'login.jsp' starting page</title><meta http-equiv="pragma" content="no-cache"><meta http-equiv="cache-control" content="no-cache"><meta http-equiv="expires" content="0">    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"><meta http-equiv="description" content="This is my page"><!--<link rel="stylesheet" type="text/css" href="styles.css">--></head><body><form action="Login.action" method="post"><table width="207" border="1" height="82">
<tbody><tr>
<td> UserName:</td>
<td> <input type="text" name="username"></td></tr>
<tr>
<td> Password:</td>
<td> <input type="password" name="password"></td></tr>
<tr>
<td> <input type="submit" value="Login"></td>
<td> <input type="reset" value="Reset" name="reset"></td></tr>
</tbody></table></form></body>
</html>
LoginAction.java

public class LoginAction {private String username;private String password;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;}@SuppressWarnings("unchecked")public String execute() throws Exception{// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){ActionContext.getContext().getSession().put(key, value);}//消耗时间,提供重复提交的机会void consumeTimeForToken(){int result = 0;for( int i = 0 ; i<30000000 ; i++ ){result += (int)i/551.22;result /= 3.1458;}System.out.println("result=" + result);}// Just used for unit test!String findCompanyByName( ){Map<String, String> records = new HashMap<String, String>();records.put("gqltt", "SNJP");records.put("Liyanhong", "baidu");records.put("Bill", "Microsoft");return records.get( getUsername() );}
}
提交页面:

输出结果:

解决办法:

1、在提交页面的 form 中添加 <s:token/>


2、在Struts2 的配置文件中启用 TokenInterceptor拦截器或 TokenSessionStoreInterceptor拦截器

注意:

1、必须配置默认的拦截器(basicStack),否则取不到数据,抛出 NullPointerException

2、必须指定重复提交后的错误页面(invalid.token)

优点:可以防止客户重复提交,大大地降低了服务器的负荷。

缺点:对用户来说,可能会很不方便,一不小心点击了提交按钮,进入到了invalid.token页面,就再也回不去了,上述的操作就再也看不见了。(的确很恶心,即使倒退回登录页面,再次正常登录,还是会进入 invalid.token 页面!除非关掉网页再打开。)

参考:http://chengyue2007.iteye.com/category/73492?show_full=true

等待画面:

struts.xml 添加配置:

<action name="LongLived" class="com.gq.LongLivedAction"><interceptor-ref name="completeStack"/> <interceptor-ref name="execAndWait"/> <result name="wait">/wait.jsp</result> <result name="error">/error.jsp</result><result name="success">/success.jsp</result>
</action>
LongLiveAction.java

public class LongLivedAction {private String username;private String password;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;}@SuppressWarnings("unchecked")public String execute() throws Exception{addToSessionScope("user", getUsername());// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){//addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){Map session = ActionContext.getContext().getSession();if( session == null ){System.out.println("Error: session is null...");return ;}session.put(key, value);//ActionContext.getContext().getSession().put(key, value);}//消耗时间void consumeTimeForToken(){try {Thread.sleep( 4*1000 );} catch (InterruptedException e) {// do nothing...}System.out.println("After 4 seconds...");}
}
wait.jsp

注意:不要忘了加入 <%@ taglib prefix="s" uri="/struts-tags"%>

<%@ page language="java" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html><head><base href="<%=basePath%>"><title>Please Wait</title><meta http-equiv="refresh" content="3;url=<s:url includeParams='all'/> "/> </head><body>Please Wait...</body>
</html>

缺点:将参数写在 URL 中,明文化了(密码都看得到了!!!)



问题:取不到 session,Map session = ActionContext.getContext().getSession(); 操作一直返回 Null。为什么?


参考:http://webservices.ctocio.com.cn/java/470/9189470.shtml

下面是另一种,等待画面的配置,可以解决 session 为 Null 的问题:

struts.xml 添加配置:

		<action name="Wait" class="com.gq.WaitAction"> <interceptor-ref name="defaultStack"/><interceptor-ref name="execAndWait"> <param name="excludeMethods">input</param> <!-- 等待时间,执行时间没有超过此值,将不显示等待画面 (毫秒) <param name="delay">1000</param>--> <!-- 间隔检查时间,检查后台进程有没有执行完毕,如果完成了它就立刻返回,不用等到等待,用户不会看到等待画面  <param name="delaySleepInterval">50</param>--> </interceptor-ref> <result name="wait">/wait.jsp</result> <result name="error">/error.jsp</result><result name="success">/success.jsp</result></action>

WaitAction.java

public class WaitAction extends ActionSupport implements SessionAware {private static final long serialVersionUID = -5724238080200557097L;private Map session;public void setSession(Map session) {this.session = session;}public Map getSession(){return session;}private String username;private String password;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;}@SuppressWarnings("unchecked")public String execute() throws Exception{System.out.println("In Wait.action");addToSessionScope("user", getUsername());// Just for test of token.System.out.println( "name:" + getUsername() + "\tpassword:" + getPassword());consumeTimeForToken();if( getUsername().equals("gqltt") && getPassword().equals("123")){//addToSessionScope("user", getUsername());return "success";}return "error";}@SuppressWarnings("unchecked")void addToSessionScope( String key, String value ){getSession().put(key, value);}//消耗时间void consumeTimeForToken(){try {Thread.sleep( 4*1000 );} catch (InterruptedException e) {// do nothing...}System.out.println("After 4 seconds...");}
}
注意:Action 要实现 SessionAware接口(验证过——这样的添加属性到 session 是OK 的!)

因为这个action将会以单独的线程执行,所以你不能用ActionContext,因为它是ThreadLocal.这也就是说如果你要访问session数据,你必须实现 SessionAware结构而不是调用ActionContext.getSesion() 。


wait.jsp(带刷新失败时候的超链接)

<%@page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>   
<%@taglib prefix="s"uri="/struts-tags"%>   
<!DOCTYPEHTMLPUBLIC"-//W3C//DTDHTML4.01Transitional//EN">   
<html> 
<head> 
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">   
<meta http-equiv="refresh" content="1;url=<s:url includeParams="none" />"/>   
<title> 
</title> 
</head> 
<body> 
<h1>数据处理中,请稍等......</h1> 
如果没有自动跳转请<a href="<s:url includeParams="all" />">点这里</a>. 
</body> 
</html>
其中的includeParams参数取值为:
none,不把参数加入到url参数中 
all,是把get和post中的参数加入到url参数中
get,是只把get中的参数加入到url参数中 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/498073.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

征服围棋之后 谷歌DeepMind宣布利用AI对抗乳腺癌

来源&#xff1a;全球人工智能 概要&#xff1a;在征服围棋世界之后&#xff0c;DeepMind公司将许多机器学习资源用于提升医疗水平&#xff0c;今天&#xff0c;DeepMind宣布利用人工智能对抗乳腺癌。 在征服围棋世界之后&#xff0c;DeepMind公司将许多机器学习资源用于提升医…

php进程间通信 yoc_PHP 进程间通信各种通信方式间的优劣之分??

目前我所了解的进程间通信的方式有&#xff1a;1. PHP 消息队列(sysvmsg 扩展)我的理解&#xff1a; 消息是一次性消耗品。一个进程向消息队列发送消息后&#xff0c;这个消息只能够被另一个进程接收&#xff0c;接收后&#xff0c;这个消息就彻底从消息队列中被去除了&#xf…

rabbitmq详细入门文档+springboot结合使用

在介绍RabbitMQ之前&#xff0c;我们先来看下面一个电商项目的场景&#xff1a; 商品的原始数据保存在数据库中&#xff0c;增删改查都在数据库中完成。 搜索服务数据来源是索引库&#xff08;Elasticsearch&#xff09;&#xff0c;如果数据库商品发生变化&#xff0c;索引库…

Cognizant:走向2028年将诞生的21个新工作

来源&#xff1a;亿欧 概要&#xff1a;未来十多年&#xff0c;伴随着AI等新技术的发展&#xff0c;部分工作岗位可能消失&#xff0c;但也可能创造出很多新的工作机会。 未来十多年&#xff0c;伴随着AI等新技术的发展&#xff0c;部分工作岗位可能消失&#xff0c;但也可能创…

Struts2中ActionContext介绍

来源&#xff1a;http://blog.csdn.net/alex197963/article/details/2219912 在Web应用程序开发中&#xff0c;除了将请求参数自动设置到Action的字段中&#xff0c;我们往往也需要在Action里直接获取请求(Request)或会话(Session)的一些信息&#xff0c;甚至需要直接对JavaSe…

delphi excel取批注所在的行列_excel技巧教程丨34个常用Excel小技巧,助你玩转职场!...

技巧1&#xff1a;单元格内强制换行在单元格中某个字符后按alt回车键&#xff0c;即可强制把光标换到下一行中。技巧2&#xff1a;锁定标题行选取第2行&#xff0c;视图 - 冻结窗格 - 冻结首行(或选取第2行 - 冻结窗格)冻结后再向下翻看时标题行始终显示在最上面。技巧3&#x…

Spring Security用户认证和权限控制(默认实现)

1 背景 实际应用系统中&#xff0c;为了安全起见&#xff0c;一般都必备用户认证&#xff08;登录&#xff09;和权限控制的功能&#xff0c;以识别用户是否合法&#xff0c;以及根据权限来控制用户是否能够执行某项操作。 Spring Security是一个安全相关的框架&#xff0c;能…

2017年数据可视化的七大趋势!

来源&#xff1a; 全球人工智能 概要&#xff1a;随着科技的不断进步与新设备的不断涌现&#xff0c;数据可视化领域目前正处在飞速地发展之中。 随着科技的不断进步与新设备的不断涌现&#xff0c;数据可视化领域目前正处在飞速地发展之中。ProPublica的调查记者兼开发者Lena…

python中for语句涉及的序列可以是关系表达式吗_为什么我可以在Python for循环中为迭代器和序列使用相同的名称?...

x告诉我们什么&#xff1a;Python 3.4.1 (default, May 19 2014, 13:10:29)[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)] on darwinType "help", "copyright", "credits" or "license" for more information.>>>…

struts2中用interceptor实现权限控制

在jsp servlet中我们通常使用Servlet Filter控制用户是否登入&#xff0c; 是否有权限转到某个页面。在struts2中我们应该会想到他的拦截器(Interceptor)&#xff0c; Interceptor在struts2中起着非常重要的作用。很多struts2中的功能都是使用Interceptor实现的。 需求&#xf…

Java实现xml与map互转

此文档中包含单层和多层嵌套情况下&#xff0c;xml和map集合进行互转&#xff0c;具体代码如下&#xff1a; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry;import org.dom4j.Document; import org.dom4j.DocumentExce…

CGAL的三维点集

CGAL提供了几种处理点集的算法&#xff0c;从形状检测到通过标准点集处理工具进行的表面重建。 虽然这些算法不强制使用特定的数据结构&#xff0c;但该软件包提供了一个3D点集结构&#xff0c;使用户更容易处理附加属性&#xff0c;如法向量、颜色、标签&#xff0c;并在其上调…

2018年AI智商将达到多少?未来智能实验室启动第三次世界AI智商评测

来源&#xff1a; 人工智能学家 概要&#xff1a;21世纪以来&#xff0c;人工智能领域陆续爆发很多重要事件。其中最吸引人们眼球的&#xff0c;当属2016年战胜了人类围棋冠军并开始能够从0自我学习的AlphaGo。 一.人工智能能否超越人类智慧的争议 21世纪以来&#xff0c;人工智…

二进制函数_Go二进制文件逆向分析从基础到进阶——MetaInfo、函数符号和源码文件路径列表...

书接前文&#xff0c;本文主要介绍 Go 二进制文件中 Meta Information 的解析&#xff0c;与函数符号和源码文件路径列表的提取。最后详细介绍一下 Moduledata 这个结构。传送门&#xff1a;Go二进制文件逆向分析从基础到进阶——综述05Meta information>>>>5.1 Go…

学习网址

深入讲解权限&#xff1a; http://www.noahweb.net/mail/2/Project.htm#biaoStruts2 源码分析 http://blog.csdn.net/wl_ldy/article/details/5948779 Struts2部分源码讲解&#xff1a;http://code.google.com/p/struts2-src-study/source/browse/trunk/struts2-src-study--u…

七大科技巨头统治世界?

来源&#xff1a;亿欧智库 概要&#xff1a;我想无论是业内人士还是普通用户&#xff0c;都会思考为什么是他们成为最大的公司&#xff1f; 2017年秋天&#xff0c;随着腾讯和阿里巴巴两家中国公司市值的不断上涨&#xff0c;全球市值头部公司刚好是七大科技巨头&#xff08;下…

vue 懒人_Vue.js 中的实用工具方法【推荐】

收集日常开发中常用到的一些工具方法, 包含 vue 的公用过滤器、公用指令等 (PS: 懒人养成记)公用自定义过滤器import Vue from vueimport moment from moment/*** filter dateFormat 时间格式化* param {String, Date} value 可被 new Date 解析的字符串* param {String} forma…

用户权限管理——DB设计篇

来源&#xff1a;http://www.noahweb.net/mail/2/Project.htm#biao B/S系统中的权限比C/S中的更显的重要&#xff0c;C/S系统因为具有特殊的客户端&#xff0c;所以访问用户的权限检测可以通过客户端实现或通过客户端服务器检测实现&#xff0c;而B/S中&#xff0c;浏览器是每一…

oracle数据库常用的语法与复合函数

oracle查用到一些复合函数以及一些常用的方法用来快速查询数据&#xff0c;以下是我收集的一下常用方法&#xff0c;推荐给大家&#xff1a; 1、 当分组之后&#xff0c;针对某一属性值进行合并并以逗号进行分割&#xff1a; &#xff08;1&#xff09;所有版本都可使用&…