<p><strong>支付流程分析</strong></p>
讯享网
讯享网
购物车数据存redis,订单数据不存redis,因为现在微信同一个订单号可以生成多次二维码
流层以下图为准:

我们通过订单系统下单,然后订单系统调用支付系统去向微信支付的服务器发送请求,然后获取二
维码返回给用户,然后订单系统就开始监听MQ。
用户扫码支付后,支付系统将支付状态存进MQ中。订单系统检测到用户已经付钱了,就将订单设
为已支付,然后存进MySQL中。
可能会因为网络问题导致订单系统获取不到支付状态,所以订单系统会定时向微信支付服务器发送
请求去查询订单状态。
二维码创建(了解)
qrious是一款基于HTML5 Canvas的纯JS二维码生成插件。通过qrious.js可以快速生成各种二维
码,你可以控制二维码的尺寸颜色,还可以将生成的二维码进行Base64编码。
qrious.js二维码插件的可用配置参数如下:
例子:注意要引入qrious.js
微信扫码支付简介
微信扫码支付是商户系统按微信支付协议生成支付二维码,用户再用微信“扫一扫”完成支付的模
式。该模式适用于PC网站支付、实体店单品或订单支付、媒体广告支付等场景。
申请步骤:(了解)
第一步:注册公众号(类型须为:服务号)
请根据营业执照类型选择以下主体注册:个体工商户| 企业/公司| 政府| 媒体| 其他类型。
第二步:认证公众号
公众号认证后才可申请微信支付,认证费:300元/次。
第三步:提交资料申请微信支付
登录公众平台,点击左侧菜单【微信支付】,开始填写资料等待审核,审核时间为1-5个工作日内。
第四步:开户成功,登录商户平台进行验证
资料审核通过后,请登录联系人邮箱查收商户号和密码,并登录商户平台填写财付通备付金打的小额资金数额,完成账户验证。
第五步:在线签署协议
本协议为线上电子协议,签署后方可进行交易及资金结算,签署完立即生效。
开发文档
微信支付接口调用的整体思路:
按API要求组装参数,以XML方式发送(POST)给微信支付接口(URL),微信支付接口也是以
XML方式给予响应。程序根据返回的结果(其中包括支付URL)生成二维码或判断订单状态。
在线微信支付开发文档:
https://pay.weixin..com/wiki/doc/api/index.html


讯享网
微信支付还有模式一和模式二,
模式二适合线上支付,支付一次二维码就不能用了,
模式一的二维码可以一直使用,比如用于自动售货机。

现在官网上直接是开发指引,没有区分模式一模式二

微信支付流程分析

微信支付SDK

使用微信支付SDK,在maven工程中引入依赖

HttpClient工具类
HttpClient是Apache Jakarta Common下的子项目,用来提供高效的、最新的、功能丰富的支持HTTP协议的客户端编程工具包,并且它支
持HTTP协议最新的版本和建议。
HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClient。
HttpClient通俗的讲就是模拟了浏览器的行为,如果我们需要在后端向某一地址提交数据获取结果,就可以使用HttpClient
关于HttpClient(原生)具体的使用不属于我们本章的学习内容,我们这里这里为了简化HttpClient的使用,提供了工具类HttpClient(对原
生HttpClient进行了封装)
HttpClient工具类代码:
HttpClient工具类使用的步骤
讯享网
将HttpClient工具包放到common工程下并引入依赖,引入依赖后就可以直接使用上述的工具包了。

支付微服务搭建
(1)创建changgou-service-pay

(2)application.yml
创建application.yml,配置文件如下:
appid: 微信公众账号或开放平台APP的唯一标识
partner:财付通平台的商户账号
partnerkey:财付通平台的商户密钥
notifyurl: 回调地址
(3)启动类创建
在中创建,代码如下:
讯享网

微信支付二维码生成
在支付页面上生成支付二维码,并显示订单号和金额,用户拿出手机,打开微信扫描页面上的二维码,然后在微信中完成支付

