微信支付之JSAPI支付开发流程

article/2025/9/13 22:22:24

JSAPI支付

  • 前言
  • 准备
  • 开发
    • 1.流程说明
    • 2.下单(预支付)
    • 3.前端调起支付
    • 4.支付结果异步通知
    • 5.退款申请
    • 6.退款结果异步通知
  • 结语

前言

最近项目涉及到微信支付的功能,在这里简单分享下整体的开发流程,这里要介绍的是JSAPI支付。

JSAPI网页支付,即日常所说的公众号支付,可在微信公众号、朋友圈、聊天会话中点击页面链接,或者用微信“扫一扫”扫描页面地址二维码在微信中打开商户HTML5页面,在页面内下单完成支付。

上述介绍可以简单理解为,jsapi支付必须在微信浏览器中进行。
微信支付支持多种接入模式,常用的就是直连模式及服务商模式。

直连模式是指商户自行开发系统来对接微信支付进行交易,微信支付将资金直接结算到商户的结算账户,商户给用户提供支付服务。该模式要求商户具备系统开发能力,商户可自行前往商户平台完成入驻。

服务商模式是指针对市面上一些中小型且没有开发能力的商户,由已在微信支付官方注册入驻的系统开发商或解决方案提供商协助这些商户完成入驻,开发及日常运营工作的模式。服务商可前往 服务商平台完成注册入驻。

根据实际项目情况,来选择接入模式。2种模式的api大同小异,其中服务商模式下支持多个子商户的入驻,而且支持点金计划。
以下介绍的普通商户(直连模式)下微信支付的开发流程。

准备

1.申请公众号appId,并配置对应的网页授权域名及ip白名单等
在这里插入图片描述
2.申请mchid,入驻普通商户,并开通JSAPI支付。
在这里插入图片描述
在这里插入图片描述
3.绑定APPID及mchid
在这里插入图片描述
4.配置API key以及api证书
在这里插入图片描述
5.设置支付目录

商户最后请求拉起微信支付收银台的页面地址我们称之为“支付目录”。
如果支付授权目录设置为顶级域名,那么只校验顶级域名,不校验后缀;如果支付授权目录设置为多级目录,就会进行全匹配。

在这里插入图片描述

开发

准备工作完成后,可以愉快的开发接口了。这里要说明的是,微信支付api目前有V2和V3两个版本,都长期有效,签名方式和参数格式可能略有不同,V3还需要商户平台证书(区别于Api证书),但是大体的开发思路以及关键参数都是一致的。
在这里插入图片描述

1.流程说明

(a)微信下单支付的基本流程是,业务系统后台进行下单,生成微信支付订单(预支付),并将接口返回的相应参数(prepay_id)返回给前台,前台调起微信支付页面,输入密码支付后,微信会将支付结果异步通知给业务系统,系统进行相应业务处理。
(b)微信退款的流程是,业务系统发起退款申请,之后微信会将退款结果异步通知给业务系统,业务系统做相应处理。

注:后台发起下单申请或退款申请后,并不意味付款或退款成功,需要根据异步通知去判断,而且通知可能发起多次,需要业务系统正确处理通知,以下是官方建议。

当商户系统收到通知进行处理时,先检查对应业务数据的状态,并判断该通知是否已经处理。如果未处理,则再进行处理;如果已处理,则直接返回结果成功。在对业务数据进行状态检查和处理之前,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱。

考虑到多次异步通知处理后仍会出现订单状态未及时更新的情况,可以利用定时任务定期查询订单状态,并更新业务系统中的订单状态。

2.下单(预支付)

WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();Map<String, String> params = UnifiedOrderModel.builder().appid(wxPayApiConfig.getAppId()).mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).body("公众号支付").attach("hello world").out_trade_no(WxPayKit.generateStr()).total_fee("1000").spbill_create_ip(ip).notify_url(notifyUrl).trade_type(TradeType.JSAPI.getTradeType()).openid(openId).build().createSign(wxPayApiConfig.getPartnerKey(), SignType.HMACSHA256);String xmlResult = WxPayApi.pushOrder(false, params);log.info(xmlResult);Map<String, String> resultMap = WxPayKit.xmlToMap(xmlResult);String returnCode = resultMap.get("return_code");String returnMsg = resultMap.get("return_msg");if (!WxPayKit.codeIsOk(returnCode)) {return new AjaxResult().addError(returnMsg);}String resultCode = resultMap.get("result_code");if (!WxPayKit.codeIsOk(resultCode)) {return new AjaxResult().addError(returnMsg);}// 以下字段在 return_code 和 result_code 都为 SUCCESS 的时候有返回String prepayId = resultMap.get("prepay_id");Map<String, String> packageParams = WxPayKit.prepayIdCreateSign(prepayId, wxPayApiConfig.getAppId(),wxPayApiConfig.getPartnerKey(), SignType.MD5);String jsonStr = JSON.toJSONString(packageParams);return new AjaxResult().success(jsonStr);

