一、 订单支付数据库
1.1 订单支付数据库
订单支付的数据库:订单表,交易订单表,交易渠道,退款记录,签约合同表。
数据库如下:

1.2 防止订单多次支付
订单在进行支付过程中可能会发生失败,会记录每一次支付情况;这样查询就有所依据,用户在什么时间支付,支付结果如何。
//用户有可能会多次点击而导致创建多个支付订单,而支付多次的情况,所以需要对当前需要支付的订单进行加 分布式锁;
实现步骤:
//1 获取当前要创建支付订单的订单编号。
//2 获取分布式锁对象。
//3 对订单编号添加分布式锁。
//4 进行统一下单操作,创建交易订单并返回交易订单信息。
//5 释放分布式锁。否则会出现 出现死锁,无法创建交易订单,进行订单处理。
分布式锁原理:
在并发竞争共享资源的时候,想要对资源正确处理。如果不加分布式锁会出现 超卖 现象。
应用场景:
商品下单扣减库存、消息队列(避免重复处理)、此项目中避免重复支付、优惠券。
Redis分布式锁的实现主要依赖于Redis的SETNX(SET IF NOT EXISTS)命令和过期时间(EXPIRE)机制,或者通过SET命令的扩展参数(SET EX PX NX)来实现。
1.3 退款流程
- 1.生成退款请求:通过微信支付提供的退款接口,构造退款请求。请求中需包含商户号、商户订单号、微信支付订单号、退款金额、退款原因等必要参数。
- 2.加密签名:使用商户API密钥对退款请求参数进行签名。
- 3.发送退款请求:将加密签名后的退款请求通过OkHttp以 POST方式发送给微信支付服务器。
- 4.微信支付处理:微信支付平台进行退款操作,并更新订单状态。
- 5.接收退款结果通知:退款操作完成后,微信支付会通过商户设置的通知URL,向商户服务器发送退款结果通知。通知中包含退款状态、退款成功与否、退款金额等信息。商户再更新订单和释放库存。
二、 签约支付
签约支付产品典型场景:会员包月、租赁费用,定期还款。
包括两种形式:独立签约后扣款、支付并签约。
1)独立签约后扣款:
用户首先在独立签约页面进行签约,待签约生效后,商家可以按照协议中的时间进行扣款。
开发文档:https://opendocs.alipay.com/open/00a05b
独立签约时序图:

用户签约时序图:

请求参数:
json
bizContent={
"product_code":"CYCLE_PAY_AUTH",//周期扣款场景固定为 CYCLE_PAY_AUTH
"personal_product_code":"CYCLE_PAY_AUTH_P",//周期扣款产品时必传签约其它产品时无需传入
"sign_scene":"INDUSTRY|CARRENTAL",//签约场景
"external_agreement_no":"dk20220712102811111",//商户签约号
"sign_validity_period":"2m",//当前用户签约请求的协议有效周期
"access_params":{//接入渠道
"channel":"ALIPAYAPP"
},
"period_rule_params":{//周期管控规则
"period_type":"DAY",//周期类型枚举值为DAY和MONTH
"period":"9",//周期数
"execute_time":"2022-07-13",//商户发起首次扣款的时间
"single_amount":"0.01",//每次发起扣款时限制的最大金额单位为元
"total_amount":"0.02",//周期内允许扣款的总金额,单位为元
"total_payments":"2"//总扣款次数
},
"identity_params":{// 非必填,用户实名信息参数
"user_name":"\u5f20\u4e09",
"cert_no":"61102619921108888",
"identity_hash":"ac8c238bc68fca1c35933db1efa1d79accc014db5dc42fb3a43c421d47c2dbfa",
"sign_user_id":"2088202888530893","sign_open_id":"031_DfFvT0Ufzk1852BLPnhuSWiztu4NqbkO35ylXPow-Y6"
}
}
请求代码:
java
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2");
AlipayUserAgreementPageSignRequest request = new AlipayUserAgreementPageSignRequest();
request.setBizContent(参考上面bizContent值示例);
request.setNotifyUrl("https://www.notifyURL.com");//设置异步通知地址
request.setReturnUrl("https://www.returnURL.com");//签约完成跳转地址
// 若想获取跳转链接使用pageExecute GET方式转换二维码可使用 alipayClient.pageExecute(request,"get")
// 周期扣款场景使用小程序/h5 接口跳转至签约页面时请使用 alipayClient.sdkExecute
AlipayUserAgreementPageSignResponse response = alipayClient.sdkExecute(request);
签约成功后会进行第一次支付。 周期性支付采用任务调度框架实现。
签约成功后续支付流程图:

