防止表单重复提交的思路

面试时遇到一个题:怎么防止表单重复提交?

当时想了想,这个题不是很难,简单来说就是验证的问题。于是我很容易想到session。

因为session的原理和这个很像。

我的思路:在表单中加入隐藏字段,作为这个表单的唯一标识。同时再session中记录这个表单的提交次数。

下次再提交,就是重复提交的时候,从session中获取提交次数,判断一下就可以了。


下面给出我的例子:

先写一个简单的新增的操作。

IsRepeatSubmitAction

package org.test.submit.action;

import java.io.PrintWriter;
import java.util.Date;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.apache.struts2.ServletActionContext;
import org.base.MyBaseAction;
import org.base.pk.UUIDHexGenerator;
import org.test.submit.bean.Develpoer;
import org.test.submit.dao.SubmitDao;

import com.opensymphony.xwork2.ActionContext;

public class IsRepeatSubmitAction  extends MyBaseAction {
	private static final long serialVersionUID = 1L;
	
	public String execute() throws Exception{
		String pk_userId=(String)UUIDHexGenerator.generate();//生成主键
		
		this.getHttpServletRequest().setAttribute("userId", pk_userId);//放入页面表单的隐藏字段中
		this.getHttpSession().setAttribute(pk_userId.trim(), 0);//放入session中
		
		return SUCCESS;
	}	
	public String goSubmit() throws Exception{
		//
		ActionContext ctx = ActionContext.getContext();
		HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE); 
		HttpServletRequest request  = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
		HttpSession  session  = request.getSession();
		response.setCharacterEncoding("UTF-8");
		PrintWriter out = response.getWriter();
		
		String pk_userId_from_page="";//从页面的隐藏字段获取主键
		if(this.getDevelpoer()==null){
			System.out.println("获取表单错误!");
		}else{
			pk_userId_from_page=(this.getDevelpoer().getUserId()!=null)?(String)this.getDevelpoer().getUserId().trim():"";
			if(pk_userId_from_page.equals("")){
				System.out.println("传参错误!");
			}else{
				System.out.println("主键userId:"+pk_userId_from_page);
				if(this.getHttpSession().getAttribute(pk_userId_from_page)==null){
					System.out.println("表单已过期!!");
				}else{
					int pk_userId_count=(Integer)this.getHttpSession().getAttribute(pk_userId_from_page);//获取该主键提交的次数(没提交是0;提交过是1)
					if(pk_userId_count==0){
						this.getHttpSession().setAttribute(pk_userId_from_page, 1);//置成1--已提交
						String addres=submitDao.addDeveloper(this.getDevelpoer());//插入数据
						if(addres.equals("success")){
							System.out.println("成功写库!"+new Date().toString());
						}else{
							System.out.println("写库失败!请联系管理员!"+new Date().toString());
						}
					}else{
						System.out.println("您已提交过表单!");
					}
				}
				
			}
			
		}
		
		return NONE;
	}
	
	
	
	private SubmitDao submitDao;

	public SubmitDao getSubmitDao() {
		return submitDao;
	}
	public void setSubmitDao(SubmitDao submitDao) {
		this.submitDao = submitDao;
	}
	private Develpoer develpoer;

	public Develpoer getDevelpoer() {
		return develpoer;
	}
	public void setDevelpoer(Develpoer develpoer) {
		this.develpoer = develpoer;
	}
	
}

pojo:Develpoer

package org.test.submit.bean;

public class Develpoer {
	private String userId;
	private String userName;
	private String realName;
	
	public String getUserId() {
		return userId;
	}
	public void setUserId(String userId) {
		this.userId = userId;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getRealName() {
		return realName;
	}
	public void setRealName(String realName) {
		this.realName = realName;
	}
}

SubmitDao

package org.test.submit.dao;

import org.test.submit.bean.Develpoer;

public interface SubmitDao {
	public String addDeveloper(Develpoer develpoer);
}

SubmitDaoImpl

package org.test.submit.dao.impl;

import org.base.MyHibernateDao;
import org.test.submit.bean.Develpoer;
import org.test.submit.dao.SubmitDao;

public class SubmitDaoImpl extends MyHibernateDao implements SubmitDao{

	public String addDeveloper(Develpoer develpoer) {
//		String userId,String userName,String realName
		String res="fail";
		if(develpoer==null){
			
		}else if(develpoer.getUserId()==null||develpoer.getUserId().trim().equals("")){
			res="fail";
		}else{
			String uname=(develpoer.getUserName()==null)?"":develpoer.getUserName().trim();
			String rname=(develpoer.getRealName()==null)?"":develpoer.getRealName().trim();
			String sql="insert into lsy_user_develop(USER_ID, USER_NAME, REAL_NAME) " +
					" values('"+develpoer.getUserId().trim()+"','"+uname+"','"+rname+"')";
			this.executeSql(sql);
			res="success";
		}
		
		return res;
	}

}

struts_submit.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="submit" extends="base-struts-default" namespace="/submit">
	    <!-- 防止表单重复提交 -->	
		<action name="addDeveloper" class="org.test.submit.action.IsRepeatSubmitAction">
		   <result name="success">/jsp/test/repeat.jsp</result>
		</action>
		<action name="goSubmit" class="org.test.submit.action.IsRepeatSubmitAction" method="goSubmit">
		</action>
	</package>
</struts>

context_submit.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