微信下单返回的信息中有一项关键参数,prepay_id,需要返回给前端。

3.前端调起支付

function onBridgeReady(){WeixinJSBridge.invoke('getBrandWCPayRequest', {"appId":"wx2421b1c4370ec43b",     //公众号ID,由商户传入     "timeStamp":"1395712654",         //时间戳,自1970年以来的秒数     "nonceStr":"e61463f8efa94090b1f366cccfbbb444", //随机串     "package":"prepay_id=u802345jgfjsdfgsdg888",     "signType":"MD5",         //微信签名方式:     "paySign":"70EA570631E4BB79628FBCA90534C63FF7FADD89" //微信签名 },function(res){if(res.err_msg == "get_brand_wcpay_request:ok" ){// 使用以上方式判断前端返回,微信团队郑重提示://res.err_msg将在用户支付成功后返回ok,但并不保证它绝对可靠。} }); 
}
if (typeof WeixinJSBridge == "undefined"){if( document.addEventListener ){document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);}else if (document.attachEvent){document.attachEvent('WeixinJSBridgeReady', onBridgeReady); document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);}
}else{onBridgeReady();
}

发起请求时,package参数的统一格式prepay_id=***,就是统一下单接口返回的prepay_id参数值,就是上文提到的返回的关键参数。考虑签名算法比较麻烦,前端调取js支付所需的所有参数可以统一由后端返回。

4.支付结果异步通知

 @RequestMapping(value = "/payNotify", method = {RequestMethod.POST, RequestMethod.GET})public String payNotify(HttpServletRequest request) {String xmlMsg = HttpKit.readData(request);log.info("支付通知=" + xmlMsg);Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);String returnCode = params.get("return_code");// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态// 注意此处签名方式需与统一下单的签名类型一致if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {if (WxPayKit.codeIsOk(returnCode)) {// 更新订单信息(系统的具体业务处理)// 发送通知等Map<String, String> xml = new HashMap<String, String>(2);xml.put("return_code", "SUCCESS");xml.put("return_msg", "OK");return WxPayKit.toXml(xml);}}return null;}

通知接口的地址是通过【统一下单API】中提交的参数notify_url设置,如果链接无法访问,商户将无法接收到微信通知。接收到通知后,对订单信息(状态)进行更新。
商户处理后需要返回给微信参数,如果微信收到商户的应答不符合规范或超时,微信会判定本次通知失败,重新发送通知,直到成功为止。

5.退款申请

    @RequestMapping(value = "/refund", method = {RequestMethod.POST, RequestMethod.GET})public String refund(@RequestParam(value = "transactionId", required = false) String transactionId,@RequestParam(value = "outTradeNo", required = false) String outTradeNo) {try {log.info("transactionId: {} outTradeNo:{}", transactionId, outTradeNo);if (StrKit.isBlank(outTradeNo) && StrKit.isBlank(transactionId)) {return "transactionId、out_trade_no二选一";}WxPayApiConfig wxPayApiConfig = WxPayApiConfigKit.getWxPayApiConfig();Map<String, String> params = RefundModel.builder().appid(wxPayApiConfig.getAppId()).mch_id(wxPayApiConfig.getMchId()).nonce_str(WxPayKit.generateStr()).transaction_id(transactionId).out_trade_no(outTradeNo).out_refund_no(WxPayKit.generateStr()).total_fee("1").refund_fee("1").notify_url(refundNotifyUrl).build().createSign(wxPayApiConfig.getPartnerKey(), SignType.MD5);String refundStr = WxPayApi.orderRefund(false, params, wxPayApiConfig.getCertPath(), wxPayApiConfig.getMchId());log.info("refundStr: {}", refundStr);return refundStr;} catch (Exception e) {e.printStackTrace();}return null;}

退款时需要api证书,证书应放在有访问权限控制的目录中,防止被他人下载。

