当前位置: 首页 > article >正文

虚拟电商-话费充值业务(六)话费充值业务回调补偿

一、话费充值回调业务补偿

业务需求:供应商对接下单成功后充吧系统将订单状态更改为:等待确认中,此时等待供应商系统进行回调,当供应商系统回调时说明供应商充值成功,供应商回调充吧系统将充吧的订单改为充值成功,如果在这个过程中出现了故障,比如供应商没有回调,或者回调过程中产生了异常,或者回调不通,回调失败,如果我们不对这种情况进行处理的话,那么我们的订单状态永远得不到修改.

解决方案:

1:供应商会提供一个查询订单充值状态的接口,当我们系统对接下单成功后添加一个查询状态的任务,该任务1分钟或者几分钟后去调用供应商查询状态的API,我们根据供应商返回的结果进行充吧订单状态的修改

2:如果供应商系统能够正常回调,则将查询状态的任务取消即可

1.1.状态检查接口开发

步骤1:我们在chongba_recharge_mock工程中模拟的供应商都提供了状态检查接口,同理我需要将供应商状态检查接口api地址配置到对接模块chongba_recharge_supplier中,修改application-dev.yml配置文件如下:

supplier:jisu_url: "http://127.0.0.1:8090/jisuapi/mobilerecharge"juhe_url: "http://127.0.0.1:8090/juheapi"apis: {jisuapi: "${supplier.jisu_url}/recharge",juheapi: "${supplier.juhe_url}/recharge"}maxrepeat: 4checkStateApis: {jisuapi: "${supplier.jisu_url}/orderState",juheapi: "${supplier.juhe_url}/orderState"}stateCheckTime: 1 #状态检查时间

并修改配置类:SupplierConfig

@Data
@Component
@ConfigurationProperties(prefix = "supplier")
public class SupplierConfig {private Map<String,String> apis; //加载供应商api地址private int maxrepeat;//最大重试次数private Map<String,String> checkStateApis;private int stateCheckTime; //订单充值状态检查时间
}

步骤2:在chongba_recharge_supplier模块的对接供应商接口:SupplierService中添加检查充值状态的接口方法

public interface SupplierService {/*** 对接供应商下单* @param rechargeRequest*/public void recharge(RechargeRequest rechargeRequest);/*** 对接下单成功后检查充值状态* @param checkStatusRequest */public void checkStatus(CheckStatusRequest checkStatusRequest);
}

在chongba_common工程中的:com.chongba.recharge包下创建实体:

CheckStatusRequest@Data
@NoArgsConstructor
@AllArgsConstructor
public class CheckStatusRequest {private String supplier;private String orderNo;private String tradeNo;
}

参数说明:

supplier:不同供应商查询订单充值状态API地址不一样,需要根据供应商编号去获取

orderNo:充吧系统生成的订单号,充吧支付成功后通知对接模块下单时已经将充吧订单号传递过来了

tradeNo:供应商系统生成的唯一的交易号,当我们调用供应商对接下单API后由供应商生成的唯一交易号,并返回给了充吧系统

orderNo和tradeNo参数是供应商状态检查接口需要传递的参数!企业开发中看第三方的供应商系统接口需要传递什么参数就传递什么参数。

步骤3:在SupplierServiceImpl类中实现检查状态的方法

@Override
public void checkStatus(CheckStatusRequest checkStatusRequest) {//获取状态检查接口地址String checkStatusApi = supplierConfig.getCheckStateApis().get(checkStatusRequest.getSupplier());//设置请求头HttpHeaders headers = new HttpHeaders();headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);//封装请求参数---实际业务中看供应商需要传递哪些参数,实际情况中可能要根据不同的供应商传递不同的//参数,那就要在这个逻辑中添加不同的条件分支MultiValueMap<String,String> map = new LinkedMultiValueMap<>();map.add("outorderNo",checkStatusRequest.getOrderNo());map.add("tradeNo",checkStatusRequest.getTradeNo());HttpEntity<MultiValueMap<String,String>> httpEntity = new HttpEntity<>(map,headers);ResponseEntity<String> responseEntity = restTemplate.postForEntity(checkStatusApi, httpEntity, String.class);Result<RechargeResponse> result = JSON.parseObject(responseEntity.getBody(), new TypeReference<Result<RechargeResponse>>() {});if(result.getCode() == StatusCode.OK){log.info("订单状态检查,订单成功{}",checkStatusRequest);updateTrade(checkStatusRequest.getOrderNo(),result.getData().getStatus());}else{//订单失败log.info("订单状态检查,订单失败{}",checkStatusRequest);updateTrade(checkStatusRequest.getOrderNo(),OrderStatusEnum.FAIL.getCode());}
}