实现思路
通过HttpClient工具类实现对远程支付接口的调用。
接口链接:https://api.mch.weixin..com/pay/unifiedorder
具体参数参见“统一下单”API, 构建参数发送给统一下单的url ,返回的信息中有支付url,根据url生成二维码,显示的订单号和金额也在返回
的信息中。
统一下单API讲解:https://pay.weixin..com/wiki/doc/api/native.php?chapter=9_1



代码实现
控制层
创建,主要调用WeixinPayService的方法获取创建二维码的信息
业务层
新增接口
讯享网
创建类,并发送Post请求获取预支付信息,包含二维码扫码支付地址
@Value注解将配置文件中的几个参数注入
浏览器测试:http://localhost:18089/weixin/pay/create/native?outtradeno=00&money=1
这里我们订单号随便填的,金额暂时写死,后续开发我们再对接业务系统得到订单号和金额

讯享网
打开支付页面/pay.html,修改value路径(改为上面测试结果中的code_url),然后打开,会出现二维码,可以扫码试试


检测支付状态(有时候可能因为网络原因导致支付状态没有及时返回到我们的服务器中,这个时候就要手动地去查询)
当用户支付成功后跳转到成功页面

当返回异常时跳转到错误页面

实现思路
我们通过HttpClient工具类实现对远程支付接口的调用。
接口链接:https://api.mch.weixin..com/pay/orderquery
具体参数参见“查询订单”API, 我们在controller方法中轮询调用查询订单(间隔3秒),当返回状态为success时,我们会在controller方法返
回结果。前端代码收到结果后跳转到成功页面。
https://pay.weixin..com/wiki/doc/api/native.php?chapter=9_2

代码实现
控制层
在新增方法,用于查询支付状态
业务层
修改,新增方法
讯享网
在com.changgou.pay.service.impl.WeixinPayServiceImpl中增加实现方法
测试:http://localhost:18089/weixin/pay/status/query?outtradeno=00

内网穿透
https://hsk.oray.com/
注册好花生壳,账号:ZHOUSHUVIP,密码:ZHOUSHU1*10
配置:

https://console.hsk.oray.com/forward

测试:用http://th.zicp.vip:25911/替换http://localhost:18089
http://th.zicp.vip:25911/weixin/pay/status/query?outtradeno=00

补充对订单的操作:
Redis存储订单信息(总结的时候,提到意义已经不大了,现在微信允许一个订单号生成多次的二
维码)
每次添加订单后,会根据订单检查用户是否是否支付成功,我们不建议每次都操作数据库,每次操作数据库会增加数据库的负载,我们可
以选择将用户的订单信息存入一份到Redis中,提升读取速度。
修改微服务的类中的方法,如果是线上支付,将用户订
单数据存入到Redis中,由于每次创建二维码,需要用到订单编号 ,所以也需要将添加的订单信息返回。
讯享网
修改的add方法,将订单对象返回,因为页面需要获取订单的金额和订单号用于创建二
维码,代码如下:

支付后修改订单状态
订单支付成功后,需要修改订单状态并持久化到数据库,修改订单的同时,需要将Redis中的订单删除,所以修改订单状态需要将订单日志
也传过来,实现代码如下:
修改com.changgou.order.service.OrderService,添加修改订单状态方法,代码如下:
修改com.changgou.order.service.impl.OrderServiceImpl,添加修改订单状态实现方法,代码如下:

讯享网
删除订单
如果用户订单支付失败了,或者支付超时了,我们需要删除用户订单,删除订单的同时需要回滚库存,

修改的com.changgou.order.service.OrderService,添加删除订单方法,我们只需要将订单id传入进来即可实现
修改的com.changgou.order.service.impl.OrderServiceImpl,添加删除订单实现方法
讯享网
支付结果回调通知
每次实现支付之后,微信支付都会将用户支付结果返回到指定路径,而指定路径是指创建二维码的时候填写的参数,
响应的数据以及相关文档参考一下地址:https://pay.weixin..com/wiki/doc/api/native.php?chapter=9_7&index=8

