最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot通過Redis實現(xiàn)防止重復(fù)提交

 更新時間:2024年06月28日 09:57:22   作者:信仰_273993243  
表單提交是一個非常常見的功能,如果不加控制,容易因為用戶的誤操作或網(wǎng)絡(luò)延遲導(dǎo)致同一請求被發(fā)送多次,本文主要介紹了Spring Boot通過Redis實現(xiàn)防止重復(fù)提交,具有一定的參考價值,感興趣的可以了解一下

一、什么是冪等。

1、什么是冪等:相同的條極下,執(zhí)行多次結(jié)果拿到的結(jié)果都是一樣的。舉個例子比如相同的參數(shù)情況,執(zhí)行多次,返回的數(shù)據(jù)都是樣的。那什么情況下要考慮冪等,重復(fù)新增數(shù)據(jù)。

2、解決方案:解決的方式有很多種,本文使用的是本地鎖。

二、實現(xiàn)思路

1、首先我們要確定多少時間內(nèi),相同請求參數(shù)視為一次請求,比如2秒內(nèi)相同參數(shù),無論請求多少次都視為一次請求。

2、一次請求的判斷依據(jù)是什么,肯定是相同的形參,請求相同的接口,在1的時間范圍內(nèi)視為相同的請求。所以我們可以考慮通過參數(shù)生成一個唯一標識,這樣我們根據(jù)唯一標識來判斷。

三、代碼實現(xiàn)

1、這里我選擇spring的redis來實現(xiàn),但如果有集群的情況,還是要用集群redis來處理。當?shù)谝淮潍@取請求時,根據(jù)請求url、controller層調(diào)用的方法、請求參數(shù)生成MD5值這三個條件作為依據(jù),將其作為redis的key和value值,并設(shè)置失效時間,當在失效時間之內(nèi)再次請求時,根據(jù)是否已存在key值來判斷接收還是拒絕請求來實現(xiàn)攔截。

2、pom.xml依賴

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
	<exclusions>
		<exclusion>
			<groupId>io.lettuce</groupId>
			<artifactId>lettuce-core</artifactId>
		</exclusion>
	</exclusions>
	<version>2.0.6.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.aspectj</groupId>
	<artifactId>aspectjweaver</artifactId>
	<version>1.8.9</version>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>2.9.1</version>
</dependency>
<dependency>
	<groupId>org.apache.commons</groupId>
	<artifactId>commons-pool2</artifactId>
	<version>2.6.0</version>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>fastjson</artifactId>
	<version>1.2.31</version>
</dependency>

3、在application.yml中配置redis

spring:
  redis:
    database: 0
    host: XXX
    port: 6379
    password: XXX
    timeout: 1000
    pool:
      max-active: 1
      max-wait: 10
      max-idle: 2
      min-idle: 50

4、自定義異常類IdempotentException

package com.demo.controller;
public class IdempotentException extends RuntimeException {
	public IdempotentException(String message) {
		super(message);
	}
	
	@Override
	public String getMessage() {
		return super.getMessage();
	}
}

5、自定義注解

package com.demo.controller;
 
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Idempotent {
	// redis的key值一部分
	String value();
	// 過期時間
	long expireMillis();
}

6、自定義切面

package com.demo.controller;
import java.lang.reflect.Method;
import java.util.Objects;
import javax.annotation.Resource;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisCommands;
 
@Component
@Aspect
@ConditionalOnClass(RedisTemplate.class)
public class IdempotentAspect {
	private static final String KEY_TEMPLATE = "idempotent_%s";
 
	@Resource
	private RedisTemplate<String, String> redisTemplate;
 
	//填寫掃描加了自定義注解的類所在的包。
	@Pointcut("@annotation(com.demo.controller.Idempotent)")
	public void executeIdempotent() {
 
	}
 
	@Around("executeIdempotent()")  //環(huán)繞通知
	public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
		Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
		Idempotent idempotent = method.getAnnotation(Idempotent.class);
        //注意Key的生成規(guī)則		
String key = String.format(KEY_TEMPLATE,
				idempotent.value() + "_" + KeyUtil.generate(method, joinPoint.getArgs()));
		String redisRes = redisTemplate
				.execute((RedisCallback<String>) conn -> ((JedisCommands) conn.getNativeConnection()).set(key, key,
						"NX", "PX", idempotent.expireMillis()));
		if (Objects.equals("OK", redisRes)) {
			return joinPoint.proceed();
		} else {
			throw new IdempotentException("Idempotent hits, key=" + key);
		}
	}
}

//注意這里不需要釋放鎖操作,因為如果釋放了,在限定時間內(nèi),請求還是會再進來,所以不能釋放鎖操作。

7、Key生成工具類

package com.demo.controller;
 
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
 
import com.alibaba.fastjson.JSON;
 
public class KeyUtil {
	public static String generate(Method method, Object... args) throws UnsupportedEncodingException {
		StringBuilder sb = new StringBuilder(method.toString());
		for (Object arg : args) {
			sb.append(toString(arg));
		}
		return md5(sb.toString());
	}
 
	private static String toString(Object object) {
		if (object == null) {
			return "null";
		}
		if (object instanceof Number) {
			return object.toString();
		}
		return JSON.toJSONString(object);
	}
 
