springmvc 防止表单重复提交的两种方法

目录
  • 1、通过session中的token验证
    • 步骤1:创建自定义注解
    • 步骤2:创建自定义拦截器(@slf4j是lombok的注解)
    • 步骤3:将自定义拦截器添加到配置文件
  • 2、通过当前用户上一次请求的url和参数验证重复提交
    • 步骤1:创建自定义注解
    • 步骤2:创建自定义拦截器
    • 步骤3:将自定义拦截器添加到配置文件

最近在本地开发测试的时候,遇到一个表单重复提交的现象。 因为网络延迟的问题,我点击了两次提交按钮,数据库里生成了两条记录。其实这种现象以前也有遇到过,一般都是提交后把按钮置灰,无法再次提交,这是很常见的客户端处理的方式。 但是这不是从根本上解决问题,虽然客户端解决了多次提交的问题,但是接口中依旧存在着问题。假设我们不是从客户端提交,而是被其他的系统调用,当遇到网络延迟,系统补偿的时候,还会遇到这种问题

1、通过session中的token验证

  • 初始化页面时生成一个唯一token,将其放在页面隐藏域和session中
  • 拦截器拦截请求,校验来自页面请求中的token与session中的token是否一致
  • 判断,如果一致则提交成功并移除session中的token,不一致则说明重复提交并记录日志

步骤1:创建自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
    boolean save() default false;
    boolean remove() default false;
}

步骤2:创建自定义拦截器(@slf4j是lombok的注解)

@Slf4j
public class RepeatSubmitInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        HandlerMethod handlerMethod = null;
        try {
            handlerMethod = (HandlerMethod)handler;
        } catch (Exception e) {
            return true;
        }
        Method method = handlerMethod.getMethod();

        Token token = method.getAnnotation(Token.class);
        if(token != null ){
            boolean saveSession = token.save();
            if(saveSession){
                request.getSession(true).setAttribute("token", UUID.randomUUID());
            }

            boolean removeSession = token.remove();
            if(removeSession){
                if(isRepeatSubmitSession(request)){
                    log.info("repeat submit session :" + request.getServletPath());
                    response.sendRedirect("/error/409");
                    return false;
                }
                request.getSession(true).removeAttribute("token");
            }
        }
        return true;
    }

    private boolean isRepeatSubmitSession(HttpServletRequest request){
        String sessionToken = String.valueOf(request.getSession(true).getAttribute("token") == null ? "" : request.getSession(true).getAttribute("token"));
        String clientToken =  String.valueOf(request.getParameter("token") == null ? "" : request.getParameter("token"));
        if(sessionToken == null || sessionToken.equals("")){
            return true;
        }
        if(clientToken == null || clientToken.equals("")){
            return true;
        }
        if(!sessionToken.equals(clientToken)){
            return true;
        }
        return false;
    }

}

步骤3:将自定义拦截器添加到配置文件

<mvc:interceptor>
 <mvc:mapping path="/**"/>
 <bean class="com.chinagdn.base.common.interceptor.RepeatSubmitInterceptor"/>
</mvc:interceptor>

使用案例

 //save = true 用于生成token
 @Token(save = true)
    @RequestMapping(value = "save", method = RequestMethod.GET)
    public String save(LoginUser loginUser, Model model) throws Exception {
        return "sys/user/edit";
    }
 //remove = true 用于验证token
 @Token(remove = true)
    @RequestMapping(value = "save", method = RequestMethod.POST)
    public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception {
     //.....
    }

jsp页面隐藏域添加token

 <input type="hidden" name="token" value="${sessionScope.token}">

2、通过当前用户上一次请求的url和参数验证重复提交

拦截器拦截请求,将上一次请求的url和参数和这次的对比
判断,是否一致说明重复提交并记录日志

步骤1:创建自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SameUrlData {

}

步骤2:创建自定义拦截器

