心情追忆:构建支付模块的五个基本接口设计

        之前,我独自一人开发了一个名为“心情追忆”的小程序,旨在帮助用户记录日常的心情变化及重要时刻。我从项目的构思、设计、前端(小程序)开发、后端搭建到最终部署。经过一个月的努力,通过群聊分享等方式,用户量也有了将近200人。虽然取得了初步的成绩,但我希望小程序能够持续发展。

基于上一篇

​​​​​​​心情追忆 - 打造完美支付体验:从零开始的支付功能实现https://blog.csdn.net/qq_34319145/article/details/144003105

是基于产品思维需要开发支付功能, 上篇只写了用户支付, 但实际支付需要有5个基本接口

1.用户支付

public static PrepayWithRequestPaymentResponse prepay(Integer total, String productTitle, String outTradeNo, String userOpenId) {// 使用单例模式获取配置Config config = getConfigInstance();// 构建serviceJsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();// request.setXxx(val)设置所需参数,具体参数可见Request定义PrepayRequest request = new PrepayRequest();Amount amount = new Amount();// 金额(单位分)amount.setTotal(total);request.setAmount(amount);request.setAppid(appId);request.setMchid(merchantId);// 支付项目名称request.setDescription(productTitle);// 回调地址request.setNotifyUrl(prePayNotifyUrl);// 交易编号request.setOutTradeNo(outTradeNo);Payer payer = new Payer();// 用户openidpayer.setOpenid(userOpenId);request.setPayer(payer);// 调用下单方法,这个是要给前端唤醒支付组件PrepayWithRequestPaymentResponse prepayWithRequestPaymentResponse = service.prepayWithRequestPayment(request);return prepayWithRequestPaymentResponse;}

2.支付回调

public void payNotify(@RequestHeader("Wechatpay-Signature") String wechatSignature,@RequestHeader("Wechatpay-Serial") String wechatPaySerial,@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,@RequestHeader("Wechatpay-Timestamp") String wechatTimestamp,@RequestHeader("Wechatpay-Signature-Type") String signatureType,@RequestBody String requestBody) {// 打印上面的所有参数, 方便调试log.info("wechatSignature: {}, wechatPaySerial: {}, wechatpayNonce: {}, wechatTimestamp: {}, signatureType: {}, requestBody: {}",wechatSignature, wechatPaySerial, wechatpayNonce, wechatTimestamp, signatureType, requestBody);// 构建RequestParam, 这是下面的回调通知解析器需要用到的参数com.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder().serialNumber(wechatPaySerial).nonce(wechatpayNonce).signature(wechatSignature).timestamp(wechatTimestamp).body(requestBody).build();// 初始化 回调通知解析器, 传参和支付的配置一样NotificationParser parser = new NotificationParser(WxPayment.getConfigInstance());// sdk自动 验签、解密并转换成 Transaction(交易信息)Transaction transaction = parser.parse(requestParam, Transaction.class);// 更新支付记录表WechatPaymentRecords wechatPaymentRecord = wechatPaymentRecordsService.findByOutTradeNo(transaction.getOutTradeNo());wechatPaymentRecord.setStatus(transaction.getTradeState().name());wechatPaymentRecord.setTransactionId(transaction.getTransactionId());wechatPaymentRecordsService.updateById(wechatPaymentRecord);// 上面都成功后, 处理业务: 增加用户可使用次数UserFunctionRecord userFunctionRecord = userFunctionRecordService.getUserFunctionRecord(wechatPaymentRecord.getUserId());userFunctionRecord.setTotalUsageLimit(userFunctionRecord.getTotalUsageLimit() + 1);userFunctionRecordService.updateById(userFunctionRecord);// 自己好玩, 发个钉钉消息dingTalkMsg.sendMsgToDingTalk(JSONUtil.toJsonPrettyStr(transaction));}

3.支付列表查询

        这个就是查自己记录的表了

    public BaseResult<List<WechatPaymentRecords>> listPayments(@CurrentUser UserPrincipal userPrincipal) {// 基于springSecurity管理的CurrentUser拿到用户ID, 去查询支付记录List<WechatPaymentRecords> byUserId = wechatPaymentRecordsService.findByUserId(userPrincipal.getUserId());return BaseResult.success(byUserId);}

4.用户退款

和支付差不多, 不过比支付简单的是不用返回唤起支付组件的参数, 随便返回业务需要的参数就好

/*** 退款* @param outTradeNo 内部支付单号* @param outRefundNo 内部退款单号, 自己生成* @param reason 退款原因, 不必填, 业务必须填, 用于用户画像* @param total 订单金额* @param refund 退款金额* @return*/public static Refund createRefund(String outTradeNo,String outRefundNo, String reason, Long total, Long refund) {// 使用单例模式获取配置Config config = getConfigInstance();// 构建serviceRefundService service = new RefundService.Builder().config(config).build();CreateRequest request = new CreateRequest();request.setOutTradeNo(outTradeNo);request.setOutRefundNo(outRefundNo);request.setReason(reason);request.setNotifyUrl(refundNotifyUrl);AmountReq amount = new AmountReq();amount.setTotal(total);amount.setRefund(refund);amount.setCurrency("CNY");request.setAmount(amount);Refund refundResponse = service.create(request);return refundResponse;}

5.退款回调

和支付回调差不多, 只不过解析出来的是RefundNotification退款信息, 支付回调可以和退款回调写相同的一个, 也可以写不同. 我觉得写不同代码看的会少很多分支会简洁一点. 

public void refundNotify(@RequestHeader("Wechatpay-Signature") String wechatSignature,@RequestHeader("Wechatpay-Serial") String wechatPaySerial,@RequestHeader("Wechatpay-Nonce") String wechatpayNonce,@RequestHeader("Wechatpay-Timestamp") String wechatTimestamp,@RequestHeader("Wechatpay-Signature-Type") String signatureType,@RequestBody String requestBody) {// 打印上面的所有参数log.info("wechatSignature: {}, wechatPaySerial: {}, wechatpayNonce: {}, wechatTimestamp: {}, signatureType: {}, requestBody: {}",wechatSignature, wechatPaySerial, wechatpayNonce, wechatTimestamp, signatureType, requestBody);// 构建RequestParamcom.wechat.pay.java.core.notification.RequestParam requestParam = new com.wechat.pay.java.core.notification.RequestParam.Builder().serialNumber(wechatPaySerial).nonce(wechatpayNonce).signature(wechatSignature).timestamp(wechatTimestamp).body(requestBody).build();// 初始化 NotificationParserNotificationParser parser = new NotificationParser(WxPayment.getConfigInstance());// sdk自动 验签、解密并转换成 RefundNotification(退款信息)RefundNotification transaction = parser.parse(requestParam, RefundNotification.class);WechatPaymentRecords wechatPaymentRecord = wechatPaymentRecordsService.findByOutTradeNo(transaction.getOutTradeNo());wechatPaymentRecord.setRefundStatus(transaction.getRefundStatus().name());wechatPaymentRecord.setRefundAmount(transaction.getAmount().getRefund());wechatPaymentRecord.setRefundTime(LocalDateTime.now());wechatPaymentRecord.setOutRefundNo(transaction.getOutRefundNo());wechatPaymentRecord.setRefundId(transaction.getRefundId());wechatPaymentRecordsService.updateById(wechatPaymentRecord);dingTalkMsg.sendMsgToDingTalk(JSONUtil.toJsonPrettyStr(transaction));}

然后就是通用的配置

标准的单例双重验证, 不知道的可以去了解一下单例双重验证

// 提供一个静态方法来获取 Config 实例public static RSAAutoCertificateConfig getConfigInstance() {if (configInstance == null) {synchronized (lock) {if (configInstance == null) {configInstance = new RSAAutoCertificateConfig.Builder().merchantId(merchantId).privateKeyFromPath(privateKeyPath).merchantSerialNumber(merchantSerialNumber).apiV3Key(apiV3key).build();}}}return configInstance;}

因为支付是购买产品, 所以需要一个产品表product, (有的大公司还有sku的概念, 但我这里不需要, 一切从简)

所以支付表可以这么设计:

关键是, 微信交易(transaction_id)的唯一Id和自己交易编号(out_trade_no)的唯一Id, 和状态, 退款也有一套. 是为了在微信支付平台查询实际交易信息用.

其中要关联业务数据userId和product_id.

CREATE TABLE `wechat_payment_records` (`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键,自增ID',`transaction_id` varchar(64) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '微信支付交易号,用于唯一标识一次支付交易',`out_trade_no` varchar(64) COLLATE utf8mb4_general_ci NOT NULL COMMENT '商户订单号,由商户生成,用于唯一标识一次支付请求',`user_id` bigint NOT NULL COMMENT '用户ID,关联用户表',`product_id` bigint NOT NULL COMMENT '产品Id',`amount` bigint NOT NULL COMMENT '支付金额,单位为元',`currency` varchar(10) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '货币种类,如CNY',`payment_time` datetime DEFAULT NULL COMMENT '支付时间,记录实际支付成功的时间',`status` varchar(20) COLLATE utf8mb4_general_ci NOT NULL COMMENT '支付状态,如SUCCESS、FAIL、REFUND等',`payment_method` varchar(50) COLLATE utf8mb4_general_ci NOT NULL COMMENT '支付方式,如JSAPI、APP、H5等',`description` text COLLATE utf8mb4_general_ci COMMENT '订单描述,用于记录支付的具体内容',`notify_url` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '回调通知URL,微信支付回调的地址',`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间,即发起支付请求的时间',`updated_at` datetime DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP COMMENT '记录更新时间,每次更新记录时自动更新',`ip_address` varchar(45) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户发起支付请求时的IP地址',`device_info` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '设备信息,如设备型号、操作系统等',`refund_status` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款状态,如NOT_REFUND、PARTIAL_REFUND、FULL_REFUND等',`refund_amount` bigint DEFAULT NULL COMMENT '退款金额,单位为元',`refund_time` datetime DEFAULT NULL COMMENT '退款时间,记录实际退款成功的时间',`out_refund_no` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款编号',`refund_id` varchar(64) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '微信支付退款单号',`refund_reason` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '退款原因',PRIMARY KEY (`id`),UNIQUE KEY `out_trade_no` (`out_trade_no`),UNIQUE KEY `transaction_id` (`transaction_id`),KEY `idx_user_id` (`user_id`) COMMENT '用户ID索引,用于快速查询某个用户的支付记录',KEY `idx_status` (`status`) COMMENT '支付状态索引,用于快速查询特定状态的支付记录',KEY `idx_created_at` (`created_at`) COMMENT '创建时间索引,用于按时间范围查询支付记录'
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='微信支付记录表';

总结

        和之前一篇一样: 

Java项目部署的三个阶段https://blog.csdn.net/qq_34319145/article/details/143963071目前我只有一个产品就是支付获得分析次数, 所以支付相关的表可以不太多. 如果后续业务变多变复杂, 就再继续去设计, 去完善. 不能一开始就上最完美的方案, 一定是要从最小MVP产品去一步一步迭代才行.

PS:

        上线审核时, 发现IOS打开小程序不允许出现虚拟产品的交易, 所以要关掉iOS的支付功能

// 检查是否为iOS系统const systemInfo = Taro.getSystemInfoSync();if (systemInfo.platform === 'ios') {Taro.showToast({title: 'iOS用户暂不支持支付功能',icon: 'none',duration: 2000});return;}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/479750.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

实验三 z变换及离散时间LTI系统的z域分析

实验原理 有理函数z 变换的部分分式展开 【实例2-1】试用Matlab 命令对函数 X ( z ) 18 18 3 − 1 − 4 z − 2 − z − 3 X\left(z\right)\frac{18}{183^{-1} -4z^{-2} -z^{-3} } X(z)183−1−4z−2−z−318​ 进行部分分式展开&#xff0c;并求出其z 反变换。 B[18]; A…

Web登录页面设计

记录第一个前端界面&#xff0c;暑假期间写的&#xff0c;用了Lottie动画和canvas标签做动画&#xff0c;登录和注册也连接了数据库。 图片是从网上找的&#xff0c;如有侵权私信我删除&#xff0c;谢谢啦~

【es6】原生js在页面上画矩形及删除的实现方法

画一个矩形&#xff0c;可以选中高亮&#xff0c;删除自己效果的实现&#xff0c;后期会丰富下细节&#xff0c;拖动及拖动调整矩形大小 实现效果 代码实现 class Draw {constructor() {this.x 0this.y 0this.disX 0this.disY 0this.startX 0this.startY 0this.mouseDo…

高级 K8s 面试题(Advanced K8S Interview Questions)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

HiISP(一)

系列文章目录 文章目录 系列文章目录前言一、Hi3518EV200 芯片架构1.1. ARM子系统1.2. 图像子系统&#xff08;Image Subsystem&#xff09;1.3. 视频子系统&#xff08;Video Subsystem&#xff09;1.4. 存储与接口模块1.5. 通用功能模块1.6. DDR与总线1.7. 数据流1.7.1. 数据…

京东物流与亿纬锂能达成战略合作,双方跨界意义何在?

首先&#xff0c;这一合作有助于双方实现资源共享和优势互补。京东物流作为国内领先的物流服务商&#xff0c;拥有先进的物流技术和丰富的运营经验&#xff0c;能够为亿纬锂能提供高效、安全、可靠的物流服务。而亿纬锂能作为新能源领域的佼佼者&#xff0c;拥有先进的电池技术…

103.【C语言】数据结构之二叉树的三种递归遍历方式

目录 1.知识回顾 2.分析二叉树的三种遍历方式 1.总览 2.前序遍历 3.中序遍历 4.后序遍历 5.层序遍历 3.代码实现 1.准备工作 2.前序遍历函数PreOrder 测试结果 3.中序遍历函数InOrder 测试结果 4.后序遍历函数PostOrder 测试结果 4.底层分析 1.知识回顾 在99.…

【kafka03】消息队列与微服务之Kafka 读写数据

Kafka 读写数据 参考文档 Apache Kafka 常见命令 kafka-topics.sh #消息的管理命令 kafka-console-producer.sh #生产者的模拟命令 kafka-console-consumer.sh #消费者的模拟命令 创建 Topic 创建topic名为 chen&#xff0c;partitions(分区)为3&#xff0…

SAP开发语言ABAP开发入门

1. 了解ABAP开发环境和基础知识 - ABAP简介 - ABAP&#xff08;Advanced Business Application Programming&#xff09;是SAP系统中的编程语言&#xff0c;主要用于开发企业级的业务应用程序&#xff0c;如财务、物流、人力资源等模块的定制开发。 - 开发环境搭建 - 首先需…

[护网杯 2018]easy_tornado

这里有一个hint点进去看看&#xff0c;他说md5(cookie_secretmd5(filename))&#xff0c;所以我们需要获得cookie_secret的value 根据题目tornado,它可能是tornado的SSTI 这里吧filehash改为NULL. 是tornado的SSTI 输入{{handler.settings}} (settings 属性是一个字典&am…

【k8s深入学习之 Scheme】全面理解 Scheme 的注册机制、内外部版本、自动转换函数、默认填充函数、Options等机制

参考 【k8s基础篇】k8s scheme3 之序列化_基于schema进行序列化-CSDN博客【k8s基础篇】k8s scheme4 之资源数据结构与资源注册_kubernetes 的scheam-CSDN博客 Scheme的字段总览 type Scheme struct {// gvkToType 允许通过给定的版本和名称来推断对象的 Go 类型。// map 键是…

PySide6 QSS(Qt Style Sheets) Reference: PySide6 QSS参考指南

Qt官网参考资料&#xff1a; QSS介绍&#xff1a; Styling the Widgets Application - Qt for Pythonhttps://doc.qt.io/qtforpython-6/tutorials/basictutorial/widgetstyling.html#tutorial-widgetstyling QSS 参考手册&#xff1a; Qt Style Sheets Reference | Qt Widge…

python控制鼠标,键盘,adb

python控制鼠标&#xff0c;键盘&#xff0c;adb 听说某系因为奖学金互相举报&#xff0c;好像拿不到要命一样。不禁想到几天前老墨偷走丁胖子的狗&#xff0c;被丁胖子逮到。他面对警察的问询面不改色坚持自我&#xff0c;反而是怒气冲冲的丁胖子被警察认为是偷狗贼。我觉得这…

前端Vue项目整合nginx部署到docker容器

一、通过Dockerfile整合nginx方法&#xff1a; 1&#xff0c;使用Vue CLI或npm脚本构建生产环境下的Vue项目。 npm run build or yarn build2&#xff0c;构建完成后&#xff0c;项目目录中会生成一个dist文件夹&#xff0c;里面包含了所有静态资源文件&#xff08;HTML、CSS…

ChatGPT的应用场景:开启无限可能的大门

ChatGPT的应用场景:开启无限可能的大门 随着人工智能技术的快速发展,自然语言处理领域迎来了前所未有的突破。其中,ChatGPT作为一款基于Transformer架构的语言模型,凭借其强大的语言理解和生成能力,在多个行业和场景中展现出了广泛的应用潜力。以下是ChatGPT八个最具代表…

Wireshark抓取HTTPS流量技巧

一、工具准备 首先安装wireshark工具&#xff0c;官方链接&#xff1a;Wireshark Go Deep 二、环境变量配置 TLS 加密的核心是会话密钥。这些密钥由客户端和服务器协商生成&#xff0c;用于对通信流量进行对称加密。如果能通过 SSL/TLS 日志文件&#xff08;例如包含密钥的…

【dvwa靶场:File Upload系列】File Upload低-中-高级别,通关啦

目录 一、low级别,直接上传木马文件 1.1、准备一个木马文件 1.2、直接上传木马文件 1.3、访问木马链接 1.4、连接蚁剑 二、medium级别&#xff1a;抓包文件缀名 2.1、准备一个木马文件&#xff0c;修改后缀名为图片的后缀名 2.2、上传文件&#xff0c;打开burpSuite&…

【深度学习|目标跟踪】StrongSort 详解(以及StrongSort++)

StrongSort详解 1、论文及源码2、DeepSort回顾3、StrongSort的EMA4、StrongSort的NSA Kalman5、StrongSort的MC6、StrongSort的BOT特征提取器7、StrongSort的AFLink8、未完待续 1、论文及源码 论文地址&#xff1a;https://arxiv.org/pdf/2202.13514 源码地址&#xff1a;https…

10、PyTorch autograd使用教程

文章目录 1. 相关思考2. 矩阵求导3. 两种方法求jacobian 1. 相关思考 2. 矩阵求导 假设我们有如下向量&#xff1a; y 1 3 x 1 5 [ w T ] 5 3 b 1 3 \begin{equation} y_{1\times3}x_{1\times5}[w^T]_{5\times3}b_{1\times3} \end{equation} y13​x15​[wT]53​b13​​…

【AI】Sklearn

长期更新&#xff0c;建议关注、收藏、点赞。 友情链接&#xff1a; AI中的数学_线代微积分概率论最优化 Python numpy_pandas_matplotlib_spicy 建议路线&#xff1a;机器学习->深度学习->强化学习 目录 预处理模型选择分类实例&#xff1a; 二分类比赛 网格搜索实例&…