原 redisson防止表单重复提交
版权声明:本文为博主原创文章,请尊重他人的劳动成果,转载请附上原文出处链接和本声明。
本文链接:https://www.91mszl.com/zhangwuji/article/details/1336
一:引入pom
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.16.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
二:编写yml
server:
port: 8002
spring:
application:
name: mszl-blog
redis:
database: 0
port: 6379
host: 127.0.0.1
password:
jedis:
pool:
max-active: 200 # 连接池最大连接数(使用负值表示没有限制)
max-wait: -1 # 连接池最大阻塞等待时间(使用负值表示没有限制)
max-idle: 10 # 连接池中的最大空闲连接
min-idle: 0 # 连接池中的最小空闲连接
timeout: 3000 # 连接超时时间(毫秒)
三:配置RedissonConfig
package com.mszl.blog.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RedissonConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
/**
* 单Redis节点模式
*/
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://" + host + ":" + port); // redis://127.0.0.1:6379
RedissonClient redisson = Redisson.create(config);
return redisson;
}
/**
* 集群模式
* 备注:可以用"rediss://"来启用SSL连接
*/
/*@Bean
public RedissonClient redissonClusterClient() {
Config config = new Config();
config.useClusterServers().setScanInterval(2000) // 集群状态扫描间隔时间,单位是毫秒
.addNodeAddress("redis://127.0.0.1:7000")
.addNodeAddress("redis://127.0.0.1:7002");
RedissonClient redisson = Redisson.create(config);
return redisson;
}*/
}
四:自定义注解
package com.mszl.blog.repeatsubmit;
import java.lang.annotation.*;
/**
* 功能:自定义注解[重复提交]
*/
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatSubmit {
long lockTime() default 5;
}
五:切面类
package com.mszl.blog.repeatsubmit;
import com.mszl.blog.config.RedissonConfig;
import com.mszl.blog.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
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.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;
@Slf4j
@Aspect
@Component
public class RepeatSubmitAspect {
@Autowired
private RedissonConfig redissonClient;
@Pointcut("@annotation(repeatSubmit)")
public void pointcutNoRepeatSubmit(RepeatSubmit repeatSubmit){
}
@Around("pointcutNoRepeatSubmit(noRepeatSubmit)")
public Object around(ProceedingJoinPoint joinPoint, RepeatSubmit noRepeatSubmit) throws Throwable {
HttpServletRequest request=((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String token=request.getHeader("token");
String path=request.getServletPath();
long lockTime=noRepeatSubmit.lockTime();
String key="REPEAT_SUBMIT_" + path + token;
// 分布式锁
RLock lock = redissonClient.redissonClient().getLock(key);
boolean res = lock.tryLock(0, lockTime, TimeUnit.SECONDS); // 尝试加锁,最多等待0秒,上锁以后5秒自动解锁[lockTime默认为5s, 用户可以自定义]
if(!res){
throw new BusinessException(206, "请勿重复提交");
}
Object object=joinPoint.proceed();
return object;
}
}
六:在controller类上加上@RepeatSubmit
@RepeatSubmit(lockTime = 10)
@PostMapping("/blog/adduser")
public ReturnMsgUtils insertUser(@RequestBody Userbak uu){
ReturnMsgUtils result=userService.insertUser(uu);
return result;
}
注意:@RepeatSubmit可以不指定lockTime,默认为5s,也可以根据自己的实际情况改成对应的时间。
七:测试
请求接口:http://localhost:8002/blog/adduser,注意我这里没有把 /blog/adduser 接口对应的代码贴出来,这个接口只是单纯的往用户表;里面新增一条记录。注意:需要在请求头添加token,因为我们在切面类里面有获取token并作为redis中的key
第一次请求,截图如下。
接口返回信息如下:
token截图,我这里写死,大家根据自己的实际请求来赋值token即可。
在10秒内第二次请求接口,截图如下:
接口返回信息如下:
}
项目结构
参考资料:
https://blog.csdn.net/CoreyXuu/article/details/86646183
2021-09-06 10:51:57 阅读(1579)
名师出品,必属精品 https://www.91mszl.com