返回参数分析
通知参数如下:
以下字段在return_code为SUCCESS的时候有返回
响应分析
回调地址接收到数据后,需要响应信息给微信服务器,告知已经收到数据,不然微信服务器会再次发送4次请求推送支付信息。
回调接收数据实现
修改微服务的com.changgou.pay.controller.WeixinPayController,添加回调方法
讯享网
修改application.yml文件

测试:
注意要Debug模式启动支付微服务,回调方法中断点

http://th.zicp.vip:25911/weixin/pay/create/native?outtradeno=001&money=1

“code_url”:“weixin://wxpay/bizpayurl?pr=8nNqCzz”

浏览器打开,生成二维码


微信扫码支付成功后,会自动跳转回调方法:


讯享网
MQ处理支付回调状态


支付系统是独立于其他系统的服务,不做相关业务逻辑操作,只做支付处理,所以回调地址接收微信服务返回的支付状态后,
立即将消息发送给RabbitMQ,订单系统再监听支付状态数据,根据状态数据做出修改订单状态或者删除订单操作。
补充docker rabbitmq:
容器启动之后就可以访问web管理端了http://宿主机IP:15672,默认创建了一个 guest 用户,密码也是guest


提供的虚拟机中已经存在队列和交换机,删了等下重新建


实际开发中需要手动在这里创建队列和交换机 (考虑用程序创建可能会报错)
备注:如果docker中没有安装rabbitmq,可以自己建
发送支付状态
(1)集成RabbitMQ
修改支付微服务,集成RabbitMQ,添加如下依赖:

讯享网
我们建议在后台手动创建队列,并绑定队列。

如果使用程序创建队列,可以按照如下方式实现,修改application.yml,配置支付队列和交换机信息,代码如下:

rabbitmq监听配置

创建队列以及交换机并让队列和交换机绑定,MQConfig

讯享网
发送MQ消息
修改WeixinPayController中回调方法,在接到支付信息后,立即将支付信息发送给RabbitMQ,代码如下:
整个代码如下:
讯享网
监听MQ消息处理订单
在订单微服务中,我们需要监听MQ支付状态消息,并实现订单数据操作。
集成RabbitMQ
在订单微服务中,先集成RabbitMQ,再监听队列消息。
在pom.xml中引入如下依赖:

在application.yml中配置rabbitmq配置,代码如下:

在application.yml中配置队列名字,代码如下:
讯享网
监听消息修改订单
在订单微服务于中创建com.changgou.order.listener.OrderMessagelistener,并在该类中consumeMessage方法,用于监听消息,
并根据支付状态处理订单,代码如下:

取消(关闭)订单
用微信支付开发文档中提供的取消(关闭)订单API:https://pay.weixin..com/wiki/doc/api/native.php?chapter=9_3

应用场景
以下情况需要调用关单接口:商户订单支付失败需要生成新单号重新发起支付,要对原订单号调用关单,避免重复支付;
系统下单后,用户支付超时,系统退出不再受理,避免用户继续,请调用关单接口。
注意:订单生成后不能马上调用关单接口,最短调用时间间隔为5分钟。
WeixinPayController
讯享网
想让监听支付结果的方法里调用取消订单的方法,可以使用 Feign调用:
新建一个api工程