public class SameUrlDataInterceptor extends HandlerInterceptorAdapter {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            Method method = handlerMethod.getMethod();
            //是否有 SameUrlData 注解
            SameUrlData annotation = method.getAnnotation(SameUrlData.class);
            if (annotation != null) {
                if (repeatDataValidator(request)) {//如果重复相同数据
                    response.sendRedirect("/error/409");
                    return false;
                } else {
                    return true;
                }
            }
            return true;
        } else {
            return super.preHandle(request, response, handler);
        }
    }

    /**
     * 验证同一个url数据是否相同提交  ,相同返回true
     * @param httpServletRequest
     * @return
     */
    private boolean repeatDataValidator(HttpServletRequest httpServletRequest) {
        String params = JsonMapper.toJsonString(httpServletRequest.getParameterMap());
        String url = httpServletRequest.getRequestURI();
        Map<String, String> map = new HashMap<>();
        map.put(url, params);
        String nowUrlParams = map.toString();//

        Object preUrlParams = httpServletRequest.getSession().getAttribute("repeatData");
        if (preUrlParams == null) { //如果上一个数据为null,表示还没有访问页面
            httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
            return false;
        } else { //否则,已经访问过页面
            if (preUrlParams.toString().equals(nowUrlParams)) { //如果上次url+数据和本次url+数据相同,则表示城府添加数据
                return true;
            } else { //如果上次 url+数据 和本次url加数据不同,则不是重复提交
                httpServletRequest.getSession().setAttribute("repeatData", nowUrlParams);
                return false;
            }
        }
    }
}

步骤3:将自定义拦截器添加到配置文件

<mvc:interceptor>
 <mvc:mapping path="/**"/>
 <bean class="com.chinagdn.base.common.interceptor.SameUrlDataInterceptor"/>
</mvc:interceptor>

使用案例

 //在controller层使用  @SameUrlData 注解即可
 @SameUrlData
    @RequestMapping(value = "save", method = RequestMethod.POST)
    public String save(@Valid LoginUser loginUser, Errors errors, RedirectAttributes redirectAttributes, Model model) throws Exception {
     //.....
    }

