- 浏览: 210243 次
最新评论
-
jin8000608172:
Profiler类是自己写的还是开源jar里面的,如果是开源j ...
isInfoEnabled究竟多有用? -
u011358822:
www.baidu.com
实战Concurrent -
u011358822:
[url][img][list][*]引用[/list][/i ...
实战Concurrent -
water_lang:
这本书我买了一本,但是我还是没找到该怎么解决事务这块,mong ...
《MongoDB实战》译者序 -
DREAM_UTOPIA:
每周推荐非常好,观点独到,涉及面广,谢谢
每周推荐阅读2013Q2汇总
前阵子弄了些表单防重复提交的东西,想整理整理,免得下次要用时再四处去找,其实这里的东西还是挺简单的。
原理:
在Session中保存一个表单的唯一编号,将该编号放在一个隐藏域中,同其他数据一同提交。在提交表单后,通过拦截器或其他机制检查唯一编号,如果存在则说明表单是第一次提交,如果不存在则被重复提交(理由很简单,在第一次提交检查后就会从Session中移除该编号)。保存编号可以用一个HashMap。
上代码:
表单类,用于保存表单创建时间和表单的标示
package form; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.builder.ToStringBuilder; /** * 表单类 * * @author DigitalSonic */ public class Form implements Serializable { /** * serialVersionUID */ private static final long serialVersionUID = 8796758608626021150L; public static final String FORM_UNIQ_ID_FIELD_NAME = "_form_uniq_id"; /** 表单标识*/ private String token; /** 表单创建时间*/ private Date createTime; /** * 构造函数 */ public Form(String token) { this.token = token; this.createTime = new Date(); } public String toString() { return ToStringBuilder.reflectionToString(this); } public String getToken() { return token; } public Date getCreateTime() { return createTime; } }
表单管理器接口
package form; import javax.servlet.http.HttpServletRequest; /** * 表单管理器,负责管理Session中的表单。 * * @author DigitalSonic */ public interface FormManager { /** * 生成一个新的表单 */ public Form newForm(HttpServletRequest request); /** * 判断表单是否存在。 */ public boolean hasForm(HttpServletRequest request, String token); /** * 访问参数中是否存在表单Token。 */ public boolean hasFormToken(HttpServletRequest request); /** * 销毁一个表单 */ public void destroyToken(HttpServletRequest request, String token); /** * 打印表单信息。 */ public String dumpForm(HttpServletRequest request, String token); }
表单管理器接口实现
package form; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import org.apache.commons.lang.RandomStringUtils; import org.apache.commons.lang.StringUtils /** * 表单管理器实现类 * * @author DigitalSonic */ public class FormManagerImpl implements FormManager { private static final String SESSION_KEY_OF_FROMS = "_forms_in_session"; /** 表单最大个数 */ private int maxFormNum = 7; /** * 销毁一个表单 */ public void destroyToken(HttpServletRequest request, String token) { getForms(request).remove(token); } /** * 打印表单信息。 */ public String dumpForm(HttpServletRequest request, String token) { Form form = getForms(request).get(token); if (form == null) { return "null"; } return form.toString(); } /** * 判断表单是否存在。如果token为null,直接返回false。 * * @see #getForms(HttpServletRequest) */ public boolean hasForm(HttpServletRequest request, String token) { if (token == null) { return false; } return getForms(request).containsKey(token); } /** * 访问参数中是否存在表单Token。 */ public boolean hasFormToken(HttpServletRequest request) { String formToken = request.getParameter(Form.FORM_TOKEN_FIELD_NAME); return StringUtils.isNotBlank(formToken); } /** * 生成一个新的表单,如果目前表单个数大于设定的最大表单数则先删除最早的一个表单。<br> * 新表单用RandomStringUtils.randomAlphanumeric(32)生成Token。 * * @return 创建的新表单 * @see #removeOldestForm(HttpServletRequest) * @see org.apache.commons.lang.RandomStringUtils#random(int) */ public Form newForm(HttpServletRequest request) { Form form = new Form(RandomStringUtils.randomAlphanumeric(32)); Map<String, Form> forms = getForms(request); synchronized (forms) { // 如果目前表单个数大于等于最大表单数,那么删除最老的表单,添加新表单。 if (forms.size() >= maxFormNum) { removeOldestForm(request); } forms.put(form.getToken(), form); } return form; } /** * 获得目前session中的表单列表。 * * @return 返回的Map中以表单的token为键,Form对象为值 */ @SuppressWarnings("unchecked") protected Map<String, Form> getForms(HttpServletRequest request) { Map<String, Form> formsInSession = null; HttpSession session = request.getSession(); synchronized (session) { formsInSession = (Map<String, Form>) session.getAttribute(SESSION_KEY_OF_FROMS); if (formsInSession == null) { formsInSession = new HashMap<String, Form>(); session.setAttribute(SESSION_KEY_OF_FROMS, formsInSession); } } return formsInSession; } /** * 删除最老的Form * * @see #destroyToken(HttpServletRequest, String) */ protected void removeOldestForm(HttpServletRequest request) { List<Form> forms = new ArrayList<Form>(getForms(request).values()); if (!forms.isEmpty()) { Form oldestForm = forms.get(0); for (Form form : forms) { if (form.getCreateTime().before(oldestForm.getCreateTime())) { oldestForm = form; } } destroyToken(request, oldestForm.getToken()); } } public void setMaxFormNum(int maxFormNum) { this.maxFormNum = maxFormNum; } }
Spring中的拦截器实现
package form; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; /** * 禁止表单重复提交拦截器 * * @author DigitalSonic */ public class DenyDuplicateFormSubmitInterceptor extends HandlerInterceptorAdapter { private FormManager formManager; public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { boolean flag = true; String token = request.getParameter(Form.FORM_UNIQ_ID_FIELD_NAME); if (token != null) { if (formManager.hasForm(request, token)) { formManager.destroyToken(request, token); } else { flag = false; throw new Exception("表单重复提交或过期,令牌[" + token + "]"); } } return flag; } public void setFormManager(FormManager formManager) { this.formManager = formManager; } }
在Spring MVC的HandlerMapping中配置该拦截器,随后在需要表单验证的Controller里做如下修改:
1、注入FormManager实例,主要是用newForm()生成一个新的Form对象
2、在返回的ModelAndView里加入该Form对象,假设名称是form
3、页面的表单中加入如下隐藏域
<input type="hidden" value="${form.token}" name="_form_uniq_id" />
代码中我去掉了些东西,应该还是能正常工作的,反正原理就是这么回事,呵呵。
发表评论
-
那些你该了解的Spring子项目
2013-03-20 14:39 1422去年年底,Spring Framework正式发布了3.2G ... -
《实战HotSpot JVM GC》分享Slides
2012-06-22 12:09 1718前阵子在QClub上海站做了一个与JVM GC优化相关的分享, ... -
如何简单模拟Web服务
2011-03-21 18:57 2174在SOA环境中,系统不可 ... -
代码中的坏味道
2011-01-07 04:09 1366最近InfoQ上连载了郑烨 ... -
isInfoEnabled究竟多有用?
2010-06-28 15:08 14490前段时间,公司里组织了一次代码检查,其中有一条检查项让我有些费 ... -
一个关于基于注解的Spring MVC的简单介绍
2009-05-26 17:52 2853前段时间给同事们做了一个关于Spring MVC的分享,简单介 ... -
实战Concurrent
2009-04-08 13:51 3895编写多线程的程序一直都是一件比较麻烦的事情,要考虑很多事情,处 ... -
Eclipse对JDK说“不”了
2008-09-30 21:21 1956最近开始翻译Spring Recipes了,既然是讲Sprin ... -
自己写的第一段AOP代码。
2005-04-13 22:36 1573代码1:使用安全的rand() ... -
FIFO、LRU、OPT的三个简单实现
2005-04-28 16:11 31911.利用随机数产生一个指令序列,共320条指令。其地址按下述原 ... -
JMeter小实验——JSP性能简单测试
2006-04-17 16:56 2448首先要做的当然是到Apache的站点下在一个最 ... -
利用缓存提高小型站点性能
2006-04-23 16:11 1215最近结束了 ... -
都是JDBC-ODBC惹得祸
2006-09-23 11:23 1166前阵子的一个项目需要 ... -
Fedora下瞎折腾了一个半小时,还是Sun的虚拟机可靠
2007-03-23 22:00 1195今天早上跑去了网络学院做技术支持, 他们碰到的问题是一个web ... -
一个泛型Hibernate DAO实现
2007-08-06 11:58 1720自己四处参考,写写抄抄折腾出来的一个泛型Hibernate D ... -
自己出的几道关于Spring和Hibernate的面试题
2008-02-29 16:49 2483很简单的题目,随便出着玩的,如果你是高手就请直接跳过,若有雷同 ... -
Spring MVC快速上手教程
2008-04-01 22:00 3056Spring Framework可以被使用在很多场合之中,考虑 ... -
一些关于Liferay的使用心得
2008-01-07 15:58 2141Liferay是一个出色的Java开源Portal产品,其中整 ...
相关推荐
客户端防表单重复提交和服务器端session防表单重复提交.
javascript方式防止表单重复提交,
springboot2.1+redis+拦截器 防止表单重复提交详细完整介绍,所用到的文件都上传了,下载即可使用。自己花了半天整理,并且测试通过,使用在实际项目中的,希望对每一个下载的朋友有帮助。
提交表单后提交禁用提交按钮,防止重复提交.
好友使用vue技术封装了一个专门用于提交表单和下载文件的“防抖按钮”,其实现原理和使用方法看这里 https://blog.csdn.net/PursueExcellence/article/details/103903139。
主要介绍了spring boot 防止重复提交实现方法,结合实例形式详细分析了spring boot 防止重复提交具体配置、实现方法及操作注意事项,需要的朋友可以参考下
防止表单重复提交。判断是新打开的页面还是刷新的页面 判断是新打开的页面还是刷新的页面
主要讲解了在structs怎样通过Token令牌解决表单重复提交的问题。附带了擦参考项目。
自定义封装注解类,(生成token存放到redis中)通过注解的方式解决API接口幂等设计防止表单重复提交
服务器端避免表单的重复提交,利用同步令牌来解决重复提交的基本原理如下:(1)用户访问提交数据的页面,服务器端在这次会话中,创建一个session对象,并产生一个令牌值,将这个令牌值作为隐藏输入域的值,随表单一起发送到...
先说对话框(Dialog)里的表单提交 错误方案 说起错误方案,比如,点击提交按钮,本地验证,验证通过立即让按钮不可点,这些没问题,而我的错误点概括是:在某个最后执行的回调函数的最后一行,我做了2个操作:1,...
基于springboot实现表单重复提交.docx
运用struts2解决表单的重复提交问题
struts2中对表单重复提交的处理方法;包括处理两种典型的表单重复提交的思路和方法
防止用户表单重复提交的完整demo 分别在js与后台中处理,js处理(针对网络慢情况) 后台处理(针对用户点击浏览器上的刷新按钮等)
当用户将信息提交到服务器,服务器响应采用forward方式调转到下一个页面后,此时地址栏中显示的是上个页面的URL,若刷新当前页面,浏览器会将再次提交用户先前输入的数据,就会再次出现表单重复提交的问题。...
如何修改禁止多次重复提交
今天小编就为大家分享一篇防止Layui form表单重复提交的实现方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
表单重复提交是在多用户Web应用中最常见、带来很多麻烦的一个问题。有很多的应用场景都会遇到重复提交问题,比如: 点击提交按钮两次。 点击刷新按钮。 使用浏览器后退按钮重复之前的操作,导致重复提交表单。 使用...
这是一个关于防止表单重复提交的练习,大神勿喷!