如何使用自定义注解+Redis的拦截器实现幂等性校验
发表于:2025-11-09 作者:千家信息网编辑
千家信息网最后更新 2025年11月09日,这篇文章主要介绍"如何使用自定义注解+Redis的拦截器实现幂等性校验",在日常操作中,相信很多人在如何使用自定义注解+Redis的拦截器实现幂等性校验问题上存在疑惑,小编查阅了各式资料,整理出简单好
千家信息网最后更新 2025年11月09日如何使用自定义注解+Redis的拦截器实现幂等性校验
这篇文章主要介绍"如何使用自定义注解+Redis的拦截器实现幂等性校验",在日常操作中,相信很多人在如何使用自定义注解+Redis的拦截器实现幂等性校验问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"如何使用自定义注解+Redis的拦截器实现幂等性校验"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
实现方法
编写一个自定义注解和一个拦截器,本文中的自定义注解可以指定传入超时时间(默认是60秒),拦截器对使用注解的方法进行拦截,获取到传入的参数和超时时间,将传入的一个或多个参数拼接成一个json字符串,使用md5进行加密后把它作为key存入Redis缓存中,如果根据key在超时时间范围内能找到相同的内容,则返回表单内容已提交提示,否则继续执行方法。
自定义一个@Idempotent注解
/** * 自定义防重复提交注解 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Idempotent { /**可以传入指定的重复提交限定时间,默认60秒*/ long value() default 60000;}自定义一个IdempotentAspect拦截器
/** * 拦截器 * @author 豆芽 * @Date 2020-11-11 15:05 */@Aspect@Componentpublic class IdempotentAspect { private Logger logger = LoggerFactory.getLogger(IdempotentAspect.class); @Autowired private RedisService redisService; @Around("@annotation(idempotent)") public Object aroundMethod(ProceedingJoinPoint pjp,Idempotent idempotent)throws Throwable{ /**获取执行方法的参数*/ Object[] args = pjp.getArgs(); /**获取注解传入的超时时间*/ long timeOut = idempotent.value(); /**使用MD5对传入的参数进行加密*/ String encode = getMd5Value(args); try{ /** 校验是否重复提交过,如果没有,则按指定超时时间存入Redis缓存 */ boolean checkFormToken = redisService.checkForm(encode,timeOut); if (checkFormToken) { /**这是一个自定义的异常类,可以自己编写*/ throw new CommonException(Code.RepeatSubmit,"表单内容已经提交"); } /**继续执行方法*/ return pjp.proceed(); } catch (CommonException e) { logger.error("运行时错误:" + e.getMessage(), e); if (Code.RepeatSubmit.getCode() != e.getCode()) { /**调用方法可能会存在其他的CommonException自定义异常,需要删除校验的key,支持重复提交*/ redisService.delete(encode); } throw e; } catch (Exception e){ logger.error("幂等性校验出错:" + e.getMessage(), e); throw e; } } /** * 使用MD5对传入的参数进行加密 * @param args * @return */ private String getMd5Value(Object[] args) { String md5 = "null"; if (args.length == 0) { return md5; } else { StringBuilder jsonString = new StringBuilder(JSON.toJSONString(args)); /**使用md5工具类对字符串进行加密*/ md5 = SecureUtil.md5Encode(jsonString.toString()); } return md5; }}封装的RedisService类
@Componentpublic class RedisService { private Logger logger = LoggerFactory.getLogger(RedisService.class); @Autowired private StringRedisTemplate stringRedisTemplate; /** * 将对象存入缓存中 * @param key key * @param obj 对象数据 * @param timeout 超时时间 */ public void set(String key, Object obj, long timeout) { if (obj instanceof String) { stringRedisTemplate.opsForValue().set(key, (String) obj, timeout, TimeUnit.MILLISECONDS); return; } String json = JSON.toJSONString(obj); stringRedisTemplate.opsForValue().set(key, json, timeout, TimeUnit.MILLISECONDS); } /** * 根据Key查询缓存中的数据 * @param key * @return */ public String get(final String key) { if (StringUtils.isEmpty(key)) { logger.warn("获取Redis缓存,传入的Key为空"); return null; } return stringRedisTemplate.opsForValue().get(key); } /** * 根据key删除缓存数据 * @param key */ public void delete(String key) { stringRedisTemplate.delete(key); } /** * 查询缓存是否存在 * @param checkCase * @return */ public boolean checkForm(String checkCase,long timeOut){ String cacheValue = get(checkCase); /**如果查询缓存不为空,返回true*/ if (StringUtils.isNotEmpty(cacheValue)){ return true; } /**否则将对象存入缓存中,IdUtil.randomUUID()为hutool的UUID生成工具类,可到hutool官网加载相关依赖*/ set(checkCase, IdUtil.randomUUID(), timeOut); return false; }}自定义的错误码枚举Code
public enum Code { ErrorSystem(500,"系统繁忙!"), RepeatSubmit(4,"重复提交") ; private int code; private String msg; Code(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; }}自定义异常类CommonException
public class CommonException extends RuntimeException { /** 错误码 */ private int code = Code.ErrorSystem.getCode(); /** 错误信息 */ private String msg = Code.ErrorSystem.getMsg(); public CommonException(Code code) { super("[" + code.getCode() + ":" + code.toString() +"]" + code.getMsg()); this.code = code.getCode(); this.msg = code.getMsg(); } public CommonException(String msg) { super("[" + Code.ErrorSystem.getCode() + ":" + Code.ErrorSystem.toString() +"]" + msg); this.code = Code.ErrorSystem.getCode(); this.msg = msg; } public CommonException(Code code, String msg) { super("[" + code.getCode() + ":" + code.toString() +"]" + msg); this.code = code.getCode(); this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; }}测试类RedisController,@Idempotent注解可以直接value参数,这个参数可以设置本次请求的参数在redis中的存活时间,不传参默认存活60秒
/** * @author 豆芽 * @Date 2020-11-11 11:09 */@RestControllerpublic class RedisController { private Logger logger = LoggerFactory.getLogger(RedisController.class); /** * 自定义注解+Redis+MD5加密的拦截器实现幂等性校验 * @param name * @param age * @return */ @Idempotent @RequestMapping(value = "/auth/redis/idempotent",method = {RequestMethod.GET, RequestMethod.POST}) public String idempotentTest(String name,String age){ logger.info("name: "+name); logger.info("age: "+age); // TODO 执行保存或更新方法 return "执行成功"; }}第一次发起请求返回执行成功
紧接着马上再发起一次相同参数的请求,系统会抛出"表单内容已经提交"的异常

到此,关于"如何使用自定义注解+Redis的拦截器实现幂等性校验"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!
注解
拦截器
参数
缓存
方法
时间
加密
内容
错误
学习
对象
数据
表单
查询
相同
成功
字符
字符串
工具
更多
数据库的安全要保护哪些东西
数据库安全各自的含义是什么
生产安全数据库录入
数据库的安全性及管理
数据库安全策略包含哪些
海淀数据库安全审计系统
建立农村房屋安全信息数据库
易用的数据库客户端支持安全管理
连接数据库失败ssl安全错误
数据库的锁怎样保障安全
网络安全类的产品
未来之翼服务器tike值
软件开发各项文档
在软件开发中什么是需求
网络安全攻防实战pdf
北京广厦网络技术股份公司
web开发可以转软件开发吗
腾讯云服务器的密码
计算机网络技术和计算机应用技术有什么区别
想要做软件开发需要哪些技能
加强和改进网络安全工作
清代知县数据库
山西质量软件开发参考价
暗黑2 重置选择服务器
怀旧服想练个部落去哪个服务器
dell710服务器灯亮黄灯
我的世界bug卡在定位服务器
steam中国服务器
浪潮服务器 管理地址
瓦斯监控数据库异常
网络安全策略系统
头歌数据库原理实训作业答案
马来西亚软件开发月薪
做软件开发一般去哪找公司
国家网络安全宣传具体措施
数据库定义表结构
java开发用什么数据库
想要做软件开发需要哪些技能
网络安全主要面临的威胁
我的世界服务器怎么当副管理员