	public static String md5(String str) {
		StringBuilder buf = new StringBuilder();
		try {
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(str.getBytes());
			byte b[] = md.digest();
			int i;
			for (int offset = 0; offset < b.length; offset++) {
				i = b[offset];
				if (i < 0)
					i += 256;
				if (i < 16)
					buf.append(0);
				buf.append(Integer.toHexString(i));
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		return buf.toString();
	}

8、在Controller中標記注解

package com.demo.controller;
 
import javax.annotation.Resource;
 
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
 
@RestController
public class DemoController {
	@Resource
	private RedisTemplate<String, String> redisTemplate;
	
	@PostMapping("/redis")
	@Idempotent(value = "/redis", expireMillis = 5000L)
	public String redis(@RequestBody User user) {
		return "redis access ok:" + user.getUserName() + " " + user.getUserAge();
	}
}

到此這篇關(guān)于Spring Boot通過Redis實現(xiàn)防止重復(fù)提交的文章就介紹到這了,更多相關(guān)SpringBoot Redis防止重復(fù)提交內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家! 

相關(guān)文章

  • Jackson處理Optional時遇到問題的解決與分析

    Jackson處理Optional時遇到問題的解決與分析

    Optional是Java實現(xiàn)函數(shù)式編程的強勁一步,并且?guī)椭诜妒街袑崿F(xiàn),但是Optional的意義顯然不止于此,下面這篇文章主要給大家介紹了關(guān)于Jackson處理Optional時遇到問題的解決與分析的相關(guān)資料,需要的朋友可以參考下
    2022-02-02
  • Spring Boot WebSocket 兩種集成方式詳解

    Spring Boot WebSocket 兩種集成方式詳解

    WebSocket 是實現(xiàn)服務(wù)器主動推送、實時通信的利器,常見于聊天室、消息通知、實時監(jiān)控大屏等場景,本文詳細介紹了SpringBoot集成WebSocket的兩種方式,感興趣的朋友跟隨小編一起看看吧
    2026-05-05
  • 使用Java實現(xiàn)價格加密與優(yōu)化功能

    使用Java實現(xiàn)價格加密與優(yōu)化功能

    在現(xiàn)代軟件開發(fā)中,數(shù)據(jù)加密是一個非常重要的環(huán)節(jié),尤其是在處理敏感信息(如價格、用戶數(shù)據(jù)等)時,本文將詳細介紹如何使用?Java?實現(xiàn)價格加密,并對代碼進行優(yōu)化,需要的朋友可以參考下
    2025-01-01
  • 深入解析Java的Hibernate框架中的持久對象

    深入解析Java的Hibernate框架中的持久對象

    Hibernate的持久對象在數(shù)據(jù)庫數(shù)據(jù)操作中有著重要作用,這里我們就來深入解析Java的Hibernate框架中的持久對象,首先必須從理解持久化對象的生命周期開始:
    2016-07-07
  • Spring Boot 配置大全(小結(jié))

    Spring Boot 配置大全(小結(jié))

    本篇文章主要介紹了Spring Boot 配置大全(小結(jié)),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-11-11
  • java實現(xiàn)簡單的圖書管理系統(tǒng)

    java實現(xiàn)簡單的圖書管理系統(tǒng)

    這篇文章主要為大家詳細介紹了java實現(xiàn)簡單的圖書管理系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • 關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用

    關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用

    這篇文章主要介紹了關(guān)于SpringMVC的數(shù)據(jù)綁定@InitBinder注解的使用,在SpringMVC中,數(shù)據(jù)綁定的工作是由 DataBinder 類完成的,DataBinder可以將HTTP請求中的數(shù)據(jù)綁定到Java對象中,需要的朋友可以參考下
    2023-07-07
  • Java反射與注解的詳細講解(含代碼)

    Java反射與注解的詳細講解(含代碼)

    注解和反射應(yīng)該說是后期JAVA開發(fā)里面比較重要的技術(shù)了,通過注解和反射可以簡化許許多多的操作和步驟,最重要的是為JAVA的運行提供了更多的靈活性,這篇文章主要介紹了Java反射與注解的詳細講解,需要的朋友可以參考下
    2026-06-06
  • Java如何使用ReentrantLock實現(xiàn)長輪詢

    Java如何使用ReentrantLock實現(xiàn)長輪詢

    這篇文章主要介紹了如何使用ReentrantLock實現(xiàn)長輪詢,對ReentrantLock感興趣的同學(xué),可以參考下
    2021-04-04
  • 詳解SpringMVC組件之HandlerMapping(二)

    詳解SpringMVC組件之HandlerMapping(二)

    這篇文章主要介紹了詳解SpringMVC組件之HandlerMapping(二),HandlerMapping組件是Spring?MVC核心組件,用來根據(jù)請求的request查找對應(yīng)的Handler,在Spring?MVC中,有各式各樣的Web請求,每個請求都需要一個對應(yīng)的Handler來處理,需要的朋友可以參考下
    2023-08-08

最新評論

布拖县| 呼和浩特市| 永德县| 剑川县| 抚宁县| 永昌县| 河北区| 永新县| 浮梁县| 西华县| 阜城县| 鄂伦春自治旗| 岫岩| 延长县| 磐安县| 抚宁县| 临汾市| 雅安市| 泸溪县| 保山市| 丽水市| 唐河县| 武胜县| 邢台市| 密山市| 沁水县| 临武县| 通渭县| 柳林县| 苏尼特左旗| 无棣县| 烟台市| 柞水县| 枣阳市| 平湖市| 宁国市| 平塘县| 龙门县| 祁东县| 南城县| 孟连|