1.2.添加和消费状态查询任务

有了对接供应商状态查询的接口,下面要做的就是在对接供应商下单成功之后添加一个查询状态的任务,该任务可在1分钟后执行,即1分钟后去查询供应商充值状态

步骤1:在chongba_recharge_supplier模块的任务接口:SupplierTask中新增两个方法,

添加查询状态任务方法:addCheckStatusTask(CheckStatusRequest checkStatusRequest);

消费查询状态任务方法:checkStatus();

/*** 添加状态检查查询任务* @param checkStatusRequest*/
public void addCheckStatusTask(CheckStatusRequest checkStatusRequest);/*** 状态检查任务*/
public void checkStatus();

参数说明:

添加任务是为了消费任务,消费状态检查任务就是要对接供应商状态检查接口,而该接口需要传递的参数就是CheckStatusRequest ,包含了属性supplier,orderNo,tradeNo,所以添加任务时需要将CheckStatusRequest 作为任务对象Task的parameter属性值。

步骤2:实现添加和消费任务方法

@Autowired
private SupplierConfig supplierConfig;@Override
public void addCheckStatusTask(CheckStatusRequest checkStatusRequest) {Task task = new Task();TaskTypeEnum taskTypeEnum = TaskTypeEnum.STATECHECK;task.setTaskType(taskTypeEnum.getTaskType());task.setPriority(taskTypeEnum.getPriority());Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE,supplierConfig.getStateCheckTime());task.setExecuteTime(calendar.getTimeInMillis());
​task.setParameters(ProtostuffUtil.serialize(checkStatusRequest));//添加状态检查任务ResponseMessage result = taskServiceClient.push(task);
}@Override
@Scheduled(fixedRate = 1000)
public void checkStatus() {//消费状态检查任务-----发起状态检查TaskTypeEnum statecheck = TaskTypeEnum.STATECHECK;ResponseMessage poll = taskServiceClient.poll(statecheck.getTaskType(), statecheck.getPriority());if(poll.isFlag()){if(poll.getData()!=null){String taskStr = JSON.toJSONString(poll.getData());Task task = JSON.parseObject(taskStr,new TypeReference<Task>(){});CheckStatusRequest statusRequest = ProtostuffUtil.deserialize(task.getParameters(), CheckStatusRequest.class);log.info("消费任务时从拉取的任务数据{}",statusRequest);//调用状态检查接口进行状态检查supplierService.checkStatus(statusRequest);}}
}

步骤3:对接供应商下单成功后添加状态检查任务,完善SupplierServiceImpl类中的recharge方法

