自定义注解 + Redis 实现业务的幂等性

1.实现幂等性思路

实现幂等性有两种方式:

⭐ 1. 在数据库层面进行幂等性处理(数据库添加唯一约束).

例如:新增用户幂等性处理,username 字段可以添加唯一约束.

⭐ 2. 在应用程序层面进行幂等性处理.

而在应用程序方面进行幂等性处理,又有两种方式:

  • 通过 Spring AOP 方式实现幂等性判断(需要额外添加依赖).
  • 通过 Spring Boot 提供的拦截器实现幂等性判断.

例如:发表评论,同一个用户可以发表相同的评论,添加唯一约束不合适,放在程序层面处理.

2. 自定义注解 + Redis 实现业务幂等性

【实现思路】

  1. 创建自定义幂等性注解.

  2. 实现自定义幂等性注解的拦截器

    1. 创建拦截器,添加幂等性判断逻辑

    2. 定义幂等性判断的 ID(两种方式)

      1. 请求方携带唯一业务 ID

      2. 后端程序自行组织唯一业务 ID:当前用户 ID + 请求的数据(此处使用第二种)

  3. 配置拦截规则

  4. 使用自定义幂等性注解来保证业务的幂等性

2.1 自定义幂等性注解

/*** 自定义幂等性判断注解** @author helong*/
@Target(ElementType.METHOD) // 方法注解
@Retention(RetentionPolicy.RUNTIME)  // 程序运行期间有效
public @interface Idempotent {/*** 幂等性判断的时效** @return*/int time() default 60;
}

2.2 实现自定义幂等性注解的拦截器

