说明:此博客旨在记录一此通用性支付的设计想法,微信支付相关文档此处不进行介绍(微信支付api传送门:https://pay.weixin.qq.com/wiki/doc/api/index.html),业务代码因为与公司机密相关所以此处不贴出,只贴出部分关键代码,常量部分因为命名较为规范所以不再贴出常量详细信息,且此博客主要为介绍一种想法,所有代码进行截图,不喜伸手党,设计因为时间短所以较为粗糙,只为了之后更好的扩展跟重构预留部分扩展性和通用性,如果发现有问题或者不明白的地方想要探讨欢迎留言,但是谢绝引战者和伸手党
最近公司需要对接微信小程序支付业务和微信公众号支付业务,但是我所在产品组没有对接过微信支付,而其他项目组也只有微信扫码支付的对接经验,所以不得不进行开荒工作。
微信除了扫码外所有支付业务基本流程都是:
统一下单 -> 根据响应预订单信息调起支付页面 -> 支付成功修改业务订单为中间等待状态,同时挂起查询或用户手动刷新 -> 微信方调用回调接口更改业务订单状态为已支付
这样的逻辑很适合策略模式的使用,所以决定暂时的简单设计一个通用支付接口,剥离变化将每个支付(不只是微信支付)的具体逻辑委任给具体策略。而业务订单的创建、完成等逻辑与支付的类型无关,所以使用命令模式将业务订单命令对象传入策略中在需要的时候进行业务操作(这是因为业务调用方与通用支付数据库公用所以没有进行复杂设计而选择命令模式对业务订单进行操作,如果支付业务作为一个服务与业务隔离,则建议将业务相关的代码做成接口将接口信息作为参数传递给通用支付进行回调操作)。
使用设计机制:策略模式、命令模式、简单工厂、模板方法模式(这几个模式和机制都是设计模式中最常用而且最简单的,此处不做说明,不清楚的可以查一下)
UML图:
类图:
类图说明与代码:
Controller与service不做累述
AbstractPayStrategy:支付策略的超类
方法:
generateOrder:为预订单生成方法
payOrderAgain:为生成业务订单后再次调用支付时的支付方法
AbstractWeChatPayStrategy:微信支付的支付策略超类
方法:
generateOrder:父类的委托方法,同时也是策略的入口方法
generateAndSaveOrder:创建业务订单的方法,此方法接受AbstractPayOrderCommand抽象命令对象的子类,根据选择的支付业务执行不同的业务订单创建命令
generateThirdPartyOrder:生成第三方预订单方法
collectThirdPartyOrder:收集第三方接口需要的参数的方法
addThirdPartyExtraParams:钩子方法,由子类重写添加不同微信支付类型的特有参数的方法
invokeThirdParty:执行第三方支付的调用
convertResponseDataToViewData:将第三方支付响应数据转化为DTO
convertDataToViewData:模板方法,由子类复写将转化后的DTO进行后处理
getTradeType:模板方法,获取不同支付类型
WeChatJsApiPayStrategy:公众号支付策略
WeChatMiniProgramPayStrategy:小程序支付策略
AbstractPayOrderCommand:业务订单命令对象超类,用于根据不同的传参选择不同的支付业务
方法:
generateAndSaveOrder:生成并保存订单
finishOrder:回调完成订单
payOrderAgain:再次支付订单
PayStrategyFactory:生成支付策略的简单工厂
PayOrderCommandFactory:生成订单命令的简单工厂
时序图:
- 统一下单
- 支付成功回调
微信支付文档有一些地方不明确甚至有一些问题,然后参数命名规范也没有统一当时调试遇到了很多坑,主要遇到的特别坑的地方说一下:
1、Jsapi类型的支付,openid写的非必填但是说明里又说必填
2、统一下单全部使用全小写的命名格式,但是调起微信支付页面的时候又要求驼峰规则
3、公众号支付时如果你在调起支付的时候提示你“total_fee 不能为空“那么恭喜你,很多统一下单的时候还有调起时候参数的问题都会报这个错,实际上不一定是total_fee为空,把他当作参数错误改吧,走远程debugger之类的看你统一下单时候的传参有问题没
4、他们文档里说回调时候给他们响应的格式是错误,反正我用他们说的格式怎么都不行(成不成功的现象是他回调你的次数,如果支付成功后进行回调失败微信方会试七次),我回调响应成功的方法是用响应流直接如下图:
5、如果你看到他们有了H5支付认为这个H5支付是所有浏览器都可以使用的支付就大错特错了,这个H5支付是除了微信浏览器之外的手机端浏览器调用的支付,就是说微信浏览器不能用