签约成功后续支付代码:
java
package com.java.sdk.demo;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.domain.PayParams;
import com.alipay.api.domain.PromoParam;
import com.alipay.api.response.AlipayTradePayResponse;
import com.alipay.api.domain.AlipayTradePayModel;
import com.alipay.api.domain.ExtendParams;
import com.alipay.api.domain.GoodsDetail;
import com.alipay.api.request.AlipayTradePayRequest;
import com.alipay.api.domain.AgreementParams;
import com.alipay.api.FileItem;
import java.util.Base64;
import java.util.ArrayList;
import java.util.List;
public class AlipayTradePay {
public static void main(String[] args) throws AlipayApiException {
// 初始化SDK
AlipayClient alipayClient = new DefaultAlipayClient(getAlipayConfig());
// 构造请求参数以调用接口
AlipayTradePayRequest request = new AlipayTradePayRequest();
AlipayTradePayModel model = new AlipayTradePayModel();
// 设置商户订单号
model.setOutTradeNo("20150320010101001");
// 设置订单总金额
model.setTotalAmount("88.88");
// 设置订单标题
model.setSubject("Iphone6 16G");
// 设置产品码
model.setProductCode("CYCLE_PAY_AUTH");
// 设置代扣信息
AgreementParams agreementParams = new AgreementParams();
agreementParams.setAgreementNo("20170322450983769228");
agreementParams.setApplyToken("MDEDUCT0068292ca377d1d44b65fa24ec9cd89132f");
agreementParams.setAuthConfirmNo("423979");
model.setAgreementParams(agreementParams);
// 设置卖家支付宝用户ID
model.setSellerId("2088102146225135");
// 设置订单包含的商品列表信息
List<GoodsDetail> goodsDetail = new ArrayList<GoodsDetail>();
GoodsDetail goodsDetail0 = new GoodsDetail();
goodsDetail0.setGoodsName("ipad");
goodsDetail0.setQuantity(1L);
goodsDetail0.setPrice("2000");
goodsDetail0.setGoodsId("apple-01");
goodsDetail0.setGoodsCategory("34543238");
goodsDetail0.setCategoriesTree("124868003|126232002|126252004");
goodsDetail0.setShowUrl("http://www.alipay.com/xxx.jpg");
goodsDetail.add(goodsDetail0);
model.setGoodsDetail(goodsDetail);
// 设置业务扩展参数
ExtendParams extendParams = new ExtendParams();
extendParams.setSysServiceProviderId("2088511833207846");
extendParams.setSpecifiedSellerName("XXX的跨境小铺");
extendParams.setCardType("S0JP0000");
model.setExtendParams(extendParams);
// 设置优惠明细参数
PromoParam promoParams = new PromoParam();
promoParams.setActualOrderTime("2018-09-25 22:47:33");
model.setPromoParams(promoParams);
// 设置支付相关参数
PayParams payParams = new PayParams();
payParams.setAsyncType("NORMAL_ASYNC");
model.setPayParams(payParams);
// 设置返回参数选项
List<String> queryOptions = new ArrayList<String>();
queryOptions.add("voucher_detail_list");
model.setQueryOptions(queryOptions);
request.setBizModel(model);
// 第三方代调用模式下请设置app_auth_token
// request.putOtherTextParam("app_auth_token", "<-- 请填写应用授权令牌 -->");
AlipayTradePayResponse response = alipayClient.execute(request);
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
// sdk版本是"4.38.0.ALL"及以上,可以参考下面的示例获取诊断链接
// String diagnosisUrl = DiagnosisUtils.getDiagnosisUrl(response);
// System.out.println(diagnosisUrl);
}
}
private static AlipayConfig getAlipayConfig() {
String privateKey = "<-- 请填写您的应用私钥,例如:MIIEvQIBADANB ... ... -->";
String alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
AlipayConfig alipayConfig = new AlipayConfig();
alipayConfig.setServerUrl("https://openapi.alipay.com/gateway.do");
alipayConfig.setAppId("<-- 请填写您的AppId,例如:2019091767145019 -->");
alipayConfig.setPrivateKey(privateKey);
alipayConfig.setFormat("json");
alipayConfig.setAlipayPublicKey(alipayPublicKey);
alipayConfig.setCharset("UTF-8");
alipayConfig.setSignType("RSA2");
return alipayConfig;
}
}
2)支付并签约
用户在支付流程中,同时完成支付和签约。待签约生效后,商家可以按照协议中的时间进行扣款。
开发文档:https://opendocs.alipay.com/open/041bxs
签约支付时序图:

三、支付结果同步
3.1 支付回调地址
- 更新交易订单状态(交易微服务)。
- 发送MQ消息。
1)更新订单的状态。
2)更新合同的状态。