Springboot 限制按鈕點選頻率
阿新 • • 發佈:2019-02-01
場景:
實際專案中某個頁面如果連續點選更改或新增按鈕時,後臺程式碼呼叫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; @Overridepublic 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秒之內不響應請求。大功告成!^__^