目录
1、C扫B的概念
C扫B,即顾客(Customer)扫描商户(Business)提供的二维码来完成支付。下图是支付宝提供的C扫B业务流程:
- 商家出示付款二维码。
- 客户打开支付宝或微信的扫一扫,扫描二维码。
- 确认支付,完成支付。
C扫B支付分为两种方式:
- 一是固定金额支付,顾客扫描后无需输入金额直接确认支付即可;
- 另一种是输入金额,顾客扫描后需自己输入待支付的金额,然后完成支付。
什么是固定金额支付?
C扫B固定金额比较常见的就是在自动售货机购买饮料时,当你选择一个饮料后屏幕会显示一个二维码,咱们扫描后只需确认支付即可,无需自己输入饮料的价格,这种情况大家可以根据下面的交互流程图来自行实现。
什么是输入金额支付?
C扫B输入金额支付方式可以让买方自由输入金额,商户提前生成一个二维码,将二维码张贴在结账处,买方扫描二维码,输入当前消费的金额,完成支付。
2、支付宝接口调研
2.1、产品列表
支付宝为普通商户提供如下支付产品:
各个产品介绍详见:https://b.alipay.com/signing/productSetV2.htm
上述罗列的产品有很多,但是有个别的我们普通用户基本也用不到,所以我们只分析根据日常生活中常见且常用的到支付方式。
1、当面付:
在国内线下场景,商家可通过以下任一方式进行收款。提升商家收银效率,资金实时到账。
- 商家通过扫描顾客支付宝钱包中的条码、二维码等方式完成支付;
- 顾客通过使用支付宝钱包扫一扫,扫描商家的二维码等方式完成支付。
2、APP支付
商家APP集成支付宝提供的支付能力,在线上轻松收款:
用户在商家APP消费,自动跳转支付宝完成付款,付款后自动跳回。 轻松享受更全面、更安全- 的支付服务。
3、刷脸付
无需手机,刷脸支付:
当不便使用手机或没有手机时,用户亦可“刷脸”完成——通过线下支付机具读取脸部完成自助结账等支付行为,快捷安全方便。 商家多一种方案,用户多一种选择,同样方便安全。
4、手机网站支付
无需开发APP,手机网站同样能轻松收款:
用户在商家手机网站消费,通过浏览器自动跳转支付宝APP或支付宝网页完成付款。 轻松实现和APP支付相同的支付体验。
5、电脑网站支付
PC网站轻松收款,资金马上到账:
用户在商家PC网站消费,自动跳转支付宝PC网站收银台完成付款。 交易资金直接打入商家支付宝账户,实时到账。
2.2、线下场所接入支付
下边列出接入聚合支付平台且应用于线下场所的支付方式。
线下场所泛指商场、超市、便利店、餐饮、医院、学校、电影院和旅游景区等具有明确经营地址的实体场所。
当面付条码支付:
- 商家通过扫描线下买家支付宝钱包中的条码、二维码等方式完成支付;
- 条码支付应用于 B扫C的场景,即商户扫客户。
手机网站支付:
- 买家用支付宝客户端打开H5网页,点击支付,打开支付宝客户端支付界面,完成支付。
手机网站支付应用于C扫B场景,即客户扫商户。
聚合支付接入“支付宝手机网站支付”完成C扫B自由输入金额的支付,原因如下:
聚合支付对C扫B的一个需求是用户可自由输入金额,且向用户展示订单信息,存在手机网页交互,所以使用手机网站支付可以满足需求。
3、配置支付宝沙箱环境
接入手机网站支付需要具备如下条件:
- 申请前必须拥有经过实名认证的支付宝账户;
- 企业或个体工商户可申请;
- 需提供真实有效的营业执照,且支付宝账户名称需与营业执照主体一致;
- 网站能正常访问且页面显示完整,网站需要明确经营内容且有完整的商品信息;
- 网站必须通过 ICP备案。如为个体工商户,网站备案主体需要与支付宝账户主体名称一致,且团购不开放,且古玩、珠宝等奢侈品、投资类行业无法申请本产品。
手机网站支付接口以及开发指南官方文档:https://opendocs.alipay.com/open/203/105288
根据上述条件可知,个人账户基本是不满足要求的,如果是个人用于学习使用,支付宝还提供了一种专门用于测试的沙箱环境,使用支付宝沙箱进行开发测试,这里主要介绍支付宝沙箱环境配置。
沙箱环境官方文档:https://opendocs.alipay.com/common/02kkv7
3.1、简介
沙箱环境 (Beta) 是支付宝开放平台为您提供的与线上环境完全隔离的联调测试环境,在沙箱环境中完成的调用不会对线上数据造成任何影响,尤其适合涉及资金链路的能力的调试。
除此之外,沙箱环境还会自动完成或忽略一些场景的商业门槛,如:开发者无需等待产品签约,即可直接在沙箱环境发起 OpenAPI 的调用,使得开发集成工作可以与商务流程并行,从而提高项目整体的交付效率。
3.2、注册开放平台账号
注册地址:https://memberprod.alipay.com/account/reg/index.htm
如果你已经有了个人支付宝账号,可忽略这一步,直接扫码登录即可。
注册成功,登录支付宝开放平台:
进入沙箱环境开发管理平台:
默认进入沙箱环境的应用管理菜单:
3.3、配置密钥
使用支付沙箱需要配置密钥,密钥作为与支付宝接口对接的必要参数。
下载密钥生成工具:AlipayDevelopmentAssistant-x.x.x.exe,默认下载最新版的即可,双击执行安装,注意不要安装在有空格和带中文的目录中。
下载地址:https://ideservice.alipay.com/ide/getPluginUrl.htmclientType=assistant&platform=win&channelType=WEB
安装成功,勾选创建桌面快捷入口,进或者入安装目录:
双击打开,点击生成秘钥:
默认情况下会将生成的应用私钥和应用公钥,存放到C:\Users\用户名\Documents\支付宝开放平台开发助手\RSA密钥
,直接双击打开秘钥文件路径即可:
复制应用公钥,进入沙箱应用管理界面,点击下图中的 “设置”,将应用公钥粘贴进去,点击“保存设置”:
如果已经配置过了就点击“更换应用公钥”:
点击公钥,将上述生成的应用公钥粘贴到此处:
点击保存设置,同时生成支付宝公钥
:
保存好上述支付宝开放平台开大助手工具生成的应用私钥
和沙箱应用生成的支付宝公钥
,后续在生成二维码的时候会用到:
3.4、沙箱账号
默认情况下,进入沙箱控制台,沙箱账号是已经创建好的,包括商家账号信息和买家账号信息,使用C扫B的模式,就是买家向卖家扫码付款,沙箱账号中的金额会同步更新。
4、生成二维码技术
ZXing是一个开源的,用Java编写的多格式的1D / 2D条码图像处理库,使用ZXing可以生成、识别QR Code(二维码)。常用的二维码处理库还有zbar,但是zbar近几年已经不再更新代码,下边介绍ZXing生成二维码的方法。
1、项目工程中引入依赖:
<!--二维码生成&识别组件-->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
2、编写生成二维码的工具类:
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.cloudflashpay.common.domain.BusinessException;
import com.cloudflashpay.common.domain.CommonErrorCode;
import org.apache.commons.lang3.StringUtils;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.HashMap;
/**
* <P>
* 二维码工具类
* </p>
*/
public class QRCodeUtil {
/**
* 生成二维码
* @param content 扫码后要调用的链接地址
* @param width 二维码宽度
* @param height 二维码高度
* @return
*/
public String createQRCode(String content, int width, int height) throws IOException {
String resultImage = "";
//除了尺寸,传入内容不能为空
if (!StringUtils.isEmpty(content)) {
ServletOutputStream stream = null;
ByteArrayOutputStream os = new ByteArrayOutputStream();
//二维码参数
@SuppressWarnings("rawtypes")
HashMap<EncodeHintType, Comparable> hints = new HashMap<>();
//指定字符编码为“utf-8”
hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
//L M Q H四个纠错等级从低到高,指定二维码的纠错等级为M
//纠错级别越高,可以修正的错误就越多,需要的纠错码的数量也变多,相应的二维吗可储存的数据就会减少
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
//设置图片的边距
hints.put(EncodeHintType.MARGIN, 1);
try {
//zxing生成二维码核心类
QRCodeWriter writer = new QRCodeWriter();
//把输入文本按照指定规则转成二维吗
BitMatrix bitMatrix = writer.encode(content, BarcodeFormat.QR_CODE, width, height, hints);
//生成二维码图片流
BufferedImage bufferedImage = MatrixToImageWriter.toBufferedImage(bitMatrix);
//输出流
ImageIO.write(bufferedImage, "png", os);
/**
* 原生转码前面没有 data:image/png;base64 这些字段,返回给前端是无法被解析,所以加上前缀
*/
resultImage = new String("data:image/png;base64," + EncryptUtil.encodeBase64(os.toByteArray()));
return resultImage;
} catch (Exception e) {
e.printStackTrace();
//自己编写的异常处理类,也可以使用java自带的异常处理
throw new BusinessException(CommonErrorCode.E_200007);
} finally {
if (stream != null) {
stream.flush();
stream.close();
}
}
}
return null;
}
}
3、测试根据内容生成二维码方法,在QRCodeUtil中添加main方法如下
public static void main(String[] args) throws IOException {
QRCodeUtil qrCodeUtil = new QRCodeUtil();
//http://www.baidu.com地址可根据你个人的个人的请求地址,测试使用百度地址
String qrCode = qrCodeUtil.createQRCode("http://www.baidu.com", 200, 200);
System.out.println(qrCode);
}
运行main方法,将输出的内容复制到浏览器地址后回车
data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAADIAQAAAACFI5MzAAAByklEQVR42u2YQW6DMBBFB
7HwkiP4JuViSLbExeAmPgJLFojp/8ZJ2khd5reqkgXCfixGM//P2DH/6Wdv8tdJNrNhLljMHk7rC9a9lMzu5zD7/jEc
cR+3dH0jJcWwaTsiwubWlx2h6kmO2EwlnIP/EnHmJJsvqJSesD5HtA6JYaWeKicgTaNQSHs8q/flpP6QGN/MAor05GA
BmUtYLNGiU9yrY9etlxJ3uHOyvfMcw8oAl6YQFcl4hUVBINTTrGpFTapMRodQ6Zew3vu1hlRj1rB6tsyM2MQEVSFGk0
C/7mjRlUIVEm4iLGbHENYR8Y1LCdOBVn2NqxVLJktKDkNp4FO/EtOzYYkJJUGZGEc2o7y5REWQDs5tapQy4RnCkpRAE
tUqI9oUXQLHblpSJxXWHxBqqK16MTFxjiukiJ2iFml5nBwkxOlTkG6bIhIDx94UoiIHJhVHJ61SDXLv1yrCTaZjZa+i
TNC1tKSdXSCOVGp2kKckJdf5jbHxjRN8/Habej1pdxm4ZLLWKYZZS667DFpm5oXG6NikJ4wNj8CZVUOVEx6h6M6Tb4+
JLiJcO6fmYVfXGr/ecgSk3WUCT094nWL9UEne/+L8M/IJ4hgO+SLk4asAAAAASUVORK5CYII=
这是经过base64加密后的字节文件,将这一串地址复制到浏览器打开:
使用手机扫描二维码,即可自动打开百度官网。
5、手机网站支付接口
支付宝手机网站支付接入方法,官方指导文档详见:https://opendocs.alipay.com/open/203/
5.1、场景介绍
支付宝手机网站支付适用于商家在移动端网页应用中集成支付宝支付功能。
商家在网页应用中调用支付宝提供的网页支付接口
,接口会调起支付宝客户端内的支付模块
,此时会从商家网页应用
跳转到支付宝客户端中
并开始支付;支付完成后会跳转回商家网页应用内,最后商家展示支付结果。
- 1:用户在浏览器中访问商家网页应用,选择商品下单、确认购买,进入支付环节,选择支付宝付款,用户点击去支付,如下图1;
- 2:进入到支付宝支付路由页面,支付宝处理支付请求,并尝试唤起支付宝客户端,如下图2;
- 3:进入到支付宝页面,调起支付宝客户端支付,出现确认支付界面,如下图3;
- 4:用户确认收款方和金额,点击立即支付后出现输入密码界面,如下图 4;
- 5:输入正确密码后,支付宝端显示支付结果,如下图 5;
- 6:自动回跳到浏览器中,商家根据付款结果个性化展示订单处理结果,如下图 6。
注意:在 iOS 系统中,唤起支付宝 App 支付完成后,不会自动回到浏览器或商户 App。用户可手工切回到浏览器或商户 App。
5.2、接口交互流程图
手机网站支付,服务端接入接口官方文档:https://opendocs.alipay.com/open/203/105285/
上述流程图中最关键的点在于
1.2
和1.3
请求的过程。
其实我们上述生成的二维码就是在商户系统中生成的,可以简单理解成,用户在商户系统中选中商品下单,生成二维码,用户用支付宝扫描二维码,这个过程会将商品主要信息,订单号、商品名称和商品价格等参数携带并构造一个新的请求到支付宝系统,请求支付,支付宝系统校验商户请求所携带的参数(包括签名和签名类型),是否正确,如果正确就将支付信息返回给用户,用户输入支付密码,支付宝完成支付将支付结果再次响应给用户,用户展示订单信息。
详细过程如下:
- 1、用户在商户的H5网站下单支付后,商户系统按照手机网站支付接口alipay.trade.wap.payAPI 的参数规范生成订单数据。
- 2、前端页面通过Form表单的形式请求到支付宝。此时支付宝会自动将页面跳转至支付宝H5收银台页面,如果用户手机上安装了支付宝APP,则自动唤起支付宝APP;如果未安装,则需要先下载安装。
- 3、输入支付密码完成支付。
- 4、用户在支付宝APP或H5收银台完成支付后,会根据商户在手机网站支付API中传入的前台回跳地址return_url自动跳转回商户页面,同时在URL请求中以Query String的形式附带上支付结果参数,详细回跳参数见“手机网站支付接口alipay.trade.wap.pay”前台回跳参数。
- 5、支付宝还会根据原始支付API中传入的异步通知地址notify_url,通过POST请求的形式将支付结果作为参数通知到商户系统,详情见支付结果异步通知。
5.3、下单接口定义
接口定义:外部商户请求支付宝创建订单并支付
环境 | HTTPS请求地址 |
---|---|
正式环境 | https://openapi.alipay.com/gateway.do |
沙箱环境(dev) | https://openapi.alipaydev.com/gateway.do |
所有的请求参数,参考官方文档: https://opendocs.alipay.com/open/203/107090#%E5%85%AC%E5%85%B1%E5%8F%82%E6%95%B0
说明:下述标记蓝色
的由支付宝 sdk(开发工具包)内部设置、标记红色
的是在支付渠道参数中配置,标记绿色
的是需程序来设置的。
1、公共请求参数:
2、业务请求参数:
3、功能响应参数:
4、响应参数:
5.4、下单接口实现
使用支付宝提供sdk(开发工具包)调用支付宝的接口。
sdk是一个方便调用支付宝接口的开发工具包,提供方便接口调用的api方法。
下图展现sdk所在的位置,闪聚平台微服务需要引入sdk依赖(jar包),即可使用sdk的api。
5.4.1、环境准备
1、在交易服务项目中,引入支付宝的sdk开发工具包:
<!--支付宝SDK-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
</dependency>
<!--支付宝SDK依赖的日志-->
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
</dependency>
2、必要参数
如下参数是支付宝接口交互中的必要参数:appId
、应用私钥
、支付宝公钥
//沙箱应用id
String APP_ID= "202100011922222222";
//应用私钥(支付宝开发助手生成的应用私钥)
String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCC2WVbFQds9PXn0Fx60q/gZcSRPO23LdWdKdGRM59OAysCSV6Iggfn0oGTs5dhr2cUHeGrFzBs2hdsJjWxKCvniWA9RTuQlKIOFnZgxdvMQWajzhy46QQyvAMus9IIirecRWtUsLGEsTjeHPj+Lmzyf8qUvHeKiJNyQC7oJiNDOE/HK7YkVY7YJmT9mtHMU/n/NuS2bfQkcvzJVI1CUuWGIluFHLI3Rvw4o2R/nBjdsPRRoZDNRNugPxmM3E2lAytHNt7C8fGjl5VwEs1RnEWqLT+RfkB4Z12wp+4MgT6nlv96bpDfj5BShn3BPIVj/tKQTAg7R1ESWo2FK0/ITb5DAgMBAAECggEAefBCRjk4rE80Ao3oQQWqpUHxhy/yj+yEz2uzQs+Ku9az8/OPx0L2PxGrc4u/nWcqdlLKhPidRjOP9Fc/XhMDp0gcibzFH52D0AEa3GBGzvh7wFdJ6QAty2HuzU0ChLdRGK6QsWHgbLoDNuplF+sH2I1Cqo1gEZfpYGVz0SAJaI/kmaNGdi+VyxEm93s6F479LBMS/t55LLxB/xuViq1mq7I+u/ZUmABjVS+k4m2B6nmOt55MFf7RjMSmnu0vENt5tjEpABa88xR5C1qK4ikqYeJytLHGYuwmeN6sL5weM+LEo2nEJ0TYYvjW45lDBfWdZd4F7hGF69bA45jnKV0zcQKBgQDzgBB35xRN9PUkv80hYcjNu5Qj3NOLaiSpMfgkGuPXQC+dQ9nP1zocfn+q6wxhZ76ZLCcSxsjnmM4DK1ckSke8gKstzedgL5wJxB+E1+Ky33Hfn/VqMBjhY/XnwyHSykOOHcH2aS+/1mvDD+vzvV27EfqulDArBojoM7IJD0jX9QKBgQCJkPA8jFE9jnvcp2PV2B3rRcoKjlT8rdeoghG4sYTlnBlp1aHhlfWBEKJSB6MOL434QJxjGNb7EHpjFM4/N8Nk+hc79HsPGAuw9hGN2j3GfLa2EYXoIKSgT1KtWw1B9wZl+g09OkmELlYGVUQIiY/RCMDQpyJ3UPg/aOObRFSyVwKBgQDmezSbWcX1WETmCQqQa29XlRLOs0olb03OPPckrbM13pJzKHM18QIXUIFldeCdHkbh01IUysYFubReeZqdRhYKzju5OmmkuMvYzqQK6RGywB+YTV9NqMMULLrpKeGNFVjGX1Jl/ABvc/VCiIKNjpP26zi+IJRLVX8nUy9Utfv8NQKBgQCHAvjEc/JHt89Yf/A7sB+tCJGCSq6eTv+ZIg7CdXc44jsO49w8yjBouyqT12rwQTvUqZTSrU5QmZuEIqdI5DGgqNKkxQ0Bg1f2FYqk7cwzQbMQfaIub9sierdp7DLWyto8u2zC6rG8SL2k+YoL1vaO8UhLf70T3SPHF+pKOIXngQKBgCJQ45121smzN/Lad1QsPY4XEqK++hiVpwpXQpyUyfiHf5S+ixKT0kW/fPFjeWLr3PLMUe0lYd4Izh2/hSGPjQwIBEzAVT/7dQjGzbkUMTISC3o87neBJ38YHzBXCikvLgFGSY85Jb9jcVbnkAFMEQhbjrPaAc/wllxuWHH7Ilf";
//支付宝公钥(支付宝开放平台中配置生成的支付宝公钥)
String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvLzWaU4LQrb6yzLadxz2Fc0FH7PYA3XudMPeyVrGyKs7Evo6CwOZb2KwRgxHaY94Axc8AuSK9JVYWRC2Lj9QenCLxwQ1xyk5xsALxESqIrg4IMumGhiA1Onrjo0Mh9YNuzahP350lisX2hNiAaEm3+4U89PJmjXUwxqD/TgFuI/21VkBshc6TVtNRlO9NAH4aa3JyIBYSKq/L1ZdR5OY41VWm3noTmwEfEFow3ROEvnMReHDdDRtz9RWk+KzZBw4OrtfYYiUtpqNCSG2o8sHMMrwRmAo9WCa7gLnTkPggyvaPqe+/xm46jCBxlOv3F+qewwG2rwvivtuVGk6OMDpwIDAQAB";
//字符集编码
String CHARSET = "UTF-8";
//沙箱测试地址中间带dev标志,正式地址:https://openapi.alipay.com/gateway.do
String serverUrl = "https://openapi.alipaydev.com/gateway.do";
//数据格式
String format = "json";
//签名算法类型,如果不指定默认会使用RSA类型(不推荐)
String sign_type = "RSA2";
5.4.2、编写controller层下单接口
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradeWapPayRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Controller
@Slf4j
public class PayTestController {
//应用id
String APP_ID= "202100011922222222";
//应用私钥
String APP_PRIVATE_KEY = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCC2WVbFQds9PXn0Fx60q/gZcSRPO23LdWdKdGRM59OAysCSV6Iggfn0oGTs5dhr2cUHeGrFzBs2hdsJjWxKCvniWA9RTuQlKIOFnZgxdvMQWajzhy46QQyvAMus9IIirecRWtUsLGEsTjeHPj+Lmzyf8qUvHeKiJNyQC7oJiNDOE/HK7YkVY7YJmT9mtHMU/n/NuS2bfQkcvzJVI1CUuWGIluFHLI3Rvw4o2R/nBjdsPRRoZDNRNugPxmM3E2lAytHNt7C8fGjl5VwEs1RnEWqLT+RfkB4Z12wp+4MgT6nlv96bpDfj5BShn3BPIVj/tKQTAg7R1ESWo2FK0/ITb5DAgMBAAECggEAefBCRjk4rE80Ao3oQQWqpUHxhy/yj+yEz2uzQs+Ku9az8/OPx0L2PxGrc4u/nWcqdlLKhPidRjOP9Fc/XhMDp0gcibzFH52D0AEa3GBGzvh7wFdJ6QAty2HuzU0ChLdRGK6QsWHgbLoDNuplF+sH2I1Cqo1gEZfpYGVz0SAJaI/kmaNGdi+VyxEm93s6F479LBMS/t55LLxB/xuViq1mq7I+u/ZUmABjVS+k4m2B6nmOt55MFf7RjMSmnu0vENt5tjEpABa88xR5C1qK4ikqYeJytLHGYuwmeN6sL5weM+LEo2nEJ0TYYvjW45lDBfWdZd4F7hGF69bA45jnKV0zcQKBgQDzgBB35xRN9PUkv80hYcjNu5Qj3NOLaiSpMfgkGuPXQC+dQ9nP1zocfn+q6wxhZ76ZLCcSxsjnmM4DK1ckSke8gKstzedgL5wJxB+E1+Ky33Hfn/VqMBjhY/XnwyHSykOOHcH2aS+/1mvDD+vzvV27EfqulDArBojoM7IJD0jX9QKBgQCJkPA8jFE9jnvcp2PV2B3rRcoKjlT8rdeoghG4sYTlnBlp1aHhlfWBEKJSB6MOL434QJxjGNb7EHpjFM4/N8Nk+hc79HsPGAuw9hGN2j3GfLa2EYXoIKSgT1KtWw1B9wZl+g09OkmELlYGVUQIi/RCMDQpyJ3UPg/aOObRFSyVwKBgQDmezSbWcX1WETmCQqQa29XlRLOs0olb03OPPckrbM13pJzKHM18QIXUIFldeCdHkbh01IUysYFubReeZqdRhYKzju5OmmkuMvYzqQK6RGywB+YTV9NqMMULLrpKeGNFVjGX1Jl/ABvc/VCiIKNjpP26zi+IJRLVX8nUy9Utfv8NQKBgQCHAvjEc/JHt89Yf/A7sB+tCJGCSq6eTv+ZIg7CdXc44jsO49w8yjBouyqT12rwQTvUqZTSrU5QmZuEIqdI5DGgqNKkxQ0Bg1f2FYqk7cwzQbMQfaIub9sierdp7DLWyto8u2zC6rG8SL2k+YoL1vaO8UhLf70T3SPHF+pKOIXngQKBgCJQ45121smzN/Lad1QsPY4XEqK++hiVpwpXQpyUyfiHf5S+ixKT0kW/fPFjeWLr3PLMUe0lYd4Izh2/hSGPjQwIBEzAVT/7dQjGzb4kUMTISC3o87neBJ38YHzBXCikvLgFGSY85Jb9jcVbnkAFMEQhbjrPaAc/wllxuWHH7Ilf";
//支付宝公钥
String ALIPAY_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvLzWaU4LQrb6yzLadxz2Fc0FH7PYA3XudMPeyVrGyKs7Evo6CwOZb2KwRgxHayY94Axc8AuSK9JVYWRC2Lj9QenCLxwQ1xyk5xsALxESqIrg4IMumGhiA1Onrjo0Mh9YNuzahP350lisX2hNiEm3+4U89PJmjXUwxqD/TgFuI/21VkBshc6TVtNRlO9NAH4aa3JyIBYSKq/L1ZdR5OY41VWm3noTmwEfEFow3ROEvnMReHDdDRtz9RWk+KzZBw4OrtfYYiUtpqNCSG2o8sHMMrwRmAo9WCa7gLnTkPggyvaPqe+/xm46jCBxlOv3F+qewwG2rwvivtuVGk6OMDpwIDAQAB";
//字符集编码
String CHARSET = "UTF-8";
//沙箱支付宝网关地址,正式网关地址:https://openapi.alipay.com/gateway.do
String serverUrl = "https://openapi.alipaydev.com/gateway.do";
//数据格式
String format = "json";
//签名算法类型
String sign_type = "RSA2";
@GetMapping("/alipaytest")
public void alipaytest(HttpServletRequest httpRequest,
HttpServletResponse httpResponse) throws ServletException, IOException {
//构造sdk的客户端对象
AlipayClient alipayClient = new DefaultAlipayClient(serverUrl, APP_ID, APP_PRIVATE_KEY, format, CHARSET, ALIPAY_PUBLIC_KEY, sign_type); //获得初始化的AlipayClient
//创建API对应的request
AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();
//在公共参数中设置回跳和通知地址,可以暂时为空
alipayRequest.setReturnUrl("");
alipayRequest.setNotifyUrl("");
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", "20210817010101004");
bizContent.put("total_amount", 88.88);
bizContent.put("subject", "华为p100");
bizContent.put("product_code", "QUICK_WAP_WAY");
//填充业务参数,因为需要json格式的数据,所以使用JSON对象填充
alipayRequest.setBizContent(bizContent.toJSONString());
//当然也可以直接使用json数据格式的字符串
/*alipayRequest.setBizContent("{" +
" \"out_trade_no\":\"20210817010101004\"," +
" \"total_amount\":\"88.88\"," +
" \"subject\":\"华为p100\"," +
" \"product_code\":\"QUICK_WAP_PAY\"" +
" }");*/
String form = "";
try {
//请求支付宝下单接口,发起http请求
form = alipayClient.pageExecute(alipayRequest).getBody(); //调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
log.info("异常错误:{}",e.getMessage());
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
httpResponse.getWriter().write(form);//直接将完整的表单html输出到页面
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
}
特别注意:
因为我们是在自己的本机电脑上开发的环境,地址可以直接写成localhost
或者127.0.0.1
,但是后续我们使用模拟器的时候他是不同的系统,所以是不能通过localhost
或者127.0.0.1
来访问请求的,我们需要使用局域网ip地址来请求访问。
打开cmd窗口,输入
ipconfig -all
使用局域网的ipv4地址即可。或者是vm虚拟机的ipv4地址也可以。
所以上述的下单接口在我的工程中是:http://192.168.0.105:56050/transaction/alipaytest
,将此url放到二维码生成工具类中,只需修改修改url即可:
public static void main(String[] args) throws IOException {
QRCodeUtil qrCodeUtil = new QRCodeUtil();
String qrCode = qrCodeUtil.createQRCode("http://192.168.0.105:56050/transaction/alipaytest", 200, 200);
System.out.println(qrCode);
}
再次运行main方法,将控制台输出内容,复制到浏览器中打开:
6、模拟器测试环境准备
我们对接的是支付宝支付接口,在测试支付宝下单接口时需要使用支付宝扫描二维码,需要安装 支付宝客户端(沙箱版本)
,用沙箱账号登录沙箱版支付宝,扫二维码,二维码的地址即为下单接口的地址。
沙箱版本的支付宝可以有很多种的安装方式,我原本是跟着教程走的,使用的是电脑端的模拟器,下面罗列出常用的模拟器,根据我的踩坑经验,这点我先提前说一下,如果你的CPU是AMD锐龙版的,MuMu模拟器(网易开发)是无法安装的,原因是AMD兼容问题。而雷电、天天和夜神模拟器都可以安装,但是打开模拟器之后安装了沙箱版支付宝无法正常运行,刚打开就闪退,即使是进去了,随便一操作也会闪退,而且这几个模拟器要求电脑配置比较高,就是比较吃内存,并且不是很稳定,可能是我个人电脑的原因。
但是不管怎么说,最终还是让我找到了一个比较完美的模拟器,就是下述高亮的逍遥模拟器
,要求配置比较低,一般的电脑基本都可以,运行流畅,可以同时高开5个系统,很满足。
- 电脑端安装模拟器(常见模拟器如下:)
- MuMu模拟器:https://mumu.163.com/
- 雷电模拟器:https://www.ldmnq.com/
- 天天模拟器:https://www.ttmnq.com/
逍遥模拟器
:http://www.xyaz.cn/- 夜神模拟器:https://www.yeshen.com/
6.1、安装模拟器
在官网下载安装包,直接解压安装即可。
初始化只有一些系统默认的应用,我们需要下载沙箱版支付宝安卓apk安装包,推荐直接再绿色资源网下载即可http://m.downcc.com/d/320904
下载好安装包之后,点击模拟器右上角的安装apk:
直接在本地找到上述下载好的安装包位置,直接安装即可。
登录支付宝开放平台,点击左侧菜单沙箱账号:
获取登录账号和密码,登录成功后如下:
6.2、测试下单扫描二维码
此时我们启动交易服务项目,上述我们生成的二维码地址不用重新修改,因为地址请求的地址没有变。
然后打开模拟器中的浏览器,将二维码地址粘贴到地址栏回车:
点击截图保存,因为在电脑上很多是没有摄像头权限,即使有权限,也没有后置摄像头,扫描二维码比较麻烦,所以将二维码截图保存在模拟器的相册文件夹中。
打开支付宝扫一扫,点击右上角的相册,选择保存的截图:
点击立即付款,默认支付密码为111111。
此处注意:
模拟器网络不是很稳定,如果你点击立即支付后,出现了支付异常,再次点击支付的时候,会提示你“订单已付款成功,请勿重复提交。”因为第一次支付之后,即使是支付异常,但是这个订单已经是存在了,在商户系统
中的商品订单id
和支付宝系统
中的支付id
是一一对应的关系,所以不可以重复提交支付。
还可以在支付宝的账单中查看交易信息:
至此Springboot接入支付宝沙箱测试就完成了!!!
7、模拟器扩展
其实上述我也说了,使用模拟器有很多方法,如果觉得上述在电脑上使用不是很方便,而且不能真正体会到拿手机支付的感觉,其实博主就是觉得上述的操作太麻烦了,还要每次截图,所以我就是试着在手机上也安装一个沙箱环境,结果还真的有。x8沙箱官网https://x8sb.com/,手机应用商店也可以直接下载安装,安装完成后,同样将我们下载好的apk传到手机上,在x8沙箱里找到手机本地的支付宝沙箱版本的apk安装包安装即可。
此时只需要你的手机和电脑是在同一个局域网内,登录沙箱账号,就可以直接扫描上述生成的二维码。
就这样拿着手机就尅扫了,是不是很爽!!!
如果想更爽,还有一个方法(先狗头保命),沙箱版支付宝,是apk的,那既然是apk,安卓手机肯定也可以安装吧,没毛病就是这个理,我就试着直接在手机上安装了,安装完成后,同样是登录账号。
卧槽!!!居然也可以,效果和上述一毛一样,兄弟们不要怪我,我也是最后才知道的,乃乃嘞腿,早知道就不用在电脑上那么麻烦导出找合适的模拟器了,而且体验感还很差。
一起学编程,让生活更随和!如果你觉得是个同道中人,欢迎关注博主公众号:【随和的皮蛋桑】。专注于Java基础、进阶、面试以及计算机基础知识分享🐳。偶尔认知思考、日常水文🐌。