如何使用自定义注解+Redis的拦截器实现幂等性校验
发表于:2025-01-20 作者:千家信息网编辑
千家信息网最后更新 2025年01月20日,这篇文章主要介绍"如何使用自定义注解+Redis的拦截器实现幂等性校验",在日常操作中,相信很多人在如何使用自定义注解+Redis的拦截器实现幂等性校验问题上存在疑惑,小编查阅了各式资料,整理出简单好
千家信息网最后更新 2025年01月20日如何使用自定义注解+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安全错误
数据库的锁怎样保障安全
金蝶k3创建数据库失败
农村办互联网科技讲堂
跳出去下载软件开发
湖南计算机网络技术专业学院
r720服务器耗电750w
网络安全病毒应急
网络安全技术与应运
网络安全短视频封面
禁止网易云音乐服务器ip
济南舜脉互联网科技有限公司
中华网络安全法首要目的
字体排版软件开发
mqtt 云服务器搭建
ciw网络安全与防火墙
网络安全工程师的理解
试验检测软件开发
服务器查看网站路径
orace完全恢复数据库
服务器 关闭安全组
软件开发企业人工成本
网络安全红蓝紫对抗比赛
导入手机数据库文件
大型会议服务器搭建
数据库update更新所有行
爹4服务器
宝山区个人软件开发进货价
数据库查询命令怎么学
orace完全恢复数据库
杭州广悦互联网科技有限公司
网络安全信息安全国家安全