幂等性组件

根据上篇文章改进,并做成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://***:6379
  database: 1
  password: 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 {

    @Resource
    private 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;
    }
}

测试结果

连续点击时

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值