@Override
public void recharge(RechargeRequest rechargeRequest) {if(result !=null){//判断成功还是失败if(result.getCode() == StatusCode.OK){log.info("下单成功,等待充值处理回调!");//特别注意此时订单状态还不能修改为充值成功-----供应商回调之后才能修改为成功updateTrade(rechargeRequest.getOrderNo(),OrderStatusEnum.UNAFFIRM.getCode());//充值处理中等待确认log.info("下单成功,添加状态检查任务,1分钟后进行状态检查");supplierTask.addCheckStatusTask(new CheckStatusRequest(rechargeRequest.getSupply(),result.getData().getOrderNo(),result.getData().getTradeNo()));return;}else {//.....................后面的代码省略}}
}

步骤3:测试:

现在要测试供应商回调不成功由充吧系统主动发起状态查询的情形,在chongba_recharge_mock工程中的MockJisuRechargeController中注释掉回调的方法

启动所有系统,进行话费充值业务。

1.3.回调成功后取消任务

步骤1:当供应商成功回调后我们需要取消状态查询任务,取消任务需要任务id,而在供应商的回调方法中,只有供应商返回的订单号和交易号,没有任务id,因此在充吧添加状态查询任务时需要将充吧订单号和任务id进行关联存储,

步骤1:在SupplierTaskImpl类中完善:addCheckStatusTask添加状态检查任务方法

@Autowiredprivate CacheService cacheService;@Overridepublic void addCheckStatusTask(CheckStatusRequest checkStatusRequest) {Task task = new Task();TaskTypeEnum taskTypeEnum = TaskTypeEnum.STATECHECK;task.setTaskType(taskTypeEnum.getTaskType());task.setPriority(taskTypeEnum.getPriority());Calendar calendar = Calendar.getInstance();calendar.add(Calendar.MINUTE,supplierConfig.getStateCheckTime());task.setExecuteTime(calendar.getTimeInMillis());task.setParameters(ProtostuffUtil.serialize(checkStatusRequest));//添加状态检查任务ResponseMessage result = taskServiceClient.push(task);//供应商系统能够正常回调则需要取消状态检查任务,取消任务需要任务id,回调成功后修改充吧订单状态知道订单号//因此要将订单号和任务id做一个映射存储if(result.getCode() == StatusCode.OK){cacheService.hPut(Constants.order_checked,checkStatusRequest.getOrderNo(),String.valueOf(result.getData()));}}

步骤2:在SupplierTask中添加一个取消状态检查任务的方法,方法参数是订单号

 /*** 取消状态检查任务* @param orderNo*/public void cancelCheckTask(String orderNo);

步骤3:在SupplierTaskImpl类中实现取消状态检查任务的方法

@Override
public void cancelCheckTask(String orderNo) {String taskId = (String) cacheService.hGet(Constants.order_checked, orderNo);if(taskId!=null){taskServiceClient.cancel(Long.valueOf(taskId));cacheService.hDelete(Constants.order_checked,orderNo);}
}

步骤4:在供应商回调成功的方法中调用取消状态检查的任务,在chongba_recharge_supplier模块的:com.chongba.supplier.controller包下的RechargeNotifyController中的notify(@RequestBody String result)方法,调用取消状态检查方法

@Autowiredprivate SupplierTask supplierTask;@RequestMapping(value = "/order/notify")public String notify(@RequestBody String result) {JSONObject jsonObject = (JSONObject) JSON.parse(result);String orderNo= (String) jsonObject.get("orderNo");int status= Integer.parseInt(jsonObject.get("status").toString());log.info("充值回调成功修改订单{}的状态为{}",orderNo,status);updateTrade(orderNo, status);log.info("回调成功后取消状态检查任务");supplierTask.cancelCheckTask(orderNo);return "sucess";}

步骤5:测试,

注意:在chongba_recharge_mock模块中将极速的回调通知方法放开,然后再测试,

启动所有工程,进行话费充值。

相关文章:

虚拟电商-话费充值业务(六)话费充值业务回调补偿

一、话费充值回调业务补偿 业务需求&#xff1a;供应商对接下单成功后充吧系统将订单状态更改为&#xff1a;等待确认中&#xff0c;此时等待供应商系统进行回调&#xff0c;当供应商系统回调时说明供应商充值成功&#xff0c;供应商回调充吧系统将充吧的订单改为充值成功&…...

Apache httpclient okhttp

学习链接 okhttp github okhttp官方使用文档 SpringBoot 整合okHttp okhttp3用法 Java中常用的HTTP客户端库&#xff1a;OkHttp和HttpClient&#xff08;包含请求示例代码&#xff09; 深入浅出 OkHttp 源码解析及应用实践 httpcomponents-client github apache httpclie…...

SQL Server 2022 读写分离问题整合

跟着热点整理一下遇到过的SQL Server的问题&#xff0c;这篇来聊聊读写分离遇到的和听说过的问题。 一、读写分离实现方法 1. 原生高可用方案 1.1 Always On 可用性组&#xff08;推荐方案&#xff09; 配置步骤&#xff1a; -- 1. 启用Always On功能 USE [master] GO ALT…...

Docker部署Blinko:打造你的个性化AI笔记助手与随时随地访问

文章目录 前言1. Docker Compose一键安装2. 简单使用演示3. 安装cpolar内网穿透4. 配置公网地址5. 配置固定公网地址 前言 嘿&#xff0c;小伙伴们&#xff0c;是不是觉得市面上那些单调乏味的笔记应用让人提不起劲&#xff1f;今天&#xff0c;我要给大家安利一个超炫酷的开源…...

Python Cookbook-5.2 不区分大小写对字符串列表排序

任务 你想对一个字符串列表排序&#xff0c;并忽略掉大小写信息。举个例子&#xff0c;你想要小写的a排在大写的 B 前面。默认的情况下&#xff0c;字符串比较是大小写敏感的(比如所有的大写字符排在小写字符之前)。 解决方案 采用 decorate-sort-undecorate(DSU)用法既快又…...

安全业务的manus时代即将到来

“(人)把业务流程任务化,把任务工具化,再把工具服务化,剩下的交给智能体。” 一、自动化与智能化浪潮下的安全业务变革 近期,笔者着迷于模型上下文协议(Model Context Protocol,简称MCP),这项技术所带来的变革性力量令人惊叹。在对多个技术案例进行实践的过程中,笔者…...

程序化广告行业(55/89):DMP与DSP对接及数据统计原理剖析

程序化广告行业&#xff08;55/89&#xff09;&#xff1a;DMP与DSP对接及数据统计原理剖析 大家好呀&#xff01;在数字化营销的大趋势下&#xff0c;程序化广告已经成为众多企业实现精准营销的关键手段。上一篇博客我们一起学习了程序化广告中的人群标签和Look Alike原理等知…...

【文献研究】铝对热冲压加热过程中锌氧化的影响

在热冲压过程中&#xff0c;镀锌铁板和镀锌板等镀锌钢板表面发生Zn氧化。为了阐明镀锌层中的Al对Zn氧化的影响&#xff0c;本研究研究了镀锌钢板上添加和不添加Al时形成的ZnO量。发现添加铝后ZnO量减少。对添加铝的镀锌钢板的显微组织分析表明&#xff0c;添加的Al在热冲压后Zn…...

Win11本地从零开始部署dify全流程

1.安装wsl和打开Hyper-V功能&#xff08;前置准备&#xff09; 这个是为了支持我们的Docker Desktop运行。 1.1.安装wsl 使用管理员身份运行命令行。 如果显示 “无法与服务器建立连接就执行“&#xff0c;表示没有安装wsl&#xff0c;如果更新成功&#xff0c;那就不用执行…...

从代码学习深度学习 - RNN PyTorch版

文章目录 前言一、数据预处理二、辅助训练工具函数三、绘图工具函数四、模型定义五、模型训练与预测六、实例化模型并训练训练结果可视化总结前言 循环神经网络(RNN)是深度学习中处理序列数据的重要模型,尤其在自然语言处理和时间序列分析中有着广泛应用。本篇博客将通过一…...

【HTB】Windwos-easy-Legacy靶机渗透

靶机介绍&#xff0c;一台很简单的WIndows靶机入门 知识点 msfconsole利用 SMB历史漏洞利用 WIndows命令使用&#xff0c;type查看命令 目录标题 一、信息收集二、边界突破三、权限提升 一、信息收集 靶机ip&#xff1a;10.10.10.4攻击机ip&#xff1a;10.10.16.26 扫描TC…...

蓝桥杯真题———k倍区间

题目如下 代码如下 记录余数 cnt[0] 1 的初始化是为了处理 空前缀和 说明...

LeetCode 891 -- 贡献度思想

题目描述 子序列宽度之和 思路 ref 代码 相似题 子数组范围和 acwing...

无人机等非合作目标公开数据集2025.4.3

一.无人机遥感数据概述 1.1 定义与特点 在遥感技术的不断发展中&#xff0c;无人机遥感数据作为一种新兴的数据源&#xff0c;正逐渐崭露头角。它是通过无人驾驶飞行器&#xff08;UAV&#xff09;搭载各种传感器获取的地理空间信息&#xff0c;具有 覆盖范围大、综合精度高、…...

机器视觉--python基础语法

Python基础语法 1. Python标识符 在 Python 里&#xff0c;标识符由字母、数字、下划线组成。 在 Python 中&#xff0c;所有标识符可以包括英文、数字以及下划线(_)&#xff0c;但不能以数字开头。 Python 中的标识符是区分大小写的。 以下划线开头的标识符是有特殊意义的…...

司南评测集社区 3 月上新一览!

司南评测集社区 CompassHub 作为司南评测体系的重要组成部分&#xff0c;旨在打创新性的基准测试资源导航社区&#xff0c;提供丰富、及时、专业的评测集信息&#xff0c;帮助研究人员和行业人士快速搜索和使用评测集。 2025 年 3 月&#xff0c;司南评测集社区新收录了一批评…...

TrollStore(巨魔商店)介绍及操作手册

TrollStore&#xff08;巨魔商店&#xff09;介绍及操作手册 一、TrollStore 简介 TrollStore 是一款针对 iOS 设备开发的第三方应用安装工具&#xff0c;它允许用户在不越狱设备的情况下&#xff0c;安装和使用未经过苹果官方 App Store 审核的应用程序。该工具利用了 iOS 系…...

SSE与Streamable HTTP的区别:协议与技术实现的深度对比

引言 在现代Web开发中&#xff0c;实时数据传输是许多应用的核心需求&#xff0c;从聊天应用到股票市场更新&#xff0c;从游戏服务器到AI模型通信。为了满足这一需求&#xff0c;各种技术应运而生&#xff0c;其中Server-Sent Events (SSE)和Streamable HTTP是两种重要的实时…...

android 之简述屏幕分辨率、屏幕密度、屏幕最小宽度

一、屏幕分辨率 屏幕分辨率是指屏幕显示的像素数量&#xff0c;通常以水平像素数乘以垂直像素数表示&#xff0c;例如 1920x1080。它直接影响屏幕的显示效果&#xff0c;包括图像的清晰度和细节。不同的设备可能有不同的屏幕分辨率。 1、常见的屏幕分辨率 标准分辨率&#x…...

mac环境中Nginx安装使用 反向代理

安装 如没有Homebrew 先安装Homebrew 国内镜像&#xff1a; /bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)" 安装成功后安装nginx&#xff1a; brew install nginx 启动nginx&#xff1a; nginx 或者 brew services st…...

2025年3月个人工作生活总结

本文为 2025年3月工作生活总结。 研发编码 一个curl下载失败问题的记录 问题&#xff1a; 某程序&#xff0c;指定IP和账户密码配置&#xff0c;再使用curl库连接sftp服务器&#xff0c;下载文件。在CentOS系统正常&#xff0c;但在某国产操作系统中失败&#xff0c;需要用命…...

实战打靶集锦-36-Deception

文章目录 1. 主机发现2. 端口扫描3. 服务枚举4. 服务探查5. 系统提权6. 写在最后 靶机地址&#xff1a;https://download.vulnhub.com/haclabs/Deception.ova 1. 主机发现 目前只知道目标靶机在192.168.56.xx网段&#xff0c;通过如下的命令&#xff0c;看看这个网段上在线的主…...

前端开发技术演进与就业现实:顺应时代方能不被淘汰-优雅草卓伊凡

前端开发技术演进与就业现实&#xff1a;顺应时代方能不被淘汰-优雅草卓伊凡 在技术浪潮汹涌的当下&#xff0c;常有人发问&#xff1a;“学习CSS、HTML、JS以后可以干什么&#xff1f;”对此&#xff0c;卓伊凡可以明确地给出答案&#xff1a;单纯学习这些过于基础的Web前端开…...

敏捷开发:以人为本的高效开发模式

目录 前言1. 什么是敏捷开发&#xff1f;1.1 敏捷开发的核心理念1.2 敏捷开发的优势 2. 敏捷宣言&#xff1a;四大核心价值观2.1 个体和交互胜过工具和过程2.2 可工作的软件胜过大量的文档2.3 客户合作胜过合同谈判2.4 响应变化胜过遵循计划 3. 敏捷开发的实践3.1 Scrum&#x…...

HarmonyOS 基础组件和基础布局的介绍

1. HarmonyOS 基础组件 1.1 Text 文本组件 Text(this.message)//文本内容.width(200).height(50).margin({ top: 20, left: 20 }).fontSize(30)//字体大小.maxLines(1)// 最大行数.textOverflow({ overflow: TextOverflow.Ellipsis })// 超出显示....fontColor(Color.Black).…...

CAD插入属性块 弹窗提示输入属性值——CAD知识讲堂

插入属性块时&#xff0c;有时会遇到不弹窗输入属性值的情况&#xff0c;解决方案如下&#xff1a; 最好关闭块编辑器并保存&#xff0c;插入属性块即可弹窗。...

Redis 主要能够用来做什么

Redis&#xff08;Remote Dictionary Server&#xff09;是一种基于内存的键值存储数据库&#xff0c;它的性能极高&#xff0c;广泛应用于各种高并发场景。以下是 Redis 常见的用途&#xff1a; 1. 缓存&#xff08;Cache&#xff09; 作用&#xff1a;存储热点数据&#xf…...

MySQL GROUP BY 和 HAVING 子句中 ‘Unknown column‘ 错误的深入解析

在使用 MySQL 进行数据分析和报表生成时&#xff0c;GROUP BY 和 HAVING 子句是非常强大的工具。然而&#xff0c;很多开发者在使用它们时会遇到一个常见的错误&#xff1a;"Unknown column column_name in having clause"。本文将深入解析这个错误的原因&#xff0c…...

Sentinel实战(三)、流控规则之流控效果及流控小结

spring cloud Alibaba-Sentinel实战&#xff08;三&#xff09;、流控效果流控小结 一、流控规则&#xff1a;流控效果一&#xff09;、流控效果&#xff1a;预热1、概念含义2、案例流控规则设置测试结果 二&#xff09;、流控效果&#xff1a;排队等待1、概念含义2、案例流控规…...

JavaScrip——DOM编程

一、DOM元素创建与属性操作 1. 元素创建与插入 // 创建新元素 const newDiv document.createElement(div); newDiv.textContent "动态创建的内容";// 插入到容器末尾 document.body.appendChild(newDiv);// 在指定元素前插入 existingElement.before(newDiv);// …...