通过Redis实现防止接口重复提交功能

本功能是在切面执行链基础上实现的功能,如果不知道切面执行链的同学,请看一下我之前专门介绍切面执行链的文章。

在SpringBoot项目中实现切面执行链功能-CSDN博客

1.定义防重复提交handler

/**
 * 重复提交handler
 *
 */
@AspectHandlerOrder
public class ResubmitAspectHandler implements AspectHandler {

    private StringRedisTemplate stringRedisTemplate;

    public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Override
    public boolean execute(ProceedingJoinPoint pjp) throws Exception {
        Method method = getMethod(pjp);
        if (!method.isAnnotationPresent(Resubmit.class)) {
        	return true;
        }
    	Resubmit annotation = method.getAnnotation(Resubmit.class);
    	long ttl = annotation.ttl();
    	String key = getKey();
    	String value = "1";
    	if (lock(key, value, ttl)) {
    		return true;
    	} 
		throw new BaseRuntimeException(ExceptionEnums.ERROR_10012.getCode(), "操作频率过高,请稍后再试!");
    }

    @Override
    public void afterCompletion(ProceedingJoinPoint pjp, Object response, Exception exception) {
        Method method = getMethod(pjp);
        if (method.isAnnotationPresent(Resubmit.class)) {
            unlock(getKey());
        }
    }

    /**
     * redis原子操作:如果key不存在就设置key:value
     *
     * @param key
     * @param value
     * @return true:设置成功拿到锁,false:设置失败未拿到锁
     */
    private boolean lock(final String key, final String value, final long ttl) {
        Boolean result = stringRedisTemplate.boundValueOps(key).setIfAbsent(value, Duration.ofSeconds(ttl));
        return result != null ? result : false;
    }

    /**
     * 解锁:删除key
     *
     * @param key
     */
    private void unlock(String key) {
        if (StringUtils.isNotBlank(key)) {
            stringRedisTemplate.delete(key);
        }
    }

    /**
     * 获取方法
     *
     * @param pjp
     * @return
     */
    private Method getMethod(ProceedingJoinPoint pjp) {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        return method;
    }

    /**
     * 获取key
     *
     * @return
     */
    private String getKey() {
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();
        String url = request.getRequestURI();
        String httpMethod = request.getMethod();

        HttpHeader httpHeader = WebContext.getHttpHeader();
        String deviceId = httpHeader.getDevice_id();

        String key = RedisConstants.REDIS_RESUBMIT_KEY + httpMethod + url + ":" + deviceId;
        return key;
    }
}

2.定义防重复提交注解

/**
 * 防止重复提交
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Resubmit {

    /**
     * 存活时间(秒),当意外情况(例如锁定之后重启服务)
     * 未能执行解锁功能,redis将在${ttl}秒之后自动删除锁标志
     * 默认 10秒
     * @return
     */
    long ttl() default 10;

}

3.在配置类中注入防重复提交切面类

@Bean
public List<AspectHandler> apiAspectHandlers() {
   ResubmitAspectHandler resubmitAspectHandler = new ResubmitAspectHandler();
   resubmitAspectHandler.setStringRedisTemplate(stringRedisTemplate);

   return Arrays.asList(resubmitAspectHandler);
}

4.controller中应用防重复提交注解

@PostMapping("/release")
@Resubmit
public ApiResponse<?> insert(@RequestBody @Valid InsertAppRequestDTO req) {
    // 处理业务逻辑
}

相关推荐

  1. 通过Redis实现防止接口重复提交功能

    2024-06-07 00:46:03       10 阅读
  2. 功能问题:如何防止接口重复请求?

    2024-06-07 00:46:03       8 阅读
  3. 002 springboot redis 防止表单重复提交

    2024-06-07 00:46:03       11 阅读
  4. 分布式防止重复请求或者高并发防止重复提交

    2024-06-07 00:46:03       8 阅读
  5. 后端怎样防止重复提交订单?

    2024-06-07 00:46:03       36 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-06-07 00:46:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-07 00:46:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-07 00:46:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-07 00:46:03       20 阅读

热门阅读

  1. 适配器模式 Adapter Pattern

    2024-06-07 00:46:03       10 阅读
  2. JVM内存分析之JVM优化

    2024-06-07 00:46:03       10 阅读
  3. excel 转换MAC地址格式方法

    2024-06-07 00:46:03       9 阅读
  4. 求二叉树第k层结点的个数--c++【做题记录】

    2024-06-07 00:46:03       10 阅读
  5. npm:Node.js包管理器的使用指南

    2024-06-07 00:46:03       7 阅读
  6. 【机器学习】之 kmean算法原理及实现

    2024-06-07 00:46:03       10 阅读
  7. DVWA-CSRF

    DVWA-CSRF

    2024-06-07 00:46:03      8 阅读