到此这篇关于springmvc 防止表单重复提交的两种方法的文章就介绍到这了,更多相关springmvc 防止表单重复提交内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springMVC中基于token防止表单重复提交方法

    本文介绍了springMVC中基于token防止表单重复提交方法,分享给大家,具体如下: 实现思路: 在springmvc配置文件中加入拦截器的配置,拦截两类请求,一类是到页面的,一类是提交表单的.当转到页面的请求到来时,生成token的名字和token值,一份放到Redis缓存中,一份放传给页面表单的隐藏域.(注:这里之所以使用redis缓存,是因为tomcat服务器是集群部署的,要保证token的存储介质是全局线程安全的,而redis是单线程的) 当表单请求提交时,拦截器得到参数中的toke

  • springmvc 防止表单重复提交的两种方法

    目录 1.通过session中的token验证 步骤1:创建自定义注解 步骤2:创建自定义拦截器(@slf4j是lombok的注解) 步骤3:将自定义拦截器添加到配置文件 2.通过当前用户上一次请求的url和参数验证重复提交 步骤1:创建自定义注解 步骤2:创建自定义拦截器 步骤3:将自定义拦截器添加到配置文件 最近在本地开发测试的时候,遇到一个表单重复提交的现象. 因为网络延迟的问题,我点击了两次提交按钮,数据库里生成了两条记录.其实这种现象以前也有遇到过,一般都是提交后把按钮置灰,无法再次提

  • js防止表单重复提交的两种方法

    第一种:用flag标识,下面的代码设置checkSubmitFlg标志: 复制代码 代码如下: <script language=""javascript""> var checkSubmitFlg = false; function checkSubmit(){ if(checkSubmitFlg ==true){ return false; //当表单被提交过一次后checkSubmitFlg将变为true,根据判断将无法进行提交. } checkS

  • php解决和避免form表单重复提交的几种方法

    前言 为什么要避免form表单被重复提交呢?因为我们不想让我们的服务器重复处理没必要的数据,同时我们也是避免我们的数据库产生重复的数据,避免表单重复提交也是让我们的网站更安全的一种表现. 先看一下有哪些情况下回导致表单重复提交呢,知道哪些情况下可能会出现表单重复提交就可以从根源处理表单重复提交的情况了. 下面的情况就会导致表单重复提交: 点击提交按钮两次. 点击刷新按钮. 使用浏览器后退按钮重复之前的操作,导致重复提交表单. 使用浏览器历史记录重复提交表单. 浏览器重复的HTTP请求. 网页被恶

  • 详谈表单重复提交的三种情况及解决方法

    第一种情况:提交完表单以后,不做其他操作,直接刷新页面,表单会提交多次. - 在servlet中写一句输出,用来判断是否提交多次 System.out.println("已经插入"); request.getRequestDispatcher("/login_success.jsp").forward(request, response); - 这样的话,刷新多少次,就会在控制器显示多少个"已经插入". - 根本原因:Servlet处理完请求以后

  • PHP防止表单重复提交的几种常用方法汇总

    本文较为详细的汇总了PHP防止表单重复提交的几种常用方法,在PHP程序开发中有着很高的实用价值.具体方法如下: 1. 使用JS让按钮在点击一次后禁用(disable).采用这种方法可以防止多次点击的发生,实现方式较简单. 缺点是若客户端禁止JavaScript脚本,则失效. 2. 在提交成功后执行页面重定向(redirect).转到提交成功信息页面. 特点:避免F5重复提交,消除浏览器前进和后退按钮可导致的同样问题. 3. 表单隐藏域中存放session(表单被请求时生成的标记).采用此方法在接

  • jQuery的 $.ajax防止重复提交的两种方法(推荐)

    下面给大家带来两种关于jquery 的ajax防止重复提交的解决方法,具体介绍如下所示: 1.第一种,对于onclick事件触发的的ajax 可以采用如下方法: 即在beforeSend中使点击按钮不可用,ajax结果返回后置为可用 $.ajax( { type: 'POST', url: APP+'?m=Shopping&a=ajaxSubmitorder&sid='+sid+'&src='+src, cache:false, dataType: 'json', data: {'

  • ASP.NET中防止页面刷新造成表单重复提交执行两次操作

    之前看过别人防刷新的方法,是让页面刷新或返回上一步让页面过期,这里介绍一种另类的方法,使用Session来处理. 实现原理: 由于刷新提交表单,实际上提交的就是上一次正常提交的表单,所以我们只要做一个标志,判断出是新表单还是上一次的旧表单就可以分辨出是否进行了重复提交操作. 实现方法: 在页面上放置一个Hidden域,当页面第一次载入的时候,在Session里面保存一个标志,同时,把这个标志保存到页面上的Hidden里面.在提交表单时,判断表单中提交上来的Hidden和Session中的标志是否

  • php 防止表单重复提交两种实现方法

    php 防止表单重复提交 由于网络原因,经常出来点了提交按钮,网页没有反应,而进行再次点击.这样就导致后台收到两次提交,从而进行两次处理,本文章向大家介绍php 防止表单重复提交的几种方法 1.前端解决 方法一: 可以通过前端来解决.当用户点了提交按钮之后,先使用js进行有效性判断,没问题后,将提交按钮"禁用"掉.然后再提交! 方法二: 使用ajax提交表单.点了提交按钮后,禁用提将按钮,或者设置一个状态值,将其设为1,表示正在提交.再提交时判断如果正在提交,则不作处理.等ajax返回

  • PHP+Session防止表单重复提交的解决方法

     index.php 当前表单页面is_submit设为0 SESSION_START(); $_SESSION['is_submit'] = 0; <form id="reg" action="post.php" method="post"> <p>用户名:<input type="text" class="input" name="username" i

  • springMVC如何防止表单重复提交详解

    目录  前言 防止表单重复提交 单机 实现的思路步骤 代码实现 分布式 实现的思路步骤 代码实现 总结  前言 在系统中,有些接口如果重复提交,可能会造成脏数据或者其他的严重的问题,所以我们一般会对与数据库有交互的接口进行重复处理 首先可以在前端做一层控制.当前端触发操作时,或弹出确认界面,或 disable 禁用按钮等等,但是这并不能彻底解决问题.假设我们不是从客户端提交,而是被其他的系统调用,还会遇到这种问题 为了彻底解决问题,还需要在后端对接口做防重处理 一般会引起表单重复提交的场景 在网

随机推荐