您好,登錄后才能下訂單哦!
本篇文章為大家展示了redis分布式鎖如何解決表單重復提交的問題,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
假如用戶的網速慢,用戶點擊提交按鈕,卻因為網速慢,而沒有跳轉到新的頁面,這時的用戶會再次點擊提交按鈕,舉個例子:用戶點擊訂單頁面,當點擊提交按鈕的時候,也許因為網速的原因,沒有跳轉到新的頁面,這時的用戶會再次點擊提交按鈕,如果沒有經過處理的話,這時用戶就會生成兩份訂單,類似于這種場景都叫重復提交。
使用redis的setnx和getset命令解決表單重復提交的問題。
1.引入redis依賴和aop依賴
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-redis</artifactId> <version>1.3.8.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
2.編寫加鎖和解鎖的方法。
/** * @author wangbin * @description redis分布式鎖 * @date 2019年09月20日 */ @Component public class RedisLock { private final Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowired private StringRedisTemplate redisTemplate; /** * @author wangbin * @description 進行加鎖的操作(該方法是單線程運行的) * @date 2019年09月20日 * @param key 某個方法請求url加上cookie中的用戶身份使用md5加密生成 * @param value 當前時間+過期時間(10秒) * @return true表示加鎖成功 false表示未獲取到鎖 */ public boolean lock(String key,String value){ //加鎖成功返回true if(redisTemplate.opsForValue().setIfAbsent(key,value,10, TimeUnit.SECONDS)){ return true; } String currentValue = redisTemplate.opsForValue().get(key); //加鎖失敗,再判斷是否由于解鎖失敗造成了死鎖的情況 if(StringUtils.isNotEmpty(currentValue) && Long.parseLong(currentValue) < System.currentTimeMillis()){ //獲取上一個鎖的時間,并且重新設置鎖 String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if(StringUtils.isNotEmpty(oldValue) && oldValue.equals(currentValue)){ //設置成功,重新設置鎖是保證了單線程的運行 return true; } } return false; } /** * @author wangbin * @description 進行解鎖的操作 * @date 2019年09月20日 * @param key 某個方法請求url使用md5加密生成 * @param value 當前時間+過期時間 * @return */ public void unLock(String key,String value){ try { String currentValue = redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue) && currentValue.equals(value)){ redisTemplate.delete(key); } }catch (Exception e){ logger.error("redis分布式鎖,解鎖異常",e); } } /** * @author wangbin * @description 進行解鎖的操作 * @date 2019年09月20日 * @param key 某個方法請求url使用md5加密生成 * @return */ public void unLock(String key){ try { String currentValue = redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue)){ redisTemplate.delete(key); } }catch (Exception e){ logger.error("redis分布式鎖,解鎖異常",e); } } }
3.使用攔截器在請求之前進行加鎖的判斷。
@Configuration public class LoginInterceptor extends HandlerInterceptorAdapter { private final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); //超時時間設置為10秒 private static final int timeOut = 10000; @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisLock redisLock; /** * 在請求處理之前進行調用(Controller方法調用之前) * 基于URL實現的攔截器 * @param request * @param response * @param handler * @return * @throws Exception */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String path = request.getServletPath(); if (path.matches(Constants.NO_INTERCEPTOR_PATH)) { //不需要的攔截直接過 return true; } else { // 這寫你攔截需要干的事兒,比如取緩存,SESSION,權限判斷等 //判斷是否是重復提交的請求 if(!redisLock.lock(DigestUtils.md5Hex(request.getRequestURI()+value),String.valueOf(System.currentTimeMillis()+timeOut))){ logger.info("===========獲取鎖失敗,該請求為重復提交請求"); return false; } return true; } } }
4.使用aop在后置通知中進行解鎖。
/** * @author wangbin * @description 使用redis分布式鎖解決表單重復提交的問題 * @date 2019年09月20日 */ @Aspect @Component public class RepeatedSubmit { @Autowired private RedisLock redisLock; //定義切點 @Pointcut("execution(public * com.kunluntop.logistics.controller..*.*(..))") public void pointcut(){ } //在方法執行完成后釋放鎖 @After("pointcut()") public void after(){ ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); redisLock.unLock(DigestUtils.md5Hex(request.getRequestURI()+ CookieUtils.getCookie(request,"userkey"))); } }
上述內容就是redis分布式鎖如何解決表單重復提交的問題,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。