文章目录
1. 前言
很多人或者很多业务都有接入支付宝支付或者微信支付的需要,但接入第三方支付(alipay、wxpay)一直都需要公司资质或者个体户等,使得个人开发者只能望而却步。
最近了解到支付宝有一个支付能力【当面付】竟然支持个人接入,激动得我不得不写一篇博客好好介绍一下(太懒了,有大半年没有写博客了),这款支付产品可以支持实现【电脑端的web支付】和【手机端的h5支付】,简直顶到爆炸,博客下面有体验地址~
别着急,看完这篇博客,相信你都不用看官方文档就可以完成对接,我也会提供对接的核心代码出来作为参考。(Java对接支付宝当面付)
2. 当面付产品介绍
2.1 场景描述2种场景
当面付帮助商家在线下消费场景中实现快速收款,支持 【扫码支付】 和 【条码支付】 两种付款方式。商家可通过以下两种任一方式进行收款,提升收银效率,实现资金实时到账。
- 扫码支付:买家通过使用支付宝 扫一扫 功能,扫描商家收款二维码即可完成 扫码支付 付款。(用户扫商家的收款码)
- 条码支付:买家出示支付宝钱包中的条码、二维码,商家扫描用户条码即可完成 条码支付 收款。(商家扫用户的付款码)
如果上面的文字不够清晰明细,那就来看下面的图片吧,简单明了
2.2 申请条件
1. 支持的账户类型:经过实名认证的个人/企业支付宝账号
2. 签约申请提交资料:
1) 经营场所照片
a. 有店铺门头的经营场所,需提供门头照;
b. 无店铺门头的经营场所,需提供内景照或场景照
2)个人账户需提供经实名认证的支付宝账号持有人本人的营业执照(即营业执照的法人代表与支付宝账号持有人相同)
2.3 费率
服务名称 | 费率 | 服务期限 |
---|---|---|
单笔费率 | 0.6% | 1年 |
2.4 产品签约管理
账户类型 | 收款额度规则 | 入驻资质要求(页面需要填写) | 使用时间 |
---|---|---|---|
个人账户 | 单笔收款 ≤ 500元,单日收款 ≤ 5000元,不区分借记或贷记渠道。 | 1、需按规范提交经营场景照片(如门头照、门店地址);2、提供本人同名营业执照。 | 30天。如提交资料均不通过,商家需要在合约生效后的30天内补全门头照等资料,否则会影响正常收款。温馨提示:当使用时间到期(从合约生效开始计算 30天)系统会在到期前 15 天和 3 天发出代办通知,30 天到期,为了更好的产品使用体验,建议您及时补全资质)。 |
个人账户 | 收款不受限额。 | 1、需按规范提交经营场景照片(如门头照、门店地址);2、提供本人同名营业执照。 | 若提交资料均通过,收款不受限。 |
企业账户 | 收款不受限额。 | 无 | 无 |
3. 实现的效果
3.1 基于当面付 - 扫码支付 实现的【电脑端web】支付
电脑点击下方链接可以立即体验测试
https://fb.ihouyu.cn/alipay/web/index.html
- 支付流程如下图
3.2 基于当面付 - 扫码支付 实现的【手机端h5】支付
支付宝扫一扫 可以立即体验测试(或者手机系统浏览器扫,不要使用微信扫,因为微信浏览器会限制支付宝功能)
- 支付流程如下图
4. 开通支付宝当面付
- 开通 当面付(点击下方链接开通)
https://b.alipay.com/signing/productDetailV2.htm?productId=I1011000290000001003
- 填写相关资料
- 经营类目 选择 “百货零售 / 其他零售 / 杂货店”,或者其他…问题不大
- 营业执照 可不上传
- 店铺招牌 可以拍一下身份的百货店,或者百度找一张类似的图
- 等待审核(工作日的话大概30分钟,非工作日就不好说了)
5. 创建应用并且添加支付能力
可以参考官方文档:(或者按照我的步骤下面步骤)
https://opendocs.alipay.com/open/200/105310
5.1 创建应用(点击链接进入)
https://open.alipay.com/platform/developerIndex.htm
5.2 填写相关应用资料
- 应用名称
- 应用图标
5.3 应用 添加能力
5.4 应用 开发设置
- 设置 接口加签方式,手机收到验证码填写
- 下载 支付宝开放平台开发助手即密钥生成工具 https://opendocs.alipay.com/open/291/introduce
- 上传刚才生成的应用公钥
- 点击保存上传的应用公钥之后,会弹窗给出支付宝的公钥
- 设置应用网关等
5.5 应用 提交审核
6. Java对接支付宝当面付
6.1 官方文档
https://opendocs.alipay.com/open/194/106078
6.2 引入相关依赖
- gradle依赖方式
compile group: 'com.alipay.sdk', name: 'alipay-sdk-java', version: '4.10.170.ALL'
- maven依赖方式
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.10.170.ALL</version>
</dependency>
6.3 当面付-预下单
/** 创建的应用ID */
@Value("${fastboot.pay.alipay.app-id}")
private String appId;
/** 自己生成的应用私钥 */
@Value("${fastboot.pay.alipay.private-key}")
private String privateKey;
/** 支付宝提供的支付宝公钥 */
@Value("${fastboot.pay.alipay.alipay-public-key}")
private String alipayPublicKey;
/** 回调地址,需要公网且链接不需要重定向的,如:https://fastboot.shaines.cn/api/myalipay/trade-notify */
@Value("${fastboot.pay.alipay.notify-url}")
private String notifyUrl;
@RequestMapping("/trade-precreate")
@ApiOperation("当面付预下订单")
@ResponseBody
public Result<AlipayTradePrecreateResponseDTO> tradePrecreate(AlipayTradePrecreateRequestDTO requestDTO) {
AssertUtils.notEmpty(requestDTO.getSubject(), "标题不可以为空");
AssertUtils.notEmpty(requestDTO.getTotalAmount(), "金额不可以为空");
AssertUtils.check(requestDTO.getSubject().length() > 50, "标题不可以超过50字");
AssertUtils.check(requestDTO.getTotalAmount().compareTo(new BigDecimal("0")) <= 0, "金额需要大于0元");
AssertUtils.check(requestDTO.getTotalAmount().compareTo(new BigDecimal(50)) >= 0, "金额不可以超过50元");
// 金额保留两位小数
requestDTO.setTotalAmount(requestDTO.getTotalAmount().setScale(2, BigDecimal.ROUND_HALF_UP));
// 创建 AlipayClient
AlipayClient alipayClient = new DefaultAlipayClient(
"https://openapi.alipay.com/gateway.do",
appId,
privateKey,
"json",
"UTF-8",
alipayPublicKey,
"RSA2");
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
// String outTradeNo = UUID.randomUUID().toString().replace("-", "");
String orderNo = IDUtil.generate().toString();
request.setBizContent(String.format("{\n"
+ " \"out_trade_no\": \"%s\", \n"
+ " \"total_amount\": \"%s\", \n"
+ " \"subject\": \"%s\", \n"
+ " \"store_id\": \"JM01\", \n"
+ " \"qr_code_timeout_express\": \"30m\"\n"
+ "}",
orderNo,
requestDTO.getTotalAmount(),
requestDTO.getSubject()));
request.setNotifyUrl(notifyUrl);
AlipayTradePrecreateResponse response;
try {
response = alipayClient.execute(request);
} catch (AlipayApiException e) {
throw new BusinessException(String.format("下单失败 错误代码:[%s], 错误信息:[%s]", e.getErrCode(), e.getErrMsg()));
}
log.info("AlipayTradePrecreateResponse = {}", response.getBody());
/*
{
"code": "10000",
"msg": "Success",
"out_trade_no": "815259610498863104",
"qr_code": "https://qr.alipay.com/bax09455sq1umiufbxf4503e"
}
*/
if (!response.isSuccess()) {
throw new BusinessException(String.format("下单失败 错误代码:[%s], 错误信息:[%s]", response.getCode(), response.getMsg()));
}
// TODO 下单记录保存入库
//
// 返回结果,主要是返回 qr_code,前端根据 qr_code 进行重定向或者生成二维码引导用户支付
AlipayTradePrecreateResponseDTO responseDTO = new AlipayTradePrecreateResponseDTO();
responseDTO.setOrderNo(orderNo);
responseDTO.setQrCode(response.getQrCode());
return new Result<>(responseDTO);
}
6.4 支付宝官方支付回调(扫码支付)
@RequestMapping("/trade-notify")
@ResponseBody
public String tradeNotify(HttpServletRequest request) {
Map<String, String[]> parameterMap = request.getParameterMap();
Map<String, String> params = new HashMap<>(32);
parameterMap.forEach((key, val) -> params.put(key, String.join(",", val)));
/*
{
"gmt_create": "2021-02-24 09:12:57",
"charset": "UTF-8",
"seller_email": "272694308@qq.com",
"subject": "测试",
"sign": "XyrF+MU+zPIAVKdBGcrpgwpYYaG3uAqk7Y34LDQJ+BHXyBTfRvkq8wEm6MOz2np4GoJ1pkoV1ZzZGKdhoTHrxFAxk2hFvTXs9UoBpyrzV/kuLmC436IHWOe2koTWqTZCWhm+6w3NJWCNwq+nmUjzvLvmQWgSruBBJ/ZLR3cWGwMQleoj1clkc7smVdBKiFpY1oxc8nCOSIgKsyxZZ3Iza0rJKYResR7BRNFhmSI7sOYQyQEr0c8LPTPnyhAWVypQcAhHEkpZIyMbRjG9ayOdhtmI3VLh7Kh5AD9c1/VVT1grHrcucXhkhwBvJndQPDmXxcl/nSwhuSlMttAd9HPL2A==",
"buyer_id": "2088112022569596",
"invoice_amount": "0.01",
"notify_id": "2021022400222091303069591445812598",
"fund_bill_list": "[{\"amount\":\"0.01\",\"fundChannel\":\"ALIPAYACCOUNT\"}]",
"notify_type": "trade_status_sync",
"trade_status": "TRADE_SUCCESS",
"receipt_amount": "0.01",
"app_id": "2021002107650269",
"buyer_pay_amount": "0.01",
"sign_type": "RSA2",
"seller_id": "2088122717972675",
"gmt_payment": "2021-02-24 09:13:03",
"notify_time": "2021-02-24 09:13:03",
"version": "1.0",
"out_trade_no": "def55f2d4076451c948eba010dfc1255",
"total_amount": "0.01",
"trade_no": "2021022422001469591437625740",
"auth_app_id": "2021002107650269",
"buyer_logon_id": "143***@qq.com",
"point_amount": "0.00"
}
*/
log.info("============>>> /trade-notifyparams:{}", JSON.toJSONString(params));
//
boolean check;
try {
// 必须要验签
check = AlipaySignature.rsaCheckV1(params, alipayPublicKey, "UTF-8", "RSA2");
log.info("============>>> check: [{}]", check);
} catch (Exception e) {
log.warn("tradeNotify exception", e);
return "failure";
}
if (!check) {
return "rsaCheckV1 = false";
}
// TODO 修改下单的订单信息为已支付
//
return "success";
}
7. 结束语
好了,来到这里基本完成对接了,如果还需要对接退款或者其他的业务,请浏览更多官方文档实现或者给我留言,如果本文有记录不对或者笔误,还劳烦指出修正以免误导他人,感谢!
如果本文有帮助到你,你也可以 点击链接 或者 支付宝扫一扫二维码 给我一点小反馈~
电脑点击下方链接测试
https://fb.ihouyu.cn/alipay/web/index.html
支付宝扫一扫 即可测试(或者系统浏览器扫,不要使用微信扫,因为微信浏览器会限制支付宝功能)
- 公众号:IT加载中(it_loading)
- CSDN:https://blog.csdn.net/JinglongSource
- 博客:https://ihouyu.cn/
- 邮箱:for.houyu@qq.com
程序员[ 后宇 ],是一个关注编程,热爱技术的Java后端开发者,热衷于 [ Java后端 ],[ 数据爬虫领域 ]。不定期分享 I T 技能和干货!!欢迎关注 “IT加载中”,一个只出 干货 和 实战 的公众号。