6.退款结果异步通知

    @RequestMapping(value = "/refundNotify", method = {RequestMethod.POST, RequestMethod.GET})public String refundNotify(HttpServletRequest request) {String xmlMsg = HttpKit.readData(request);log.info("退款通知=" + xmlMsg);Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);String returnCode = params.get("return_code");// 注意重复通知的情况,同一订单号可能收到多次通知,请注意一定先判断订单状态if (WxPayKit.codeIsOk(returnCode)) {String reqInfo = params.get("req_info");String decryptData = WxPayKit.decryptData(reqInfo, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey());log.info("退款通知解密后的数据=" + decryptData);// 更新订单信息// 发送通知等Map<String, String> xml = new HashMap<String, String>(2);xml.put("return_code", "SUCCESS");xml.put("return_msg", "OK");return WxPayKit.toXml(xml);}return null;}

退款结果的异步通知与支付异步通知处理方式类似,这里不再赘述。

结语

这里只是介绍了微信JSAPI支付的大体开发流程,实际开发中还需要考虑避免重复下单,重复退款,业务系统订单的状态与实际付款(退款)状态是否一致等情况;在对业务数据进行状态检查和处理时,要采用数据锁进行并发控制,以避免函数重入造成的数据混乱,以及事务的控制等。
具体的api实现可参照微信支付的官方文档和官方SDK及Demo,微信开放社区也有相应的代码实践供使用。

相关链接:
[1]微信支付官方文档
[2]:官方sdk及DEMO
[3]: 微信开放社区优秀实践源码


http://chatgpt.dhexx.cn/article/GtDJSTjp.shtml

相关文章

FME是一个好东东

FME产品分为三个层次&#xff1a; 一、入门级 1、特点&#xff1a;支持常见的GIS软件的数据交换&#xff0c;如 MapInfo TAB, DGN, DXF, DWG, SDTS, SHP, and TIGER&#xff1b;可以运行大部分函数&#xff08;Funtion和Factory&#xff09;&#xff1b;不支持由Plug-in开发的第…

黑马程序员Maven学习笔记

前言 这里是黑马程序员Maven学习笔记分享&#xff0c;这是视频链接。 我还有其它前端内容的笔记&#xff0c;有需要可以查看。 文章目录 前言基础Maven简介Maven是什么Maven的作用 Maven的下载Maven的基础概念仓库坐标本地仓库配置远程仓库的配置 第一个Maven项目Maven的项目…

MAEKDOWN

这里写自定义目录标题 欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants 创建一个自定义列表如何创建一个…

谷粒商城前端笔记

前端笔记 JavaScript ES6 ECMAScript6.0&#xff08;以下简称ES6&#xff0c;ECMAScript是一种由Ecma国际通过ECMA-262标准化的脚本&#xff09;&#xff0c;是JavaScript语言的下一代标准&#xff0c;2015年6月正式发布&#xff0c;从ES6开始的版本号采用年号&#xff0c;如…

谷粒商城-分布式基础【业务编写】

谷粒商城-分布式基础篇【环境准备】谷粒商城-分布式基础【业务编写】谷粒商城-分布式高级篇【业务编写】持续更新谷粒商城-分布式高级篇-ElasticSearch谷粒商城-分布式高级篇-分布式锁与缓存项目托管于gitee 一、三级分类 此处三级分类最起码得启动renren-fast、nacos、gate…

1. 谷粒商城架构

架构图 解析 客户通过任意客户端&#xff08;app/Web&#xff09;向服务器发送请求&#xff0c; 请求首先来到Nginx集群&#xff0c;Nginx将请求转交给Api网关&#xff08;SpringCloud Gateway&#xff09;, Api网关&#xff1a; 可以根据当前请求&#xff0c;动态路由到指…

谷粒商城详细笔记

前言 mysql安装在腾讯云 redis安装在本地虚拟机master上 运行时&#xff0c;renren-fast这个项目要到单独开个idea窗口打开。 一、项目简介 1、项目微服务架构图 微服务&#xff1a;拒绝大型单体应用&#xff0c;基于业务边界进行服务微化拆分&#xff0c;各个服务独立部…

谷粒商城之分布式基础(二)

6 商品服务 6.1 三级分类 商城的商品页面展示是一个三级分类的。有一级分类、二级分类、三级分类。这就是我们接下来要进行的操作。 6.1.1 数据库 首先我们在gulimall_pms这个数据库中的pms_category这个表下插入数据 商品三级分类SQL代码 6.1.2 查出所有分类及其子分类 1…

麦克

品牌&#xff1a;InvenSense Kingstate RS PRO 灵敏度&#xff1a;-27到-44db之间 方向性&#xff1a;全方位、单向性、噪声消除 标准操作电压&#xff1a;1.5V到3.3V均有 安装方式&#xff1a;导线、表面贴装、通孔 输出阻抗大小&#xff1a;1.8K、2.2K、200欧、350欧…