    <bean id="submitDaoTarget" class="org.test.submit.dao.impl.SubmitDaoImpl">
		<property name="sessionFactory">
			<ref bean="sessionFactory"/>
		</property>
	</bean>
	<bean id="submitDao" parent="transactionProxyTemplate">
		<property name="target" ref="submitDaoTarget" />
		<property name="proxyInterfaces">
			<value>org.test.submit.dao.SubmitDao</value>
		</property>
	</bean>
</beans>

页面;

repeat.jsp

<%@ page contentType="text/html; charset=UTF-8"%>
<%@page import="java.util.*"%>
<% 
String path = request.getContextPath();
%>
<% 
String pk_userId="";
if(request.getAttribute("userId")!=null){
	pk_userId=(String)request.getAttribute("userId");
}
%>
<html>
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
	<title></title>
	<script src="<%=path%>/script/jquery-1.7.1.min.js" type="text/javascript"></script>	
<style type="text/css"> 
td,th { 
font-family: 宋体, Arial; 
font-size: 12px; 
}

th { 
font: bold 11px "Trebuchet MS", Verdana, Arial, Helvetica, sans-serif; 
color: #4f6b72; 
border-right: 1px solid #C1DAD7; 
border-bottom: 1px solid #C1DAD7; 
border-top: 1px solid #C1DAD7; 
letter-spacing: 2px; 
text-transform: uppercase; 
text-align: left; 
padding: 6px 6px 6px 12px; 
background: #CAE8EA  no-repeat; 
} 



td { 
border-right: 1px solid #C1DAD7; 
border-bottom: 1px solid #C1DAD7; 
background: #ECFFFF; 
font-size:11px; 
padding: 6px 6px 6px 12px; 
color: #4f6b72; 
} 

td.other { 
border-right: 1px solid #C1DAD7; 
border-bottom: 1px solid #C1DAD7; 
background: #FFFFDF; 
font-size:11px; 
padding: 6px 6px 6px 12px; 
color: #4f6b72; 
}
</style> 
</head>
<body style="overflow: scroll; overflow: auto;">
<input type="hidden" name="path" id="path" value='<%=path%>' ></input>

<form id="form1" action="<%=path%>/submit/goSubmit.action" method="GET">
<input type="hidden" id="" name="develpoer.userId" value="<%=pk_userId%>"></input>

<table id="table1" cellspacing="0" style="width:700px; padding: 0; margin: 0;">
	<tr> 
	  <th>账号</th> 
	  <th>昵称</th> 
	</tr>

	<tr> 
	  <td><input type="text" id="" name="develpoer.userName"></input></td> 
	  <td><input type="text" id="" name="develpoer.realName"></input></td>
	</tr> 

	<tr>
	  <td class="other" colspan="1"><input type="button" value="提交" οnclick="goSubmit()"></input></td>
	  <td class="other" colspan="1"><input type="button" value="取消" οnclick="clear()"></input></td>
	</tr>
</table>
</form>

</body>
</html> 
<script type="text/javascript">	

function goSubmit(){
	document.all.form1.submit();
	
}

function clear(){
	$("input['name=develpoer.userName']").val("");
	$("input['name=develpoer.realName']").val("");
}

</script>

实验:在页面填入数据,点击提交按钮,打印:

主键userId:f6463fb03dbae37b013dbae37b680000
Hibernate: insert into lsy_user_develop(USER_ID, USER_NAME, REAL_NAME)  values('f6463fb03dbae37b013dbae37b680000','55','555')
成功写库!Sat Mar 30 18:42:50 CST 2013


成功提交后,按F5刷新页面:

打印:
主键userId:f6463fb03dbae37b013dbae37b680000
您已提交过表单!


或者点击浏览器的回退按钮回到刚才的页面,再点击提交。打印:
主键userId:f6463fb03dbae37b013dbae37b680000
您已提交过表单!


好,从结果上看,这个思路是可行的!


############################-----分割-----################################

从网上搜了一下,struts2有个防止表单重复提交的标签<s: token />,配合拦截器 <interceptor-ref name="token" />来使用。

大体是:

在页面加载时,<s: token />产生一个GUID(Globally Unique Identifier,全局唯一标识符)值的隐藏输入框
同时,将GUID放到会话(session)中;在执行action之前,“token”拦截器将会话token与请求token比较,如果两者相同,则将会话中的token删除并往下执行,否则向actionErrors加入错误信息。如此一来,如果用户通过某种手段提交了两次相同的请求,两个token就会不同。

##################################################

我想这个原理和我想到的解决方案大同小异。只不过struts2把这个写入了标签库和拦截器中。

具体逻辑上strus2根据session是否有这个唯一标识来判断,我根据这个标识的提交次数来判断的。

从实施上,我们完全不必要使用struts2的方案,因为我不喜欢struts2的标签库。只要懂了原理,自己照样能实现。




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值