使用SpringAOP+Redis实现接口处理幂等

文章目录

  • 一、思路分析
  • 二、代码实战
    • 1、搭建Springboot+AOP+Redis环境
    • 2、自定义注解
    • 3、切面类
    • 4、测试一下吧

一、思路分析

在调用后台接口时,由于用户多次点击或者说第三方重试,可能会导致幂等问题。

解决方案无非就是上一次请求没有处理完,第二次请求不会处理,或者直接提示请求频繁,让用户等待。

我们基于SpringAOP(或者拦截器)来实现接口的幂等处理,多次请求时,提示用户不要重复请求,并缓存处理结果,将处理后的结果快速返回。

流程图如下:

在这里插入图片描述

二、代码实战

1、搭建Springboot+AOP+Redis环境

2、自定义注解

该注解标注在Controller层,可以根据项目需要进行参数调整,比如说可以实现按指定字段判断幂等、实现接口的限流、指定幂等的判断条件等等。

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)
public @interface Idempotent {

}

3、切面类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 幂等切面
 */
@Aspect
@Component
public class IdempotentAspect {

    private final StringRedisTemplate redisTemplate;

    private final String Status = "status";
    private final String Begin = "begin";
    private final String End = "end";
    private final String Data = "data";

    @Autowired
    public IdempotentAspect(StringRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    @Around("@annotation(idempotent)")
    public Object around(ProceedingJoinPoint point, Idempotent idempotent) throws Throwable {
        String identifier = generateIdentifier(point);

        // 直接设置状态为begin,设置成功,说明该请求已处理
        Boolean beginStatus = redisTemplate.opsForHash().putIfAbsent(identifier, Status, Begin);
        if(!beginStatus) {
            // 先取数据,再取状态,防止这期间数据过期
            Object dataObject = redisTemplate.opsForHash().get(identifier, Data);
            Object status = redisTemplate.opsForHash().get(identifier, Status);
            if (Begin.equals(status)) {
                // 请求在处理,抛异常退出
                throw new RuntimeException("请求处理中,不要重复请求");
            }

            if (End.equals(status)) {
                // 如果处理结束,直接将结果返回
                return JsonAide.fromJson(dataObject.toString(), getMethod(point).getReturnType());
            }
        }
        // 5分钟过期
        redisTemplate.expire(identifier, 5, TimeUnit.MINUTES);

        // 设置成功,执行流程
        Object proceed = point.proceed();
        // 将请求状态设为结束,并且缓存返回值
        // TODO 请求结束之后,可以将key删掉,在业务中进行判断是否重复请求
        redisTemplate.opsForHash().put(identifier, Status, End);
        redisTemplate.opsForHash().put(identifier, Data, JsonAide.toJson(proceed));

        return proceed;
    }

    /**
     * 获取方法
     */
    private Method getMethod(ProceedingJoinPoint point) {
        Signature signature = point.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        return methodSignature .getMethod();
    }

    /**
     * 获取方法签名
     */
    private String generateIdentifier(ProceedingJoinPoint point) {
        // 获取方法参数和相关信息
        Method method = getMethod(point);
        Object[] args = point.getArgs();
        // 根据方法名和参数生成唯一标识 TODO 可以替换为使用统一流水号
        return method.getName() + ":" + Stream.of(args).filter(Objects::nonNull).map(Object::toString).collect(Collectors.joining());
    }
}

4、测试一下吧

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;

@RestController
@RequestMapping("/test")
public class TestController {