Kubeedge Beehive 模块源码分析

文章目录 概述结构Model --- 消息模型Header --- 消息头Router --- 消息路由资源操作资源类型 Context --- 上下文ModuleContext --- 模块上下文MessageContext --- 消息上下文GlobalContext --- 全局上下文方法 Channel Context数据结构方法ModuleContext 接口实现AddModuleAd…

谷粒商城简介(1~5集)

谷粒商城简介&#xff08;1~5集&#xff09; 一、项目简介 1、项目背景 1&#xff09;、电商模式 市面上有 5 种常见的电商模式 B2B、B2C、C2B、C2C、O2O&#xff1b; 1、B2B 模式 B2B (Business to Business)&#xff0c; 是指商家与商家建立的商业关系。 如&#xff1a;阿…

谷粒商城:分布式基础概念(2)

微服务 微服务架构风格&#xff0c;就像是把一个单独的应用程序开发为一套小服务&#xff0c;每个小服务运行在自 己的进程中&#xff0c;并使用轻量级机制通信&#xff0c;通常是 HTTP API。这些服务围绕业务能力来构建&#xff0c; 并通过完全自动化部署机制来独立部署。这些…

beetl,freemarker,thymeleaf对比及springboot集成

调研类型&#xff1a; Freemarker&#xff0c;Thymeleaf&#xff0c;Beetl&#xff0c;Velocity 调研方向&#xff1a; 性能&#xff0c;活跃度&#xff0c;各自优缺点&#xff0c;应用实例 2.1、性能报告&#xff1a; Jdk:1.8 Cpu: 8核12线程 Jvm : -Xms512m -Xmx512m B…

部分壳与脱壳

壳与脱壳 对网上部分壳与脱壳的摘录与总结&#xff0c;仅供参考&#xff0c;侵删 参考链接1 https://www.52pojie.cn/thread-138380-1-1.html 参考链接2 https://www.cnblogs.com/milantgh/p/3869083.html 参考链接3 http://blog.sina.com.cn/s/blog_3e28c8a5010132m6.html 壳…

谷粒商城项目学-分布式基础

项目框架图 分布式基础概念 • 微服务、注册中心、配置中心、远程调用、Feign、网关 • 2、基础开发 • SpringBoot2.0、SpringCloud、Mybatis-Plus、Vue组件化、阿里云对象存储 • 3、环境 • Vagrant、Linux、Docker、MySQL、Redis、逆向工程&人人开源 • 4、开发规范 •…

【笔记/后端】谷粒商城基础篇

目录 一、环境配置1 Docker1.1 Docker是什么&#xff1f;1.2 安装&启动1.2.1 阿里云镜像加速 1.3 安装MySQL1.4 安装Redis 2 开发环境2.1 Maven2.2 Git2.3 Node 二、创建微服务项目1 内容2 问题记录3 renren-generator 三、分布式组件1 Nacos1.1 注册中心1.2 配置中心1.2.1…

谷粒商城(二)

谷粒商城&#xff08;二&#xff09; 后台商品服务 - 三级分类1、查询1&#xff09;、接口编写2&#xff09;、树形展示三级分类数据3&#xff09;、配置网关路由1 更改前端 base 路径2 将服务注册进nacos3 网关模块配置路由4 测试 4&#xff09;、解决跨域 2、删除1&#xff0…

谷粒商城(五)

谷粒商城&#xff08;五&#xff09; 订单服务1、环境搭建1&#xff09;、页面2&#xff09;、代码 2、订单登录拦截3、订单确认页1&#xff09;、VO模型2&#xff09;、订单确认页数据查询1 接口编写2 调用远程服务 3&#xff09;、Feign远程调用丢失请求头启动服务报错解决 4…

谷粒商城(一)

谷粒商城&#xff08;一&#xff09; 1、环境搭建安装 dockerdocker 安装 mysqldocker 安装 redis安装配置 git准备工具 IDEA、VsCode从 gitee 初始化项目 2、创建微服务项目1&#xff09;、创建项目2&#xff09;、初始化数据库 3、使用人人开源搭建后台管理系统1&#xff09;…

谷粒商城:如何通过笔记复盘实现事半功倍?

前言 把谷粒商城做了一遍&#xff0c;其中遇的困难也记录了一下。将零散的笔记整理成有顺序的目录结构。方便自己回看、以及快速定位文章。特此记录、大部分在CSDN博客里边都可以搜索到。 大家想看的话也可以去这里看看&#xff1a;笔记地址传送门 后续还会继续维护这个笔记…