Springboot 限制按钮点击频率

7 篇文章 0 订阅
3 篇文章 0 订阅

场景:

            实际项目中某个页面如果连续点击更改或新增按钮时,后台代码调用saveAndFlush()方法后 有可能会出现数据库中被插入重复数据的现象。

分析: 

            经过分析后发现,当saveAndFlush方法开始操作数据库但未完成的时候,第二个请求也调用了saveAndFlush方法的时候,由于项目配置了数据库连接池,所以系统会重新建立一个数据库连接来完成操作,所以会偶尔出现相同数据被保存到数据库产生脏数据的现象。

解决:

            原因知道了,解决就很简单了,90%的解决办法都是在前端用js来进行控制,请求发出后立即设按钮不可用,结果返回后再将按钮设置为可用,这样做可行,但是我个人比较懒不喜欢每个按钮都去写一遍。

我的解决方法

            用全局拦截器拦截所有请求,用注解标注需要被拦截的方法,有注解的进行延时处理,没有的就全部放行,代码如下:

            1、创建一个注解类(默认延时1秒)

                

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface Delay {
    int time() default 1000;
}

        2、创建拦截器

package com.lhzs.springdemo.interceptor;

import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

public class DelayInterceptor implements HandlerInterceptor {

    private long lastTime = 0;

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        //开始进入请求地址拦截
        HandlerMethod hm = (HandlerMethod) o;
        Delay delay = hm.getMethodAnnotation(Delay.class);
        if (delay != null) {
            return startDelay(delay.time());
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        //处理请求完成后视图渲染之前的处理操作
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        //视图渲染之后的操作
    }

    private boolean startDelay(int time) {
        long currentTime = System.currentTimeMillis();
        if (currentTime - lastTime > time) {
            lastTime = currentTime;
            return true;
        }
        return false;
    }
}

        3、在需要进行延时处理的方法上用@Delay注解进行标注

@Delay(time = 2000)
@RequestMapping(value = "dic/getDicAll")
@ResponseBody
public List<DicModel> getDicAll() {
    return ds.findAll();
}

            4、springboot配置拦截器

/**
 * 配置自定义拦截器
 */
@Override
public void addInterceptors(InterceptorRegistry registry) {
    //注册自定义拦截器,添加拦截路径和排除拦截路径
    registry.addInterceptor(new DelayInterceptor())
            .addPathPatterns("/**");
}

点击按钮访问 dic/getDicAll 接口后2秒之内不响应请求。大功告成!^__^


  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值