范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

springboot实现接口等幂性校验

  一 前言
  本篇内容的内容是实现接口等幂次校验,学习知识追寻者更多springboot系类教程看公众号专辑; 接口等幂性通俗的来说就是同一时间内,发起多次请求只有一次请求成功;其目的是防止多次提交,数据重复入库,表单验证网络延迟重复提交等问题二 实现方案
  主流的实现方案如下2.1 唯一索引
  给表加唯一索引,次方法最简单,当数据重复插入时,直接报SQL异常,对应用影响不大;
  alter table 表名 add unique(字段)
  示例,两个字段为唯一索引,如果出现完全一样的 order_name, create_time 就直接重复报异常;alter table `order`  add unique(order_name,create_time)2.2 锁
  分布式锁也可以实现接口等幂次校验,知识追寻者有写过一篇使用redis实现分布式锁思路的一篇文件,小伙伴们可以参考下《为什么你不会redis分布式锁?因为你没看到这篇文章》
  使用乐观锁(基于版本号实现),或者 悲观锁(表锁或者行锁)实现;2.3 先查询后判断
  入库时先查询是否有该数据,无插入,否则不插入;2.4 token 机制
  token 机制 也就是本篇文章的重点;大致实现思路就是 发起请求的时候先去 redis 获取 token , 将获取的token 放入 请求的hearder , 当请求到达服务端的时候拦截请求,对请求的 hearder 中的token,进行校验,如果校验通过则 放开拦截,删除token,否则 使用自定义异常返回错误信息;三 使用redis 实现 接口等幂性校验3.1 redis 工具类
  关于 RedisTemplate 的配置可以参考知识追寻者发布的文章 《springboot集成redis(基础篇)》/**  * @Author lsc  * 

*/ @Component public class RedisUtils { @Autowired private RedisTemplate redisTemplate; /** * 判断key是否存在 * @param key 键 * @return boolean */ public boolean hasKey(String key) { try { return redisTemplate.hasKey(key); } catch (Exception e) { e.printStackTrace(); return false; } } /** * 删除key * @param key 键 */ public Boolean del(String key) { if (key != null && key.length() > 0) { return redisTemplate.delete(key); }else { return false; } } /** * 普通缓存获取 * @param key 键 * @return 值 */ public Object get(String key) { return key == null ? null : redisTemplate.opsForValue().get(key); } /** * 普通缓存放入并设置时间 * @param key 键 * @param value 值 * @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期 * @return true成功 false 失败 */ public boolean set(String key, Object value, long time) { try { if (time > 0) { redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } }3.2 token 工具类   使用 uuid 生成 随机字符串,通过md5加密防止token被解密,保证token的唯一性与安全性;,设置过期时间为 30 秒,即在30秒内只能提交成功一次请求,根据不同的业务需求,读者们自行处理;/** * @Author lsc *

*/ @Component public class TokenUtis { @Autowired RedisUtils redisUtils; // token 过期时间为30秒 private final static Long TOKEN_EXPIRE = 30L; private final static String TOKEN_NAME = "token"; /* * * @Author lsc *

生成token 放入缓存 * @Param [] */ public String generateToken() { String uuid = UUID.randomUUID().toString(); String token = DigestUtils.md5DigestAsHex(uuid.getBytes()); redisUtils.set(TOKEN_NAME,token,TOKEN_EXPIRE); return token; } /* * * @Author lsc *

token 校验 * @Param [request] */ public boolean verifyToken(HttpServletRequest request) { String token = request.getHeader(TOKEN_NAME); // header中不存在token if(StringUtils.isEmpty(token)) { // 抛出自定义异常 System.out.println("token不存在"); throw new GlobleException(CodeMsg.BAD_REQUEST); } // 缓存中不出在 if(!redisUtils.hasKey(TOKEN_NAME)) { // 抛出自定义异常 System.out.println("token已经过期"); throw new GlobleException(CodeMsg.BAD_REQUEST); } String cachToekn = (String)redisUtils.get(TOKEN_NAME); if (!token.equals(cachToekn)){ // 抛出自定义异常 System.out.println("token校验失败"); throw new GlobleException(CodeMsg.BAD_REQUEST); } // 移除token Boolean del = redisUtils.del(TOKEN_NAME); if (!del){ // 抛出自定义异常 System.out.println("token删除失败"); throw new GlobleException(CodeMsg.BAD_REQUEST); } return true; } }3.3 注解   定义注解,使用在方法上,当控制层的方法上被注释时,表示该请求为等幂性请求;/** * @Author lsc *

*/ @Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Idempotent { }3.4 拦截器配置   选择 前置拦截器,每次请求都校验 到达的方法上是否有等幂性注解,如果有则进行token 校验;/** * @Author lsc *

*/ @Component public class IdempotentInterceptor implements HandlerInterceptor { @Autowired private TokenUtis tokenUtis; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { if (!(handler instanceof HandlerMethod)) { return true; } // 对有Idempotent注解的方法进行拦截校验 HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); Idempotent methodAnnotation = method.getAnnotation(Idempotent.class); if (methodAnnotation != null) { // token 校验 tokenUtis.verifyToken(request); } return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }   对拦截器进行url模式匹配,并注入spring容器/** * @Author lsc *

*/ @Configuration public class WebConfiguration implements WebMvcConfigurer { @Autowired IdempotentInterceptor idempotentInterceptor; @Override public void addInterceptors(InterceptorRegistry registry) { // 拦截所有请求 registry.addInterceptor(idempotentInterceptor).addPathPatterns("/**"); } }3.5 控制层   对控制层进行编写如下,发起请求时通过 getToken 方法获取token,将获取的token 放入 hearder 后 再请求 testIdempotent 方法/** * @Author lsc *

*/ @RestController public class ZszxzController { @Autowired TokenUtis tokenUtis; @GetMapping("zszxz/token") public ResultPage getToken(){ String token = tokenUtis.generateToken(); JSONObject jsonObject = new JSONObject(); jsonObject.put("token",token); return ResultPage.sucess(CodeMsg.SUCESS,jsonObject); } @Idempotent @GetMapping("zszxz/test") public ResultPage testIdempotent(){ return ResultPage.sucess(CodeMsg.SUCESS,"校验成功"); } }3.6 测试   请求获取token   已经被消耗的token,请求时报错   重新获取token 请求成功   对于高并发请求可以使用jmeter进行测试,本篇文章也可以使用aop拦截实现;   作者:知识追寻者   链接:https://juejin.im/post/5efc9e47f265da22c46938bc


机器人烧本帮菜,老年人吃得香?上海现全国首个社区AI食堂中国经济周刊记者王雨菲上海报道(虹桥社区AI食堂)上海新开了一家智能餐厅,在这里,所有菜品都由机器程序自动烹饪。自助面档区从和面到煮好面条,机械臂操作2分钟即可完成,结算支付柜台通中国移动SDWAN组网服务,进军医疗行业领域目前,医疗资源在全国范围内分布不均,例如省会城市以及一线城市,医疗资源充沛,病情案例,医生经验丰富,但下级医疗机构没有足够的医疗资源,医护人员自身资质也相对欠缺,这一问题亟待解决。准备去广西,广西南宁哪些地方比较好玩?南宁简称邕,所以有邕城的别称。作为广西壮族自治区的首府,因植被丰富,四季常青,它又有绿城的美丽称号。那么它有哪些地方好玩呢?图1(来自网络侵权删)要说好玩的地方,那真是说也说不完哦有没有某个罪名设立至今无人触犯过?这个问题我可以试着回答一下。97刑法修订后,出现了一些新的罪名刑法第376条第1款战时拒绝逃避征召军事训练罪第2款战时拒绝逃避服役罪第377条战时故意提供虚假敌情罪第378条战时造怎样评价华为售后服务?忽然收到这个问题有点懵,感觉自己被监控了似的我想静静,因为今天下午刚刚去过华为售后服务部,之前有一个mate9手机屏幕有问题一直放着没用,最近需要一个备用机就想着拿去修一下,到了以请问一下,电视有没有必要去选购那些大几千的中高端机,4000左右的电视机难道真不行吗?电视这个产品,我一直认为品牌差异很小,目前大致分为三类进口(索尼,三星),传统国产(海信,创维,TCL),互联网(小米)。这六家基本代表了中电视市场的最热门品牌。先说选品牌电视的使中美互联网科技对比随着21世纪的到来,全球经济以及科学技术得到了更好的发展,尤其是互联网的发展更是迅猛,全球出现了很多跨国的高科技公司,这其中美国的高科技占据了很大一部分,经济总量为全球第二的中国的朱耿洲搜狗众多老员工离职!曾经的互联网巨头缘何沦落成这般?7月13日,国家市场监管总局无条件批准腾讯收购搜狗。这倒是个旧闻,略为新一点的则是一般而言,公司合并后需要保持企业文化和晋升体系的高度统一。但腾讯于8月初步完成搜狗整合工作后,搜狗小米又一款5G新机通过3C认证!配备33W快充,定位不高从上个月开始,各大手机厂商就进入了下半年新机扎堆发布模式,预计本月还会有一大波的新机会到来。作为新晋的全球第二大手机厂商,小米上个月带来了小米MIX4高端旗舰机,本以为接下来会轮到小米11T强悍黑科技泄露,小米11低至百元机刷新发烧纪录9月5日消息,近日外媒91mobiles曝光了小米11T系列(包括小米11T和小米11TPro)将在国外上市的外观效果图。小米11T系列正面采用了居中打孔直屏设计。后置摄像头模组与雷鸟75吋80分区5K出头,跟价格屠夫小米有一拼这款雷鸟75S535C4K液晶电视,今天京东促销价来到了5769元,作为TCL旗下专攻性价比的子品牌,不吹不黑,跟价格屠夫小米有得一拼。为什么它性价比更高?先来看看这款雷鸟75S5
蔚来智己埃安小鹏,那些年车企画过的大饼,如今烙熟了吗?如果你闭着眼买了一台纯电动汽车,恰好安装私人充电桩又没遇到物业阻挠,那么你的用车之路恐怕只有惊喜惊喜再惊喜。如果你每天上网看智能电动车企画大饼,对千公里续航无人驾驶充满期待好嘛,恐推进新能源汽车发展,2022年将有哪些举措?新华社记者张辛欣工信部近日发布数据显示,2021年,我国新能源汽车发展迅猛,产销量均超过350万辆,同比增长1。6倍。2022年,工信部将全力推进新能源汽车发展再上台阶。产业配套如现在有比徕卡技术水平更高的相机公司吗?玩相机的老司机和器材党大都对卡尔蔡司和徕卡两家德国企业比较熟悉,数码时代前者虽不再生产Contax那种相机机身,后者依旧制造高端的中画幅和全画幅相机。但论光学技术同为德国企业的Ca从今往后驾驶不必导航了,北斗云航诞生,路况清楚浮现前面因为科技变得越来越发达了,为此汽车也随之不断便宜起来,自己开车外出的话能够带来诸多优势,使得很多人纷纷拥有了私家车,实现全天24小时都能外出,而且不受天气的影响,当然出远门也会变得关于拜新年你最想用什么方式?回答了关于拜年,不同时代,具有不同方式。过去老一辈人互相拜年,都是面对面。后来有电话了,还可以用电话。近期,网络时代,拜年也现代化了,可以用语音方式,视频方式,还可以用电话方式。老python编程基础学习之数据类型与基本运算符基本数据类型数值类型1。整数整数用来表示整数数值,没有小数部分的数值在python中整数包括正整数负整数和0,整数类型包括十进制整数八进制整数十六进制整数二进制整数2。浮点数浮点数市场消息IBM(IBM。US)将与泰国最大企业PTTEP合作,开发基于区块链的国家数字企业认证平台(NCID)市场消息IBM(IBM。US)将与泰国最大企业PTTEP合作,开发基于区块链的国家数字企业认证平台(NCID)。IBMCorp(IBM。US)公司简介国际商业机器公司是一家信息技术36氪首发泡芙传媒获坚果资本数百万美金天使轮融资,布局品牌全链路出海服务36氪获悉,品牌出海全链路服务商泡芙传媒获坚果资本领投易点天下及知名跨境产业方跟投的数百万美金天使轮融资。本轮资金将用于既有业务版块深度拓展团队人员扩充与市场推广加强海外资源优势和2022年最热门的15项技术人工智能引发新浪潮德国商报网站1月7日发表题为这些技术趋势将影响2022年的报道。为了识别2022年最重要的技术趋势,德国商报记者走访了高校实验室研究机构和企业,并与学界和业界的领军人物探讨,列出了你认为锐捷和华三哪家的产品好?看技术能力,就看能不能做运营商。说这句话你们都懂了吧只用过这两家的交换机,锐捷的交换机质量远不如华三锐捷强,锐捷无线做得更专,浸淫时间更长,积累更多。关键是实测过,跟h3c和hua银行业务流程软件自动化RPAAI商业银行数字化转型的根本动机,是以数据流动的自动化来化解复杂环境的不确定性。传统机器设备的自动化替代了体力劳动,数据流动的自动化则替代了脑力劳动。判断银行内部决策是否智能,就是看在