备注:也可以不用 HttpClient httpClient = new HttpClient(“”);这种方式
在pom.xml中引入微信支付的SDK
讯享网
https://github.com/objcoding/WXPay-SDK-Java
https://blog.csdn.net/remsqks/article/details/
https://blog.csdn.net/haiyanghan/article/details/?ops_request_misc=%257B%2522request%255Fid%2522%253A%%2522%252C%2522scm%2522%253A%3...%2522%257D&request_id=00&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~top_positive~default-1-.pc_search_result_before_js&utm_term=%E5%BE%AE%E4%BF%A1%E6%94%AF%E4%BB%98&spm=1018.2226.3001.4187
上面取消(关闭)订单代码传的参数不全,改进如下:
关闭支付
用户如果半个小时没有支付,我们会关闭支付订单,但在关闭之前,需要先关闭微信支付,防止中
途用户支付。
修改支付微服务的WeixinPayService,添加关闭支付方法,代码如下:
修改WeixinPayServiceImpl,实现关闭微信支付方法,代码如下:
讯享网
现在还有个问题,如果用户下单 30 分钟后还没有支付,需要把订单取消。(超过5分钟取消订
单,是可以实现的,微信规定5分钟内不可取消)
超时订单处理思路

RabbitMQ延时消息队列(文档参考第14天文档)
延时队列介绍
延时队列即放置在该队列里面的消息是不需要立即消费的,而是等待一段时间之后取出消费。
那么,为什么需要延迟消费呢?我们来看以下的场景
网上商城下订单后30分钟后没有完成支付,取消订单(如:淘宝、去哪儿网)
系统创建了预约之后,需要在预约时间到达前一小时提醒被预约的双方参会
系统中的业务失败之后,需要重试
这些场景都非常常见,我们可以思考,比如第二个需求,系统创建了预约之后,需要在预约时间到达前一小时提醒被预约的双方参会。那么一天之中肯定是会有很多个预约
的,时间也是不一定的,假设现在有1点 2点 3点 三个预约,如何让系统知道在当前时间等于0点 1点 2点给用户发送信息呢,是不是需要一个轮询,一直去查看所有的预约,
比对当前的系统时间和预约提前一小时的时间是否相等呢?这样做非常浪费资源而且轮询的时间间隔不好控制。如果我们使用延时消息队列呢,我们在创建时把需要通知的
预约放入消息中间件中,并且设置该消息的过期时间,等过期时间到达时再取出消费即可。
Rabbitmq实现延时队列一般而言有两种形式:
第一种方式:利用两个特性: Time To Live(TTL)、Dead Letter Exchanges(DLX)[A队列过期->转发给B队列]
第二种方式:利用rabbitmq中的插件x-delay-message
TTL DLX实现延时队列
TTL
RabbitMQ可以针对队列设置x-expires(则队列中所有的消息都有相同的过期时间)或者针对Message设置x-message-ttl(对消息进行单独设置,
每条消息TTL可以不同),来控制消息的生存时间,如果超时(两者同时设置以最先到期的时间为准),则消息变为dead letter(死信)
Dead Letter Exchanges(DLX)
RabbitMQ的Queue可以配置x-dead-letter-exchange和x-dead-letter-routing-key(可选)两个参数,如果队列内出现了dead letter,
则按照这两个参数重新路由转发到指定的队列。
x-dead-letter-exchange:出现dead letter之后将dead letter重新发送到指定exchange
x-dead-letter-routing-key:出现dead letter之后将dead letter重新按照指定的routing-key发送

新建QueueConfig
讯享网
OrderServiceImpl增加发送延时消息

新建监听DelayMessageListener

测试OK
实际开发中应该监听后执行相关操作:
讯享网
定时处理订单状态
第一种方法
https://blog.csdn.net/mingwulipo/article/details/
第二种方法用redis实现延时队列
参考:
https://zhuanlan.zhihu.com/p/
https://blog.csdn.net/hyy147/article/details/
第三种方法:用两个队列
https://blog.csdn.net/weixin_/article/details/
https://blog.csdn.net/weixin_/article/details/
https://www.cnblogs.com/lylife/p/7881950.html
https://blog.csdn.net/sdTAyhn/article/details/
畅购全部代码参考地址:
https://gitee.com/dai15/changgou
https://github.com/CodeHaotian/changgou
https://github.com/SuperGabriel/changgou
https://gitee.com/SixteenWords/changgou?_from=gitee_search
购物车:
订单代码:
讯享网

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/177163.html