一个业务真实场景:在执行表单保存的时候,由于网络延迟等原因,点击保存按钮直接刷新页面,浏览器会重复提交表单信息导致数据库插入两条数据,这种情况控制保存按钮不能解决,设置主键约束太过暴力,我们可以利用session防止表单重复提交。
1.表单重复提交可能性原因
1、由于用户误操作,多次点击表单提交按钮。
2、由于网速等原因造成页面卡顿,用户重复刷新提交页面。
3、黑客或恶意用户重复恶意提交表单(攻击网站)。
2.利用session防止表单重复提交
1、获取用户填写用户名和密码的页面时向后台发送一次请求,这时后台会生成唯一的随机标识号,专业术语称为Token(令牌)。
2、将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。
3、服务器端判断客户端提交上来的Token与服务器端生成的Token是否一致,如果不一致,那就是重复提交了,此时服务器端就可以不处理重复提交的表单。如果相同则处理表单提交,处理完后清除当前用户的Session域中存储的标识号
3.代码范例(java+jsp)
- 在controlle层生成Token(令牌)和跳转到jsp页面
@RequestMapping("/")
public ModelAndView get(HttpServletRequest request){
String token = UUID.randomUUID().toString() ;//创建令牌
request.getSession().setAttribute("token", token); //在服务器使用session保存token(令牌)
String url = "跳转的页面";
return new ModelAndView(url, "");
}
- 在jsp页面中使用隐藏域来存储Token(令牌),随着表单保存时候提交到后台。
<input type="hidden" name="token" value="<%=session.getAttribute("token") %>">
- 在表单提交的controller中判断是否是重复提交
@RequestMapping("/save")
public ModelAndView save(){
if(!repeatResult){//不是重复提交,调用保存接口并删除session
//调用service业务处理层接口
request.getSession().removeAttribute("token");//移除session中的token
}
}
/**
* 判断客户端提交上来的令牌和服务器端生成的令牌是否一致
* @param request
* @return
* true 用户重复提交了表单
* false 用户没有重复提交表单
*/
public static boolean isRepeatSubmit(HttpServletRequest request) {
String client_token = request.getParameter("token");
//1、如果用户提交的表单数据中没有token,则用户是重复提交了表单
if(client_token==null){
return true;
}
//取出存储在Session中的token
String server_token = (String) request.getSession().getAttribute("token");
//2、如果当前用户的Session中不存在Token(令牌),则用户是重复提交了表单
if(server_token==null){
return true;
}
//3、存储在Session中的Token(令牌)与表单提交的Token(令牌)不同,则用户是重复提交了表单
if(!client_token.equals(server_token)){
return true;
}
return false;
}