现象描述
最近在开发的时候,遇见这样的问题,当我们在网络状况不太好的情况、或者一个业务的后台业务逻辑执行时间较长的时候,用户可能会点击多次提交或刷新多次页面,导致表单数据被提交了多次,导致了可能出现莫名其妙的问题,解决这个问题,我们可以使用session加token的方式进行解决。
方案
JSP代码:
<%@ page import="java.util.UUID" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<%@ page contentType="text/html;charset=UTF-8" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>test jsp</title>
</head>
<body>
<%
String token = UUID.randomUUID().toString().replaceAll("-","");
session.setAttribute("token",token);
%>
<form id="form1" method="post" action="/user/doSomething.do">
username : <input type="text" id="username" value=""/>
password : <input type="text" id="password" value=""/>
<input type="hidden" name="formtoken" value="<%=token%>" >
<input type="submit" value="submit"/>
</form>
</body>
</html>
Controller层:
@Controller
@RequestMapping(value="user")
public class UserController {
@RequestMapping(value="doSomething.do")
public String doSometing(String username, String password, HttpServletRequest request, RedirectAttributes attr) {
String formToken = request.getParameter("formtoken");
HttpSession session = request.getSession();
String token = (String)session.getAttribute("token");
if (formToken.equals(token)) {
session.removeAttribute("token");
} else {
attr.addFlashAttribute("msg", "请不要重复提交!");
return "redirect:error";
}
}
}
如果有多个Controller的方法都需要进行校验,可以写一个单独的校验方法,使用@ModelAttribute注解,这样让它在所有方法执行之前执行,校验是否表单重复提交了
@Controller
@RequestMapping(value="user")
public class UserController {
@ModelAttribute
public void checkForm(HttpServletRequest request, Model model) {
String formToken = request.getParameter("formtoken");
HttpSession session = request.getSession();
String token = (String)session.getAttribute("token");
if (formToken.equals(token)) {
session.removeAttribute("token");
model.addAttribute("checkResult", "success");
} else {
model.addAttribute("checkResult", "fail");
}
}
@RequestMapping(value="doSomething.do")
public String doSometing(@ModelAttribute String checkResult, String username, String password, RedirectAttributes attr) {
if (checkResult != null && checkResult.equals("success"))
{
doSomething(username, password);
} else {
attr.addFlashAttribute("msg","请不要重复提交");
return "redirect:error";
}
}
}
原理
当多次提交的时候,session中的token已经更新,但是form中的token没有变化,因此可以用此进行校验。