@Component
public class IdempotentInterceptor implements HandlerInterceptor {@Resourceprivate ObjectMapper objectMapper;@Resourceprivate StringRedisTemplate stringRedisTemplate;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {// 只处理控制器方法,而不处理其他类型的请求(如静态资源)if (handler instanceof HandlerMethod) {Method method = ((HandlerMethod) handler).getMethod();// 尝试获取方法上的 Idempotent 注解Idempotent idempotent = method.getAnnotation(Idempotent.class);if (ObjectUtil.isNotNull(idempotent)) {// 生成唯一业务 IDString id = createId(request);ValueOperations<String, String> ops = stringRedisTemplate.opsForValue();// 如果 Redis 中已存在相同的业务 ID,阻止重复提交if (ObjectUtil.isNotNull(ops.get(id))) {response.setContentType("application/json;charset=UTF-8");response.setCharacterEncoding("UTF-8");String json = "{\"code\": 500, \"msg\": \"数据正在处理,请勿重复提交!\", \"data\": null}";response.getWriter().write(json);return false;} else {// 如果 Redis 中不存在相同的业务 ID,存储这个 ID 并设置过期时间ops.set(id, Boolean.TRUE.toString(), idempotent.time(), TimeUnit.SECONDS);return true;}}}// 如果不是 HandlerMethod 实例或没有 Idempotent 注解,继续处理请求return HandlerInterceptor.super.preHandle(request, response, handler);}/*** 生成幂等性 Id -> md5(用户ID + 请求参数)** @param request*/private String createId(HttpServletRequest request) throws JsonProcessingException {Long uid = NumberUtils.LONG_ZERO;// 获取当前用户的详细信息SecurityUserDetails userDetails = SecurityUtil.getCurrentUser();if (ObjectUtil.isNotNull(userDetails)) {uid = userDetails.getUid();}// 将请求参数转换为 JSON 字符串String requestParam = objectMapper.writeValueAsString(request.getParameterMap());return SecureUtil.md5(uid + requestParam);}
}

2.3 配置拦截规则

@Configuration
public class WebConfig implements WebMvcConfigurer {/*** 注入自定义拦截器*/@Resourceprivate IdempotentInterceptor idempotentInterceptor;@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(idempotentInterceptor)// 拦截所有的请求.addPathPatterns("/**")// 放行静态资源.excludePathPatterns("/index.html").excludePathPatterns("/login.html").excludePathPatterns("/image/**").excludePathPatterns("/js/**").excludePathPatterns("/layui/**");}
}

此处也可以不需要放行静态资源,因为上一步的自定义幂等性注解拦截器的逻辑里,第一个 if 就相当于放行了静态资源。

2.4 使用自定义幂等性注解

@PostMapping("/add")
@Idempotent
public ResponseEntity addComment(@Validated Comment comment) {comment.setUid(SecurityUtil.getCurrentUser().getUid());boolean result = commentService.save(comment);return result ? ResponseEntity.success(Boolean.TRUE) : ResponseEntity.fail("评论失败");
}

就拿发表评论来看,添加完自定义幂等性注解后,来到前端页面尝试在 1 分钟内,使用相同的用户,发表相同的评论:

PS:Security 用户对象,获取当前登录用户的代码,请参照这篇文章:SpringSecurity + JWT 实现登录认证-CSDN博客

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#医学影像管理系统源码(VS2013)

目录 一、概述 二、系统功能 系统维护 工作站 三、功能介绍 影像采集 统计模块 专业阅片 采集诊断报告 报告管理 一、概述 医学影像存储与传输系统&#xff08;PACS&#xff09;是一种集成了影像存储、传输、管理和诊断功能的系统。它基于数字化成像技术、计算机技术和…

大模型+编程,未来程序员躺平还是失业?

自然语言大模型编程可以更好地理解用户的需求&#xff0c;然后输出对应代码。 最近英伟达让AI自动写代码的开源神器已上线&#xff0c;Nvidia推出了Code Llama在线体验页面&#xff0c;Code Llama 是 Llama 2 的代码专用版本&#xff0c;无需注册&#xff0c;无需本地部署&…

Jangow

关于靶场环境配置&#xff0c;确实这个靶场存在很大的问题&#xff0c;不仅仅是网络的配置问题&#xff0c;更重要的是明知道如何修改网络环境配置&#xff0c;但是键盘存在很大的问题。许多字符输入不一致。 Vulnhub靶场&#xff0c;Jangow靶机环境找不到ip解决方法。_jangow…

基于springboot新生宿舍管理系统

系统背景 在当今高等教育日益普及的时代背景下&#xff0c;高校作为知识传播与创新的重要基地&#xff0c;其基础设施的智能化管理显得尤为重要。新生宿舍作为大学生活的起点&#xff0c;不仅是学生日常生活与学习的重要场所&#xff0c;也是培养学生独立生活能力和团队合作精神…

Ubuntu 24.04 LTS 桌面安装MT4或MT5 (MetaTrader)教程

运行脚本即可在 Ubuntu 24.04 LTS Noble Linux 上轻松安装 MetaTrader 5 或 4 应用程序&#xff0c;使用 WineHQ 进行外汇交易。 MetaTrader 4 (MT4) 或 MetaTrader 5 是用于交易外汇对和商品的流行平台。它支持各种外汇经纪商、内置价格分析工具以及通过专家顾问 (EA) 进行自…

项目实用linux 操作详解-轻松玩转linux

我之前写过完整的linux系统详解介绍&#xff1a; LInux操作详解一&#xff1a;vmware安装linux系统以及网络配置 LInux操作详解二&#xff1a;linux的目录结构 LInux操作详解三&#xff1a;linux实际操作及远程登录 LInux操作详解四&#xff1a;linux的vi和vim编辑器 LInux操作…

VPN以及GRE和MGRE

VPN VPN — 是虚拟专用网络 通俗地说&#xff0c;就是通过虚拟的手段&#xff0c;将两个独立的网络&#xff0c;穿越一个公共网络进行连接&#xff0c;实现点到点专线的效果&#xff08;可以理解为&#xff1a;一个分公司通过公网和总公司建立点到点的专线连接&#xff09; 现…

数据库理论基础

1.什么是数据库 1.1数据 描述事物的符号记录&#xff0c; 可以是数字、 文字、图形、图像、声音、语言等&#xff0c;数据有多种形式&#xff0c;它们都可以经过数字化后存入计算机。 1.2数据库 存储数据的仓库&#xff0c;是长期存放在计算机内、有组织、可共享的大量数据…

【05】LLaMA-Factory微调大模型——初尝微调模型

上文【04】LLaMA-Factory微调大模型——数据准备介绍了如何准备指令监督微调数据&#xff0c;为后续的微调模型提供高质量、格式规范的数据支撑。本文将正式进入模型微调阶段&#xff0c;构建法律垂直应用大模型。 一、硬件依赖 LLaMA-Factory框架对硬件和软件的依赖可见以下…

Redis高级篇—分布式缓存

目录 Redis持久化 RDB持久化 AOF持久化 RDB与AOF对比 Redis主从 全量同步 增量同步 Redis哨兵 RedisTemplate集成哨兵实现 Redis分片集群 散列插槽 集群伸缩 故障转移 自动故障转移 手动故障转移 RedisTemplate访问分片集群 Redis持久化 RDB持久化 RDB全称Re…

Alpine Linux 轻量级Linux 适合于 docker 容器镜像

Alpine Linux是创始于2010年4月及以前的、一款开源社区开发的、基于musl libc和BusyBox的轻量级Linux发行版&#xff1b;适合用来做路由器、防火墙、VPNs、VoIP 盒子以及服务器的操作系统。 Alpine 的意思是“高山的”。Alpine Linux 围绕 musl libc 和 busybox 构建。这使得它…

LockSupport详解

目录 LockSupport详解1、LockSupport简介LockSupport 类的构造方法LockSupport 类的属性Thread类的parkBlocker属性LockSupport 类的常用方法挂起线程的相关方法唤醒线程的相关方法unpark(Thread thread)方法注意点LockSupport使用示例判断park的条件建议使用while而不是if引出…

算法篇 滑动窗口 leetCode 水果成篮

水果成蓝 1.题目描述2.图形分析2.1原理解释2.2 怎么想出使用滑动窗口2.3 图形分析 3.代码演示 1.题目描述 2.图形分析 2.1原理解释 2.2 怎么想出使用滑动窗口 2.3 图形分析 3.代码演示

Android 10.0 Launcher3拖拽图标进入hotseat自适应布局功能实现一

1.前言 在10.0的系统rom定制化开发中&#xff0c;在对于launcher3的一些开发定制中&#xff0c;在对hotseat的一些开发中&#xff0c;需要实现动态hotseat居中 的功能&#xff0c;就是在拖拽图标进入和拖出hotseat&#xff0c;都可以保持hotseat居中的功能&#xff0c;接下来分…

【Linux】基础I/O——理解ext2文件系统

我们到现在为止讲的都是打开的文件。现在我们讲讲没有打开的文件 如果一个文件没有被打开&#xff0c;那它就是在磁盘中被存储的&#xff0c;我们就要关心路径问题&#xff0c;存储问题&#xff0c;文件获取问题&#xff0c;那么操作系统是怎么处理这些问题的&#xff1f;不急…

配置SMTP服务器的要点是什么?有哪些限制?

配置SMTP服务器安全性如何保障&#xff1f;如何高效配置服务器&#xff1f; SMTP作为电子邮件发送的核心协议&#xff0c;其配置对于确保邮件的成功传递和安全至关重要。AokSend将详细介绍配置SMTP服务器的关键要点&#xff0c;帮助读者建立一个高效、安全的邮件发送系统。 配…

使用 Flask 3 搭建问答平台(三):注册页面模板渲染

前言 前端文件下载 链接https://pan.baidu.com/s/1Ju5hhhhy5pcUMM7VS3S5YA?pwd6666%C2%A0 知识点 1. 在路由中渲染前端页面 2. 使用 JinJa 2 模板实现前端代码复用 一、auth.py from flask import render_templatebp.route(/register, methods[GET]) def register():re…

政安晨【零基础玩转各类开源AI项目】基于Ubuntu系统部署Hallo :针对肖像图像动画的分层音频驱动视觉合成

政安晨的个人主页&#xff1a;政安晨 欢迎 &#x1f44d;点赞✍评论⭐收藏 收录专栏: 零基础玩转各类开源AI项目 希望政安晨的博客能够对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff01; 本文目标&#xff1a;在Ubuntu系统上部署Hallo&#x…

Python面试宝典第15题:岛屿数量

题目 在二维网格地图上&#xff0c;1 表示陆地&#xff0c;0 表示水域。如果相邻的陆地可以水平或垂直连接&#xff0c;则它们属于同一块岛屿。请进行编码&#xff0c;统计地图上的岛屿数量。比如&#xff1a;下面的二维网格地图&#xff0c;其岛屿数量为3。 基础知识 解决这类…

国产化低功耗HDMI转VGA方案,大量出货产品,广泛应用在显示器以及广告机产品

芯片描述&#xff1a; 兼具高性能和低成本效益的优点&#xff0c;是一款可以将高清视频 HDMI1.4 数字信号转换成 VGA 模拟信号输出的芯片。不需要提供外部电源&#xff0c;ICNM7301 就可以在正常模式下使用&#xff1b;ICNM7301 广 泛适用于各种市场系统和显示应用体系&#x…