1. 程式人生 > >Springboot 限制按鈕點選頻率

Springboot 限制按鈕點選頻率

場景:

            實際專案中某個頁面如果連續點選更改或新增按鈕時,後臺程式碼呼叫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秒之內不響應請求。大功告成!^__^