使用SpringBoot自定义注解+拦截器+token机制,实现接口的幂等性

1 整合springboot和redis环境的集成

2 配置请求的方法体和枚举类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class Response {private int status;private String msg;private Object data;// 省略get、set、toString、无参有参构造方法
}///import lombok.Getter;@Getter
public enum ResponseCode {// 通用模块 1xxxxILLEGAL_ARGUMENT(10000, "参数不合法"),REPETITIVE_OPERATION(10001, "请勿重复操作"),;ResponseCode(Integer code, String msg) {this.code = code;this.msg = msg;}private Integer code;private String msg;
}

3 自定义异常以及配置全局异常类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;@Data
@AllArgsConstructor
@NoArgsConstructor
public class ServiceException extends RuntimeException {private String code;private String msg;// 省略get、set、toString以及构造方法
}import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;@ControllerAdvice
public class MyControllerAdvice {@ResponseBody@ExceptionHandler(ServiceException.class)public Response serviceExceptionHandler(ServiceException exception) {Response response = new Response(Integer.valueOf(exception.getCode()), exception.getMsg(), null);return response;}
}

4 编写创建Token和验证Token的接口以及实现类【核心类】

import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;@Service
public interface TokenService {public Response createToken();public Response checkToken(HttpServletRequest request);
}//import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.UUID;@Service
public class TokenServiceImpl implements TokenService {@Autowiredprivate RedisTemplate redisTemplate;@Overridepublic Response createToken() {// 生成uuid当作tokenString token = UUID.randomUUID().toString().replaceAll("-", "");// 将生成的token存入redis中redisTemplate.opsForValue().set(token, token);// 返回正确的结果信息Response response = new Response(0, token.toString(), null);return response;}@Overridepublic Response checkToken(HttpServletRequest request) {// 从请求头中获取tokenString token = request.getHeader("token");if (StringUtils.isBlank(token)) {// 如果请求头token为空就从参数中获取token = request.getParameter("token");// 如果都为空抛出参数异常的错误if (StringUtils.isBlank(token)) {throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getCode().toString(), ResponseCode.ILLEGAL_ARGUMENT.getMsg());}}// 如果redis中不包含该token,说明token已经被删除了,抛出请求重复异常if (!redisTemplate.hasKey(token)) {throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getCode().toString(), ResponseCode.REPETITIVE_OPERATION.getMsg());}// 删除tokenBoolean del = redisTemplate.delete(token);// 如果删除不成功(已经被其他请求删除),抛出请求重复异常if (!del) {throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getCode().toString(), ResponseCode.REPETITIVE_OPERATION.getMsg());}return new Response(0, "校验成功", null);}
}

5 配置需要幂等的自定义注解

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 ApiIdempotent {
}

6 接口拦截器

public class ApiIdempotentInterceptor implements HandlerInterceptor {@Autowiredprivate TokenService tokenService;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {if (!(handler instanceof HandlerMethod)) {return true;}HandlerMethod handlerMethod = (HandlerMethod) handler;Method method = handlerMethod.getMethod();ApiIdempotent methodAnnotation = method.getAnnotation(ApiIdempotent.class);if (methodAnnotation != null) {// 校验通过放行,校验不通过全局异常捕获后输出返回结果tokenService.checkToken(request);}return true;}@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

7 配置拦截器

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;@Configuration
public class WebConfig implements WebMvcConfigurer {@Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(apiIdempotentInterceptor());}@Beanpublic ApiIdempotentInterceptor apiIdempotentInterceptor() {return new ApiIdempotentInterceptor();}
}

8 写个controller测试

import com.example.demo_26.mindeng_3.domain.Food;
import com.example.demo_26.mindeng_3.mapper.FoodMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;@RestController
@RequestMapping("/token")
public class TokenController {@Autowiredprivate TokenService tokenService;@Autowiredprivate FoodMapper tBookOrderMapper;@GetMappingpublic Response token() {return tokenService.createToken();}@GetMapping("/checktoken")@ApiIdempotent()public String demo(@RequestBody Food tBookOrder) {// 处理请求int insert = tBookOrderMapper.insert(tBookOrder);return insert==1?"ok":"wrong";}
}

9 测试

首先,通过调用/token接口生成一个token。
curl -X GET http://localhost:8080/token然后,使用生成的token调用/token/checktoken接口进行验证。
curl -X POST http://localhost:8080/token/checktoken -H "token: generated-token"如果再次使用相同的token调用,将会得到重复操作的错误:这样,我们就通过token机制实现了接口的幂等性

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

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

相关文章

LeetCode hot100---链表专题(C++语言)

1、相交链表 (1)题目描述以及输入输出 (1)题目描述: 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交点,返回 null 。 (2)输入输出描述: 输入:…

【游戏模组】重返德军总部2009高清重置MOD,建模和材质全部重置,并且支持光追效果,游戏画质大提升

各位好,今天小编给大家带来一款新的高清重置MOD,本次高清重置的游戏叫《重返德军总部2009》2009年发布,我相信很多玩家已经玩过了,如果你还没有玩过我也可以和你简单介绍一下剧情,这款游戏故事背景接续在《重返德军总部…

【Python】Dejavu:Python 音频指纹识别库详解

Dejavu 是一个基于 Python 实现的开源音频指纹识别库,主要用于音频文件的识别和匹配。它通过生成音频文件的唯一“指纹”并将其存储在数据库中,来实现音频的快速匹配。Dejavu 的主要应用场景包括识别音乐、歌曲匹配、版权管理等。 ⭕️宇宙起点 &#x1…

golang web笔记-3.响应ResponseWriter

简介 从服务器向客户端返回响应需要使用 ResponseWriter,ResponseWriter是一个接口,handler用它来返回响应。 ResponseWriter常用方法 Write:接收一个byte切片作为参数,然后把它写入到响应的body中。如果Write被调用时&a…

828华为云征文|部署在线论坛网站 Flarum

828华为云征文|部署在线论坛网站 Flarum 一、Flexus云服务器X实例介绍二、Flexus云服务器X实例配置2.1 重置密码2.2 服务器连接2.3 安全组配置2.4 Docker 环境搭建 三、Flexus云服务器X实例部署 Flarum3.1 Flarum 介绍3.2 Flarum 部署3.3 Flarum 使用 四、总结 一、…

【GeekBand】C++设计模式笔记5_Observer_观察者模式

1. “组件协作”模式 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式。典型模式 Template MethodStrategyObserver / Event 2.…

【Linux】第一个小程序——进度条实现

🔥 个人主页:大耳朵土土垚 🔥 所属专栏:Linux系统编程 这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉 文章目…

【Linux进程间通信】Linux匿名管道详解:构建进程间通信的隐形桥梁

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:Linux “ 登神长阶 ” 🌹🌹期待您的关注 🌹🌹 ❀Linux进程间通信 📒1. 进程间通信介绍📚2. 什么是管道📜3…

08.useInterval

在 React 应用中,实现定时器功能通常需要使用 setInterval() 和 clearInterval(),这可能会导致代码复杂和难以维护。useInterval 钩子提供了一种声明式的方法来实现定时器功能,使得定时器的管理更加简单和直观。这个自定义钩子不仅简化了定时器的使用,还解决了一些常见的定…

Java - MyBatis(上)

Mybatis(上) 简介 Mybatis是一款优秀的持久层框架。 Mybatis支持定制化SQL、存储过程以及高级映射。 MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。 持久化 持久化就是将程序的数据在持久状态和瞬时状态转化的过程 内存因为断电即失…

传感器模块编程实践(三)舵机+超声波模块融合DIY智能垃圾桶模型

文章目录 一.概要二.实验模型原理1.硬件连接原理框图2.控制原理 三.实验模型控制流程四.智能感应垃圾桶模型程序五.实验效果视频六.小结 一.概要 随着科技的飞速发展和环保意识的日益增强,智能垃圾桶成为了城市生活的新宠,智能垃圾桶人们无需接触垃圾桶…

灵足时代:具身智能核心部件的新秀崛起——解析数千万元天使轮融资

在智能科技日新月异的今天,具身智能作为连接物理世界与数字世界的重要桥梁,正逐步成为科技创新的前沿阵地。近日,具身智能核心部件领域的新锐公司——“灵足时代”宣布完成数千万元天使轮融资,这一消息无疑为行业内外带来了强烈的震撼与期待。本轮融资由雅瑞智友科学家基金…

计算机组成原理(笔记6阵列乘法器、补码阵列乘法器)

手算阵列乘法器 平时我们计算乘法的时候是手算的 平时手算过程中我们是进行平行移位,可是在计算机里平行移位,会带来更大的开销,如下图我们可以看到,为此聪明的人,设计了斜移位的计算机 值得注意的是最后一行用的是平…

wsl中git difftool調用beyond compare

發現有兩種方案,鏈接如下: 1,https://blog.csdn.net/u014175785/article/details/121558365 2,https://www.jianshu.com/p/3a72e2e1260b 下面的鏈接供參考: https://sep.com/blog/20170607wsl-git-and-beyond-compare…

学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)

在线学籍管理平台系统 目录 基于SpringbootVUE的在线学籍管理平台系统设计与实现 一、前言 二、系统功能设计 三、系统实现 四、数据库设计 1、实体ER图 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取: 博主介绍:✌️大…

高度细化的SAGA模式实现:基于Spring Boot与RabbitMQ的跨服务事务

场景与技术栈 场景:电商系统中的订单创建流程,涉及订单服务(Order Service)、库存服务(Inventory Service)、支付服务(Payment Service)。 技术栈: Java 11 Spring Bo…

Thinkphp/Laravel旅游景区预约系统的设计与实现

目录 技术栈和环境说明具体实现截图设计思路关键技术课题的重点和难点:框架介绍数据访问方式PHP核心代码部分展示代码目录结构解析系统测试详细视频演示源码获取 技术栈和环境说明 采用PHP语言开发,开发环境为phpstudy 开发工具notepad并使用MYSQL数据库…

Qt的互斥量用法

目的 互斥量的概念 互斥量是一个可以处于两态之一的变量:解锁和加锁。这样,只需要一个二进制位表示它,不过实际上,常常使用一个整型量,0表示解锁,而其他所有的值则表示加锁。互斥量使用两个过程。当一个线程(或进程)…

国际 Android WPS Office v18.13 解锁版

WPS Office 移动版,设计不断优化,性能再次提升!融入Google Android最新设计标准,Material Design设计风格,完美支持沉浸式!简化文档操作,全新移动办公力作。全新界面更清晰舒适,功能…

MySQL 库的操作

温馨提示:非特殊情况不要删除和随意修改数据库 清除MySQL历史命令:system clear 增删数据库 增删数据库 登录MySQL:mysql -u root -pMySQL数据目录:/var/lib/mysql查看当前数据库列表:show databases;创建数据库&#…