如何使用自定义注解+Redis的拦截器实现幂等性校验
发表于:2024-11-28 作者:千家信息网编辑
千家信息网最后更新 2024年11月28日,这篇文章主要介绍"如何使用自定义注解+Redis的拦截器实现幂等性校验",在日常操作中,相信很多人在如何使用自定义注解+Redis的拦截器实现幂等性校验问题上存在疑惑,小编查阅了各式资料,整理出简单好
千家信息网最后更新 2024年11月28日如何使用自定义注解+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安全错误
数据库的锁怎样保障安全
sql数据库中设置字符
软件开发四个月
怎么做无限流量服务器
网络技术公司客户
erp企业管理系统软件开发
新斗罗大陆魂师对决官网服务器
爱钱进为什么不能登录服务器
软件开发甲方提出终止合同
视频是如何存储的 数据库
华硕服务器内存安装
中中文数据库
git搭建代码管理服务器
武警部队可视勤务管理服务器
中国 根服务器
Timer如何结合km数据库
win8的服务器管理器
数据库 性能工具
数据库类技术要求
软件开发的硬件条件
杭州软件开发多少钱
web服务器顺序
怎么知道电脑是否安装数据库
2016网络安全和信息化委员会
服务器开安卓模拟器
连云港服务器机柜有几种
u8服务器坏了备份
服务器调试网口
dellt320服务器说明书
远程连接服务器没反应
华夏航空软件开发