根据上篇文章改进,并做成springbootstarter,依赖于redisson,如果redission已配置,则该组件可开箱即用
接口防重复提交_King_Kwin的博客-CSDN博客_接口防重复提交
本篇已做了较大的改动,可查看代码
idempotent: 幂等性组件,springboot-starter形式,项目依赖redission组件
本组件可通过Idempotent注解使用,注解如下:
package com.kwin.idempotent.annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.concurrent.TimeUnit;/*** 幂等或防重复提交* @author kwin* @Date 2022/3/24 15:11**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {/*** 幂等的key,不设置则取所有参数toString* spel表达式,支持多项拼接* @return*/String[] keys() default {};/*** keys的分隔符* @return*/String split() default "-";/*** 锁过期时间* @return*/int timeout() default 5;/*** 锁过期时间单位* @return*/TimeUnit timeUnit() default TimeUnit.SECONDS;/*** 锁的位置,不设置则取URI*/String location() default "";/*** 提醒信息* @return*/String info() default "操作过于频繁,请稍后重试";/*** 执行完成后是否释放key* @return*/boolean delKey() default false;
}
作者的测试demo
首先创建一个springboot项目
项目配置application.yml
redisson:address: redis://***:6379database: 1password: 111
redisson参数配置类
package com.example.testidempotent.config;import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/*** @author kwin* @Date 2022/1/16 18:12**/
@Data
@Configuration
@ConfigurationProperties(prefix = "redisson")
@ConditionalOnProperty("redisson.password")
public class RedissonProperties {private int timeout = 3000;private String address;private String password;private int database = 0;private int connectionPoolSize = 64;private int connectionMinimumIdleSize=10;private int slaveConnectionPoolSize = 250;private int masterConnectionPoolSize = 250;private String[] sentinelAddresses;private String masterName;
}
redisson配置类
package com.example.testidempotent.config;import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.config.SingleServerConfig;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.StringUtils;import javax.annotation.Resource;/*** @author kwin* @Date 2022/1/16 18:14**/
@Configuration
@ConditionalOnClass(Config.class)
//@EnableConfigurationProperties(RedissonProperties.class)
public class RedissonAutoConfiguration {@Resourceprivate RedissonProperties redssionProperties;/*** 哨兵模式自动装配* @return*/
/* @Bean@ConditionalOnProperty(name="redisson.master-name")RedissonClient redissonSentinel() {Config config = new Config();SentinelServersConfig serverConfig = config.useSentinelServers().addSentinelAddress(redssionProperties.getSentinelAddresses()).setMasterName(redssionProperties.getMasterName()).setTimeout(redssionProperties.getTimeout()).setMasterConnectionPoolSize(redssionProperties.getMasterConnectionPoolSize()).setSlaveConnectionPoolSize(redssionProperties.getSlaveConnectionPoolSize());if(StringUtils.hasText(redssionProperties.getPassword())) {serverConfig.setPassword(redssionProperties.getPassword());}return Redisson.create(config);}*//*** 单机模式自动装配* @return*/@Bean@ConditionalOnProperty(name="redisson.address")RedissonClient redissonSingle() {Config config = new Config();SingleServerConfig serverConfig = config.useSingleServer().setAddress(redssionProperties.getAddress()).setTimeout(redssionProperties.getTimeout()).setConnectionPoolSize(redssionProperties.getConnectionPoolSize()).setConnectionMinimumIdleSize(redssionProperties.getConnectionMinimumIdleSize());if(StringUtils.hasText(redssionProperties.getPassword())) {serverConfig.setPassword(redssionProperties.getPassword());}return Redisson.create(config);}
}
通用异常处理(用于展示重复提交的消息提示)
package com.example.testidempotent.config;import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** @author kwin* @Date 2022/4/7 16:00**/
@RestControllerAdvice
public class CommonExceptionHandler {@ExceptionHandler(value = Exception.class)public String exceptionHandler(Exception e) {return e.getMessage();}
}
引入已经打包好的Idempotent组件
<dependency><groupId>com.kwin</groupId><artifactId>idempotent</artifactId><version>0.0.1-SNAPSHOT</version></dependency>
controller接口(可看到:使用Idempotent注解即可)
package com.example.testidempotent.controller;import com.kwin.idempotent.annotation.Idempotent;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;/*** @author kwin* @Date 2022/4/7 15:16**/
@RestController
public class TestController {@Idempotent(keys = "#a")@GetMapping("/test")public String test(@RequestParam("a") String a) {return a;}
}
测试结果
连续点击时