用同一个二维码进行支付支付宝或者微信
前言
项目中需要一个二维码扫码后可以使用微信或者支付宝进行下单,今天来简要介绍一下如何实现。
这个问题其实比较简单,就是扫码后根据扫码的App调用不同的支付方式进行支付。扫码App主要有三种情况
- 微信;
- 支付宝;
- 其他可扫码的App。
至于实际生产订单的时间可以自己控制,可以在生成二维码的时候,完成订单的创建,不过这样的订单的实际支付方式是不确定的,需要用户支付的时候更新支付方式,用户可以更换支付方式。
不过我们我们并没有采用这种方式,因为这样用户可能出现用多种方式同时都付款的情况(虽然一般人不会这么做,但是还是有可能出现)。我们采用的方式是用户点击生成二维码后,生成一个预支付订单。用户扫码后,点击实际生成订单,订单的支付方式是确定的,之后不会再进行修改。
步骤如下:
- 用户点击下单,检查用户是否可以下单,可以下单的话,生成预支付id;
- 浏览器端用预支付id生成二维码;
- 用户扫码,进入下单确认页面;
- 用户点击下单进行支付。
预支付
我这边采用了预支付的方式,主要是为了两个目的:
- 记录下单需要的参数,比如用户id、商品id和优惠码,并且用户对这些参数生成后无法更改;
- 避免使用短链接,因为如果把这些参数附加到二维码中,二维码扫码的识别率就会降低,需要使用短链接。
数据库表设计
CREATE TABLE `prepay` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` bigint(20) NOT NULL,
`good_type` int(11) NOT NULL,
`add_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`sn` varchar(16) DEFAULT NULL,
`order_id` int(11) DEFAULT NULL,
`extra_info` varchar(1024) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `order_id` (`order_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
user_id
标识是哪个用户下单,good_type
标识是哪个商品,sn
标识使用的优惠码,add_time
是预下单的时间,限制预支付id,有一个过期的时间,防止对旧的预支付id进行支付,extra_info
记录一些额外的信息,order_id
表示这个预支付id实际对应的订单id,用户下单后进行更新,这个字段主要是限制用户只能使用预支付id一次,当用这个预支付id下单后,支付方式和订单号已经确定了,这个预支付id不能再使用了。
生成二维码地址
这样当用户点击下单后,我们做一些必要的检查,插入一条预支付记录,得到一个prepay_id
。组成一个url,https://example.com/p/<prepay_id>/
,返回给浏览器。
浏览器用这个url生成二维码。
微信和支付宝的支付方式的选择
当用户扫码后,我们将战场转移到了手机上了。需要对支付宝和微信支付有比较多的了解,我们才能选择一个支付方式。
对于微信支付,我们在这篇文中介绍过微信支付集成简介。
微信支付有以下几种:
- 公众号支付;
- 扫码支付;
- APP支付;
- H5支付;
- 小程序支付。
而支付宝有以下几种:
- PC端支付;
- H5支付;
- APP支付。
如果用微信扫码的话,我们必须选择微信支付,这时候只能选择公众号支付了。
如果用支付宝扫码的话,必须选择支付宝支付,这时候支付宝的H5可以胜任。
如果用其他的App扫码的话,微信和支付宝均可,这时候支付宝仍然可以使用H5支付,而微信则必须使用H5支付。
扫码后下单
当我们扫码打开页面时,服务端根据UA
进行判断:
- 如果
UA
包含micromessenger
,则扫码的是微信,这时候用户只能现在微信公众号支付; - 如果
UA
包含alipay
,则扫码的是支付宝,这时候只能用支付宝H5支付; - 否则是其他App,支付宝H5和微信H5均可。
打开页面后如下:
用户点击下单,我们服务端根据用户的prepay_id
来拿到下单信息,如果预支付信息里包含了order_id
就说明这是一个旧的预支付id,可以显示旧的订单信息进行支付。否则,下单,更新order_id
字段。
接下来服务端只需要根据UA和用户的选择选择微信H5支付、支付宝H5支付和微信公众号支付即可。
小结
- 一个二维码支付我们将用户支付方式的选择延迟到了手机端;
- 支付宝H5在支付宝和其他App中都可以使用,但是微信需要分用微信扫码的话需要使用公众号支付,非微信扫码的话需要使用微信H5支付;
- 预支付id的使用可以限制一个订单只能一种固定的方式,并且预支付id和订单号一一对应,不会丢失预支付里的一些其它的信息。