我们在进行web开发的时候,必不可少会遇见表单重复提交问题,那么,在什么情况下会产生表单重复提交的情况呢?
1、在网络延迟的情况下让用户有时间点击多次submit按钮导致表单重复提交。
2、表单提交后用户点击【刷新】按钮导致表单重复提交。
3、用户提交表单后,点击浏览器的【后退】按钮回退到表单页面后进行再次提交。
利用JavaScript也可以防止表单重复提交,例如:
1、通过设立标识使表单不能重复提交。
2、一次点击后使得提交按钮变成不可用。
但是此方法对于前进后退操作,或者F5刷新页面等问题并不能得到解决。最重要的一点,前端的代码只能防止不懂js的用户,如果碰到懂得js的编程人员,那js方法就没用了。
利用Session防止表单重复提交,以上三种情况都能解决,具体的做法如下:
1、向表单页面跳转的同时后台会生成唯一的标识,专业术语称为Token(令牌)。
2、将Token发送到客户端的Form表单中,在Form表单中使用隐藏域来存储这个Token,表单提交的时候连同这个Token一起提交到服务器端。
3、服务器端利用过滤器来判断客户端提交上来的Token与服务器端session中的Token是否一致,如果不一致,那就是重复提交了。如果相同则处理表单提交,处理完后清除当前用户的session中存储的标识。
看具体的操作
1、编写生成token的工具类,采用单例模式,保证该类的对象在内存中只有一个,节约内存资源。
package com.example.test.utils;
import java.util.UUID;
/**
* 生成令牌工具类
* 单例模式,保证类的对象在内存中只有一个
*/
public class TokenGenertor {
//构造器私有
private TokenGenertor() {}
//对象自己创建
private static final TokenGenertor instance = new TokenGenertor();
//对外提供一个公开的方法,返回类的对象
public static TokenGenertor getInstance(){
return instance;
}
//生成令牌
public String getToken(){
String uuid = UUID.randomUUID().toString();
uuid = uuid.replace("-","").toUpperCase();
return uuid;
}
}
2、编写token过滤器来验证表单是否为重复提交
package com.example.test.filter;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* 表单提交指令过滤器
*/
@Component
@WebFilter(filterName = "tokenFilter",urlPatterns = "/*")
@Order(1)
public class TokenFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) servletRequest;
response = (HttpServletResponse) servletResponse;
HttpSession session = request.getSession();
//获取session中的指令
String sToken = (String)session.getAttribute("token");
//获取页面提交的指令
String rToken = request.getParameter("token");
if (rToken != null){
if (!rToken.equals(sToken)){
//指令不匹配,提示重复提交
response.getWriter().write("请不要重复提交");
return;
}
//指令匹配,删除session中的指令
session.removeAttribute("token");
}
filterChain.doFilter(request,response);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void destroy() {
}
}
3、看Controller中代码
@Controller
@RequestMapping("/test")
public class TestController {
@RequestMapping("/hello")
public String hello(HttpServletRequest request){
//生成指令
String token = TokenGenertor.getInstance().getToken();
//绑定到session中
request.getSession().setAttribute("token",token);
//传给表单页面
request.setAttribute("token",token);
return "hello";
}
}
利用session方法解决表单重复问题是十分完美的,基本上可以应对各种重复提交问题。在实际的项目中前端和后端都要防止重复提交。
网友评论