流程详解
相对于集成微信支付来说,支付宝相对简单些,支付宝对复杂的操作进行了高度封装
支付宝文档
创建应用
登录 支付宝开放平台,创建应用并提交审核,审核通过后会生成应用唯一标识 APPID,并且可以申请开通开放产品使用权限。通过 APPID 应用才能调用开放产品的接口能力(应用没上线也可以申请的,准备好相关的资料即可)
添加支付能力
应用创建完成后,系统会自动跳转到应用详情页面。开发者可以在 能力列表 中点击 添加能力 来添加 APP支付 功能。
接口加签
进入开发设置中完成接口加签方式、IP白名单、应用网关、接口内容加密方式开发信息设置。
接口加签方式:必填。用于保障商户应用和支付宝交互的安全性;
加签模式可分为:公钥证书模式和公钥模式,推荐使用证书模式,一劳永逸,因为支付宝很多开放功能想要使用,加签模式必须是证书模式,比如:转账到支付宝账户
获取证书
获取应用公私钥/公钥证书
最终获取证书结果:
集成支付到springboot项目
依赖
<!--easy版-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>${alipay-easysdk.version}</version>
</dependency>
<!--通用版-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>${alipay-sdk-java.version}</version>
</dependency>
版本信息
加载证书信息:
//应用私钥
static String merchantPrivateKey;
static String signType = "RSA2";
static String appId = "202100xxxxxxxx";
//应用私钥文件路径
static String appPrivateKeyPath = "zfb/appPrivate_RSA2_PKCS8.txt";
//应用公钥证书
static String merchantCertPath = "zfb/appCertPublicKey_2021002151695893.crt";
//支付宝公钥证书
static String alipayCertPath = "zfb/alipayCertPublicKey_RSA2.crt";
//支付宝根证书
static String alipayRootCertPath = "zfb/alipayRootCert.crt";
//支付异步通知接收服务地址(自己定义,支付宝异步调用,确保这个接口没有限制)
static String payNotifyUrl = "http://(域名/IP)/thirdparty/payNotify/payed/zfbNotify";
//退款异步通知接收服务地址
//static String refundNotifyUrl = "http://(域名/IP)/PayNotify/refunded/zfbNotify";
static {
//读取应用私钥
try {
InputStream is = ZfbPayInfoConfig.class.getClassLoader().getResourceAsStream(appPrivateKeyPath);
String str = IOUtils.toString(is, "utf-8");
merchantPrivateKey = str;
Config config = new Config();
config.protocol = "https";
config.gatewayHost = "openapi.alipay.com";
config.signType = signType;
config.appId = appId;
// 为避免私钥随源码泄露,推荐从文件中读取私钥字符串而不是写入源码中,应用私钥
config.merchantPrivateKey = merchantPrivateKey;
//注:证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径,优先从文件系统中加载,加载失败后会继续尝试从CLASS_PATH中加载
//应用公钥证书
config.merchantCertPath = merchantCertPath;
//支付宝公钥证书
config.alipayCertPath = alipayCertPath;
//支付宝根证书
config.alipayRootCertPath = alipayRootCertPath;
//注:支付宝公钥,如果采用非证书模式,则无需赋值上面的三个证书路径,改为赋值如下的支付宝公钥字符串即可
//config.alipayPublicKey = "<-- 请填写您的支付宝公钥,例如:MIIBIjANBg... -->";
//可设置异步通知接收服务地址(可选)
config.notifyUrl = payNotifyUrl;
//可设置AES密钥,调用AES加解密相关接口时需要(可选)
//config.encryptKey = "<-- 请填写您的AES密钥,例如:aa4BtZ4tspm2wnXLb1ThQA== -->";
// 1. 设置参数(全局只需设置一次)
Factory.setOptions(config);
} catch (Exception e) {
e.printStackTrace();
}
}
使用,老规矩,看文档,文档最详细,找到文档位置是关键:
接入流程,入口
这里有通用版和easy版的详细介绍,下边都以easy做示例,easy进行了封装,使用起来更加方便。
参考这里的开放接口
订单支付:
AlipayTradeAppPayResponse payResponse = Payment.App()
//设置15分钟未支付,则此次支付失败,因为订单过期了
.optional("timeout_express", "15m")
//passback_params 扩展参数,用于异步接收的时候根据这个参数写一些自定义逻辑,不用可以不加
.optional("passback_params", URLEncoder.encode(CommonConstant.pay_order, "utf-8"))
.pay("商品", totalOrderSn, totalPrice.toPlainString());
最重要的参数就是订单号和价格,看吧,就是如此简单。
简单看一下源码,可以看到sdk内部已经帮我们封装了前期的准备工作,签名逻辑也不用自己去封装啦,并且之后的异步通知验签一行代码就解决了,爽吧!!!
接收异步通知:
/**
* 功能描述:支付宝异步回掉地址
*
* @param vo
* @param request
* @return java.lang.String
* @author zhouwenjie
* @date 2021/5/30 22:27
*/
@ApiOperation(value = "支付宝异步通知", notes = "支付宝异步通知")
@PostMapping("/payed/zfbNotify")
public String handleAliPayed(ZfbPayAsyncVo vo, HttpServletRequest request) throws Exception {
//获取支付宝POST过来反馈信息
Map<String, String> params = new HashMap<String, String>();
Map<String, String[]> requestParams = request.getParameterMap();
for (Iterator<String> iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = iter.next();
String[] values = requestParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i]
: valueStr + values[i] + ",";
}
//乱码解决,这段代码在出现乱码时使用
//valueStr = new String(valueStr.getBytes("ISO-8859-1"), "utf-8");
params.put(name, valueStr);
}
//验签
Boolean signVerified = Factory.Payment.Common().verifyNotify(params);
if (signVerified){
//开始正常逻辑处理
}
}
ZfbPayAsyncVo 实体类
@ToString
@Data
public class ZfbPayAsyncVo {
/**
* 交易创建时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date gmt_create;
/**
* 交易付款时间
*/
private String gmt_payment;
/**
* 交易退款时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date gmt_refund;
/**
* 交易结束时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date gmt_close;
/**
* 通知时间
*/
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date notify_time;
/**
* 编码格式utf-8
*/
private String charset;
/**
* 支付宝分配给开发者的应用Id
*/
private String app_id;
/**
* 买家支付宝用户号
*/
private String buyer_id;
/**
* 买家支付宝账号
*/
private String buyer_logon_id;
/**
* 卖家支付宝用户号
*/
private String seller_id;
/**
* 卖家支付宝账号
*/
private String seller_email;
/**
* 商户订单号
*/
private String out_trade_no;
/**
* 商品描述,订单的信息
*/
private String body;
/**
* 订单标题
*/
private String subject;
/**
* 接口版本
*/
private String version;
/**
* 通知校验ID
*/
private String notify_id;
/**
* 通知类型:trade_status_sync
*/
private String notify_type;
/**
* 支付金额信息,支付成功的各个渠道金额信息,详见下表 资金明细信息说明
*/
private String fund_bill_list;
/**
* 订单金额,支付的总额
*/
private BigDecimal total_amount;
/**
* 交易状态 TRADE_SUCCESS
*/
private String trade_status;
/**
* 支付宝交易号,流水号
*/
private String trade_no;
/**
* 用户在交易中支付的可开发票的金额
*/
private BigDecimal invoice_amount;
/**
* 实收金额(商家收到的款)
*/
private BigDecimal receipt_amount;
/**
* 集分宝金额
*/
private BigDecimal point_amount;
/**
* 付款金额,最终支付的金额
*/
private BigDecimal buyer_pay_amount;
/**
* 退款通知中,返回总退款金额,单位为元,支持两位小数
*/
private BigDecimal refund_fee;
/**
* 签名
*/
private String sign;
/**
* 签名类型
*/
private String sign_type;
/**
* 公共回传参数,如果请求时传递了该参数,则返回给商户时会在异步通知时将该参数原样返回。
* 本参数必须进行UrlEncode之后才可以发送给支付宝
*/
private String passback_params;
}
退款:
- 未发货退款
/**
* 功能描述: 处理未发货退款
*
* @param refundInfo
* @return boolean
* @author zhouwenjie
* @date 2021/6/30 15:03
*/
private AlipayTradeRefundResponse refundByzfb(RefundInfo refundInfo) {
AlipayTradeRefundResponse refundResponse = null;
try {
refundResponse = Factory.Payment.Common()
.refund(refundInfo.getOrderTotalSn(), refundInfo.getRefundFee().toPlainString());
} catch (Exception e) {
e.printStackTrace();
}
return refundResponse;
}
- 已发货退款
/**
* 功能描述: 处理已发货退款
*
* @param apply
* @return boolean
* @author zhouwenjie
* @date 2021/6/30 15:03
*/
private boolean refundByzfb(OrderReturnApply apply) {
boolean isSuccess = false;
try {
//已发货退款
AlipayTradeRefundResponse refundResponse = Factory.Payment.Common()
//退款请求号,部分退款必填,防止重复退款
.optional("out_request_no", apply.getOutRequestNo())
.refund(apply.getOrderTotalSn(), apply.getReturnAmount().toPlainString());
} catch (Exception e) {
e.printStackTrace();
}
return isSuccess;
支付宝退款不同于微信,微信退款结果有三种结果,成功、失败、处理中(等待退款异步通知),而支付宝只有成功、失败,所以只在这个返回值中取结果处理逻辑即可;具体信息查看支付能力相关文档