码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 从零玩转系列之微信支付实战PC端支付微信取消接口搭建 | 技术创作特训营第一期


    合集 - 微信支付(8)
    1.从零玩转系列之微信支付开篇06-102.从零玩转系列之微信支付安全06-103.从零玩转系列之微信支付实战基础框架搭建06-104.从零玩转系列之微信支付实战PC端接口搭建06-125.从零玩转系列之微信支付实战PC端支付微信回调接口搭建07-29
    6.从零玩转系列之微信支付实战PC端支付微信取消接口搭建 | 技术创作特训营第一期 08-08
    7.从零玩转系列之微信支付实战PC端支付微信退款接口搭建 | 技术创作特训营第一期08-088.从零玩转系列之微信支付实战PC端项目构建+页面基础搭建 | 技术创作特训营第一期08-09
    收起

    一、前言

    从零玩转系列之微信支付实战PC端支付微信取消接口搭建 | 技术创作特训营第一期

    halo各位大佬很久没更新了最近在搞微信支付,因商户号审核了我半个月和小程序认证也找了资料并且将商户号和小程序进行关联,至此微信支付Native支付完成.此篇文章过长我将分几个阶段的文章发布(项目源码都有,小程序和PC端)

    在此之前已经更新了微信支付开篇、微信支付安全、微信实战基础框架搭建、本次更新为微信支付实战PC端接口搭建,实战篇分为几个章节因为代码量确实有点多哈.

    • 第一章从零玩转系列之微信支付开篇
    • 第二章从零玩转系列之微信支付安全
    • 第三章从零玩转系列之微信支付实战基础框架搭建
    • 第四章从零玩转系列之微信支付实战PC端支付下单接口搭建
    • 第五章从零玩转系列之微信支付实战PC端支付微信回调接口搭建
    • 第五章从零玩转系列之微信支付实战PC端支付微信取消订单接口搭建
    • 第六章从零玩转系列之微信支付实战PC端支付微信退款订单接口搭建

    请在此添加图片描述

    本次项目使用技术栈

    后端: SpringBoot3.1.x、Mysql8.0、MybatisPlus

    前端: Vue3、Vite、ElementPlus

    小程序: Uniapp、Uview

    一、取消订单接口

    场景

    1. 用户下单完毕后未支付 可进行取消订单
    2. 订单超时支付系统自动取消订单

    修改 WechatNativeController

    /**
    * 用户取消订单
    */
    @PostMapping("/cancel/{orderNo}")
    public R cancel(@PathVariable String orderNo) {
    log.info("取消订单");
    wxPayService.cancelOrder(orderNo);
    return R.ok("订单已取消");
    }

    修改 wxPayService

    /**
    * 关闭订单
    */
    @SneakyThrows
    public void cancelOrder(String orderNo) {
    // ...../
    }

    逻辑分析

    在工作中我们逻辑可能是这样子的

    step 1 查询该订单状态是否需要关闭订单,如果订单已经关闭则不需要再次关闭

    思考: 我们应该去哪里查询订单的状态?

    输入图片说明

    假如我们去数据库查询记录的话,如果数据库因为什么原因导致状态可能不对呢?

    所以我们直接去微信服务器查最新的直接更新关闭状态到数据库当中

    输入图片说明

    你看微信也要我们这样子玩那就万无一失直接干

    ================================================================

    好既然我们要去调用微信查询接口我们是不是可以封装一个通用的 后续肯定有其他地方也会调用查询支付信息的情况

    文档(商户): https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_2.shtml

    有两种查询方式第二种方便就这么简单

    代码很好理解传递商户订单号和直连商户号mchid

    /**
    * 抽出公共获取微信订单信息
    */
    private WeChartOrderInfo selectOrderInfo(String orderNo) throws IOException {
    log.info("查询订单,直连商户号:{} , 微信支付订单号: {}", orderNo, wxPayConfig.getMchId());
    String url = wxPayConfig.getDomain().concat(String.format(WxApiType.ORDER_QUERY_BY_NO.getType(), orderNo)).concat("?mchid=").concat(wxPayConfig.getMchId());
    HttpGet httpGet = new HttpGet(url);
    httpGet.setHeader("Accept", "application/json");
    CloseableHttpResponse response = wxPayClient.execute(httpGet);
    WeChartOrderInfo weChartOrderInfo = buildBodyParams(response, WeChartOrderInfo.class);
    log.info("查询订单响应, {}", weChartOrderInfo);
    response.close();
    return weChartOrderInfo;
    }

    响应结果

    {
    "amount": {
    "currency": "CNY",
    "payer_currency": "CNY",
    "payer_total": 1,
    "total": 1
    },
    "appid": "wxdace645e0bc2cXXX",
    "attach": "",
    "bank_type": "OTHERS",
    "mchid": "1900006XXX",
    "out_trade_no": "44_2126281063_5504",
    "payer": {
    "openid": "o4GgauJP_mgWEWictzA15WT15XXX"
    },
    "promotion_detail": [],
    "success_time": "2021-03-22T10:29:05+08:00",
    "trade_state": "SUCCESS",
    "trade_state_desc": "支付成功",
    "trade_type": "JSAPI",
    "transaction_id": "4200000891202103228088184743"
    }

    完善逻辑

    /**
    * 关闭订单
    */
    @SneakyThrows
    public void cancelOrder(String orderNo) {
    // step 1 查询该订单状态是否需要关闭订单
    WeChartOrderInfo state = selectOrderInfo(orderNo);
    // 判断如果订单已经关闭则不需要再次关闭 更新数据库
    if (null == state || state.getTrade_state() == null) {
    // 更新本地订单状态超时关闭订单
    orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.CLOSED.getType()).update();
    return;
    }
    // step 2 还未支付才能取消订单
    if (state.getTrade_state().equals(OrderStatus.NOTPAY.name())) {
    // step 2 进行调用微信关闭订单接口
    sendCloseRequest(orderNo);
    // step 2 更新商户端的订单状态用户取消订单
    this.orderInfoService.lambdaUpdate().eq(OrderInfo::getOrderNo, orderNo).set(OrderInfo::getOrderStatus, OrderStatus.CANCEL.getType()).update();
    }
    }

    抽出通用订单关闭代码

    文档: https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_4_3.shtml

    /**
    * 发送关闭订单请求
    *
    * @param orderNo 订单编号
    */
    @SneakyThrows
    private void sendCloseRequest(String orderNo) {
    log.info("关闭订单, 订单号:{}", orderNo);
    String url = String.format(wxPayConfig.getDomain().concat(WxApiType.CLOSE_ORDER_BY_NO.getType()), orderNo);
    HttpPost httpPost = new HttpPost(url);
    Map paramsMap = new HashMap<>(1);
    paramsMap.put("mchid", wxPayConfig.getMchId());
    String jsonParams = JSONUtil.toJsonStr(paramsMap);
    log.info("请求参数 ===> {}", jsonParams);
    StringEntity entity = new StringEntity(jsonParams, "utf-8");
    entity.setContentType("application/json");
    httpPost.setEntity(entity);
    httpPost.setHeader("Accept", "application/json");
    try (CloseableHttpResponse response = wxPayClient.execute(httpPost)) {
    log.info("关单响应: {}", response.getEntity());
    log.info("解析body {}", buildBodyParams(response, Map.class));
    }
    }

    到这里订单取消就完毕了

    二、查询订单接口

    根据上面编写的查询订单方法完善一下

    修改 WechatNativeController

    /**
    * 查询订单
    */
    @PostMapping("/query/{orderNo}")
    public R query(@PathVariable String orderNo) {
    log.info("查询订单");
    return R.ok(wxPayService.queryOrder(orderNo));
    }

    修改 WxPayService

    /**
    * 查询订单信息
    *
    * @param orderNo 订单号
    * @return 订单信息
    */
    @SneakyThrows
    public WeChartOrderInfo queryOrder(String orderNo) {
    return this.selectOrderInfo(orderNo);
    }

    好了查询接口也写完了so easy to happy !

    我们来测试看看是什么效果咯~

    请在此添加图片描述

    三、测试

    下单

    我们还没编写到前端来所以还是和之前的文章操作一样使接口调试工具操作这里我使用之前推荐的IDEA FastRequest插件如下图

    发送请求

    发送

    发送

    生成二维码

    复制codeUrl参数打开草料 https://cli.im/url 不要支付哦我们确保订单是否成功创建,确保二维码没有过期哦

    下单

    我们也可以先看看订单啥状态上面我们不是写了个查询订单详情的嘛

    查询订单详情

    调用取消订单接口

    复制 orderNo 订单编号直接发送取消完成

    取消订单

    在查询一下订单看看状态是不是取消成功

    over

    over

    本文章仓库WeChatPayScaffolding

    【写作提纲】

    I. 前言

    A. 通过前言表达我每次的文章内容是什么东西

    II. 取消订单接口实现

    A. 集结生活之中的场景来解析他的逻辑

    III. 查询订单接口实现

    A. 完善取消订单接口当中已经实现了的功能

    IV. 测试

    A. 通过测试用例一步步排查编写是否存在BUG

  • 相关阅读:
    math_消除根式:椭圆的标准式方程推导&坐标系平移&整理多项式
    【Linux初阶】Linux调试器-gdb使用 | gdb的 l/b/info/d/r/n/s/bt/finish/p/(un)display/q
    libOpenDRIVE
    人机界面在石油钻井工程中的应用:如何搭建钻井工程参数监测系统?
    【android开发-10】android中四种布局详细介绍
    安卓期末大作业——售票APP源码和设计报告
    C++【内存管理】
    hdfs shell操作助记总结
    7-1归并排序还是插入排序
    使用Python的Turtle库绘制一个心形图像(含详细Python代码与注释)
  • 原文地址:https://www.cnblogs.com/Yangbuyi/p/17613962.html
  • 最新文章
  • 【JVM】编译执行与解释执行的区别是什么?JVM 使用哪种方式?
    用 Hashids 优雅解决 C 端自增 ID 暴露问题
    V8引擎 精品漫游指南--Ignition篇(上) 指令 栈帧 槽位 调用约定 内存布局 基础内容
    LLVM Pass快速入门(四):代码插桩
    milkup:桌面端 markdown AI续写和即时渲染
    基于项目工程构建SBOM(软件物料清单)的研究
    鸿蒙应用开发UI基础第二节:鸿蒙应用程序框架核心解析与实操
    .NET 中如何快速实现 List 集合去重?
    扣子Coze实战:从0到1打造抖音+小红书热点监控智能体
    浅谈数据访问层
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
小工具 小游戏
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

京公网安备 11010502049817号