    @PostMapping("/test")
    @Idempotent
    public Object test(@RequestBody Map<String, String> req) throws InterruptedException {
        System.out.println("请求进来了");
        // 休眠10秒 ,模拟业务处理时间
        Thread.sleep(10000);
        System.out.println("请求处理结束了");
        return req;
    }
}

我们发现,同一个请求未处理完成,会抛异常,此时我们捕获这个异常即可。(或者使用拦截器实现)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/138791.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

瑞吉外卖01-实现管理端登录登出功能

开发前准备 准备数据表 结合页面原型创建数据库reggie,可以使用图形化界面或者MySQL命令运行SQL文件导入表结构(使用命令时sql文件不要放在中文目录中) 创建工程 创建一个SpringBoot的工程(勾选Spring Web&#xff0c;MySQL和MyBatis),配置pom.xml文件导入druid&#xff0c;…

打破时空界限的虚拟线上会议大厅:多人在线互动的未来

引言&#xff1a; 在数字时代&#xff0c;迅猛发展的科技不仅改变了我们的日常生活&#xff0c;也深刻地影响着商务和社交领域。虚拟会议大厅&#xff0c;作为一种创新的交流平台&#xff0c;正以其多人同时在线、音视频通话和直播推流的强大功能&#xff0c;展现着新时代的会…

2023最新整理软件测试常见面试题附答案

包含的模块&#xff1a; 本文分为十九个模块&#xff0c;分别是&#xff1a;软件测试 基础、liunx、MySQL、web测试、接口测试、APP测试 、管理工具、Python、性能测试、selenium、lordrunner、计算机网络、组成原理、数据结构与算法、逻辑题、人力资源需要的点击文末获取&…

海思平台awb标定

文章目录 1、raw图采集2、awb标定3、标定效果优化1、raw图采集 raw图采集标准: 如果raw是12bit,即raw12,那么Block9 块的亮度就是40960.8 = 3276.8左右。 勾上Dump Raw,我这里raw10,即Depth为10bit,那么Block19的亮度应该为10240.8 = 819.2左右,调整曝光Exposure Attr…

深入探讨跨境电商商城源码的多语言、多货币、多商户入驻支持“

随着全球电子商务的飞速发展&#xff0c;跨境电商已成为一股不可忽视的力量。在这个背景下&#xff0c;为跨境电商商城源码提供多语言、多货币、多商户入驻支持显得尤为重要。本文将深入探讨这三大特性的实现方式及其对跨境电商发展的影响。 一、多语言支持 对于跨境电商来说&a…

多数据源切换

多数据源切换 1.jdbcTemplate2.使用切面3.mybatis层次的多数据源4.spring的dynamic自动注入 项目中经常会有多个数据源&#xff0c;那么如何处理呢 有4种方法 准备&#xff1a; 创建两个数据库 CREATE SCHEMA test DEFAULT CHARACTER SET utf8mb4 ; CREATE SCHEMA school DEFA…

【Debug】此语法需要一个导入的帮助程序,但找不到模块“tslib”

报错如下&#xff1a; 代码可以编译运行&#xff0c;但是会有红线和报错。 解决方法&#xff1a;TypeScript error “TS2354: This syntax requires an imported helper but module ‘tslib’ cannot be found” Issue #37991 microsoft/TypeScript GitHub 在tsconfig.jso…

MacOS下VMware Fusion配置静态IP

前言 在虚拟机安装系统后&#xff0c;默认是通过DHCP动态分配的IP&#xff0c;这会导致每次重启虚拟机ip都可能会改变&#xff0c;使用起来会有很多不便。 配置静态IP 查看主机网关地址 cat /Library/Preferences/VMware\ Fusion/vmnet8/nat.conf 查看主机DNS&#xff0c;m…

3种方法,教你用Pytest更改自动化测试用例执行顺序!

前言 在自动化测试中&#xff0c;自动化测试用例设计原则就是&#xff1a;执行过程时不能存在依赖顺序。那么如果测试用例需要按照指定顺序执行&#xff0c;这个时候应该怎么做呢&#xff1f; 目前单元测试框架中UnitTest没有办法改变测试用例的执行顺序&#xff0c;但是另一…

数据结构-数型查找

二叉排序树&#xff08;BST&#xff09; 二叉排序树&#xff0c;又称二叉查找树&#xff08;BST&#xff0c;Binary Search Tree&#xff09; 一颗二叉树或者是空二叉树&#xff0c;或者是具有如下性质的二叉树&#xff1a; 左子树上所有结点的关键字均小于根结点的关键字&…

微信支付配置完整操作手册

微信支付配置 必须申请开通微信支付 微信支付官方地址&#xff1a;https://pay.weixin.qq.com/index.php/core/home/login?return_url%2F 申请指引&#xff1a;https://pay.weixin.qq.com/index.php/public/bare_applyment/login4bank 百度经验&#xff1a;https://jingyan.b…

什么是智能井盖?万宾科技的智能井盖传感器的效果

近年来为打造智慧城市政府一直在不懈努力。加速城市基础建设是一项重要的举措&#xff0c;它有助于推动城市综合治理城市生命线的建设工程。在改善市民生活质量的过程中&#xff0c;市政部门正积极进行井盖的改进和升级工作&#xff0c;特别是那些看似微不足道的井盖却蕴含着重…

实时数仓-Flink使用总结

阿里云实时计算Flink版是阿里云基于Apache Flink构建的企业级、高性能实时大数据处理系统。具备一站式开发运维管理平台&#xff0c;支持作业开发、数据调试、运行与监控、自动调优、智能诊断等全生命周期能力。本期将对Flink的使用进行总结。 1. Flink产品回顾 阿里云实时计算…

第八章 :如何基于Spring Boot +Mybatis 快速开发 Restful API

第八章 :如何基于Spring Boot +Mybatis 快速开发 Restful API 前言 本章知识重点:主要讲解开发人员如何利用【MybatisPlus+EasyCode插件 】快速开发Restful API ,利用节约的时间学习,养成一种正向循环的技术之道,最后达到终身学习成长! 案例基于SpringBoot 2.3.2.RELEASE…

北斗卫星为油气管道安全保障提供可靠技术支持

北斗卫星为油气管道安全保障提供可靠技术支持 随着现代社会对能源需求的不断增长&#xff0c;油气管道成为了能源输送的重要通道。然而&#xff0c;油气管道的安全风险也日益凸显。为了及时掌握油气管道的运行状态并有效地监测其安全状况&#xff0c;北斗卫星技术为油气管道监测…

企业真正的性能测试,压测-内存泄露案例分析,一篇概全...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、环境配置 1&a…

OCR转换技巧:如何避免图片转Word时出现多余的换行?

在将图片中的文字识别转换为Word文档时&#xff0c;我们很多时候时会遇到识别内容的一个自然段还没结束就换行的问题&#xff0c;这些就是我们常说的多余换行的问题。为什么会产生这个问题呢&#xff1f;主要是由于OCR返回的识别结果是按图片上的文字换行而换行&#xff0c;而不…

VM虚拟机只有一个C盘怎么添加硬盘新分区盘符

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 前言 VM虚拟机中安装Window 系统后&#x…

Docker学习——⑦

文章目录 1、Docker 为什么需要网络管理2、Docker 网络架构简介2.1 CNM2.2 Libnetwork2.3 驱动 3、常见网络类型4、docker 网络管理命令5、网络详解5.2 docker Bridge 网络5.2 docker Host 网络5.3 docker Container 网络5.4 docker none 网络 1、Docker 为什么需要网络管理 容…

北京永达理慈善基金会与望京街道携手,为乡村振兴贡献10万元

东西部协作是推进巩固脱贫攻坚成果同乡村振兴有效衔接的重要手段。北京市朝阳区人民政府望京街道办事处自2021年起与内蒙古自治区通辽市科左后旗散都苏木、查日苏镇开展为期五年的结对帮扶工作&#xff0c;并号召全社会各界企事业单位及爱心人士帮扶助力&#xff0c;奉献爱心。…