java ,springboot 对接支付宝支付,实现生成付款二维码,退款,查询订单状态等接口
查看文档 支付宝文档地址:
小程序文档 - 支付宝文档中心
使用沙箱环境
沙箱登录地址
登录 - 支付宝
点击查看 才能看钥匙截图写错了。。 问号可以看默认加密方式
点击沙箱帐号 这里我们就具备所有条件了
实战开始
pom文件增加依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.38.0.ALL</version>
</dependency>
创建配置文件,将沙箱内的信息填写到配置文件
# 支付宝网关名
open_api_domain = https://openapi-sandbox.dl.alipaydev.com/gateway.do
#此处请填写你的PID
pid = 20887210111111
#此处请填写你当面付的APPID
appid = 902101111110
# RSA私钥、公钥和支付宝公钥
#此处请填写你的应用私钥且转PKCS8格式
private_key = cpwVvks4h8PwdWDm13Jc207PvY5iy+8xMQd919ClW9H8lVBbpuyA+uyRmoPHp63SpmSnyXAye7ZvjDvuJ4kH9edbLnL
#此处请填写你的应用公钥
public_key = qRhLEXLU+LvD91mAs1iVCGx4bpfl2eLpwLMYvCePwijD6xdBPuRsNv3Chw4xUHfoqK6MKRLzXeqJPdEinhr/DZrAnSbkdH8BwIDAQAB
#SHA256withRsa对应支付宝公钥
alipay_public_key = MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqGJldKdkvrx1WirZ4LGUP1DCELrb9Ci1qIdU1Y35z7v4V44BWv2QZoFVVjqVd7mAy7EtCM/cnTH5
# 签名类型: RSA->SHA1withRsa,RSA2->SHA256withRsa
sign_type = RSA2
# 当面付最大查询次数和查询间隔(毫秒)
max_query_retry = 5
query_duration = 5000
# 当面付最大撤销次数和撤销间隔(毫秒)
max_cancel_retry = 3
cancel_duration = 2000
# 交易保障线程第一次调度延迟和调度间隔(秒)
heartbeat_delay = 5
heartbeat_duration = 900
#异步通知url(注意拦截器是否拦截)
NotifyUrl=http://fpwquz.natappfree.cc/callbac
支付实体
package com.bjbr.controller;
import com.alipay.api.domain.GoodsDetail;
import java.util.List;
/**
* 支付宝当面付实体类
*
*/
public class ZFBFaceToFaceModel {
private String outTradeNo;// (必填) 商户网站订单系统中唯一订单号 ,64个字符以内,只能包含字母、数字、下划线, 需保证商户系统端不能重复,建议通过数据库sequence生成
private String subject; // (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费”
private String totalAmount;// (必填) 订单总金额单位为元,不能超过1亿元 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
private String undiscountableAmount;// (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
private String sellerId;// 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)// 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
private String body;// // 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
private String operatorId; // 商户操作员编号,添加此参数可以为商户操作员做销售统计
private String storeId; // (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
private String timeoutExpress;//支付超时如:“120m”,定义为120分钟
private List<GoodsDetail> goodsDetailList; //商品明细列表,需填写购买商品详细信息,
private String NotifyUrl;// 支付成功之后 支付宝异步调用的接口地址;
private String MoblieReturnUrl;//手机支付同步通知页面地址;
private String refundReason;//退款原因,(退款使用)
private String tradeNo;//支付宝订单号,(退款使用)
public String getTradeNo() {
return tradeNo;
}
public void setTradeNo(String tradeNo) {
this.tradeNo = tradeNo;
}
public String getRefundReason() {
return refundReason;
}
public void setRefundReason(String refundReason) {
this.refundReason = refundReason;
}
/**
* (必填) 商户网站订单系统中唯一订单号 ,64个字符以内,只能包含字母、数字、下划线, 需保证商户系统端不能重复,建议通过数据库sequence生成
* @return
*/
public String getOutTradeNo() {
return outTradeNo;
}
/**
* (必填) 商户网站订单系统中唯一订单号 ,64个字符以内,只能包含字母、数字、下划线, 需保证商户系统端不能重复,建议通过数据库sequence生成
* @param outTradeNo
*/
public void setOutTradeNo(String outTradeNo) {
this.outTradeNo = outTradeNo;
}
/**
* (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费”
* @return
*/
public String getSubject() {
return subject;
}
/**
* (必填) 订单标题,粗略描述用户的支付目的。如“喜士多(浦东店)消费”
* @param subject
*/
public void setSubject(String subject) {
this.subject = subject;
}
/**
* (必填) 订单总金额单位为元,不能超过1亿元 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
* @return
*/
public String getTotalAmount() {
return totalAmount;
}
/**
* (必填) 订单总金额单位为元,不能超过1亿元 如果同时传入了【打折金额】,【不可打折金额】,【订单总金额】三者,则必须满足如下条件:【订单总金额】=【打折金额】+【不可打折金额】
* @param totalAmount
*/
public void setTotalAmount(String totalAmount) {
this.totalAmount = totalAmount;
}
/**
* (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
* @return
*/
public String getUndiscountableAmount() {
return undiscountableAmount;
}
/**
* (可选) 订单不可打折金额,可以配合商家平台配置折扣活动,如果酒水不参与打折,则将对应金额填写至此字段 如果该值未传入,但传入了【订单总金额】,【打折金额】,则该值默认为【订单总金额】-【打折金额】
* @param undiscountableAmount
*/
public void setUndiscountableAmount(String undiscountableAmount) {
this.undiscountableAmount = undiscountableAmount;
}
/**
* // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)// 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
* @return
*/
public String getSellerId() {
return sellerId;
}
/**
* // 卖家支付宝账号ID,用于支持一个签约账号下支持打款到不同的收款账号,(打款到sellerId对应的支付宝账号)// 如果该字段为空,则默认为与支付宝签约的商户的PID,也就是appid对应的PID
* @param sellerId
*/
public void setSellerId(String sellerId) {
this.sellerId = sellerId;
}
/**
* 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
* @return
*/
public String getBody() {
return body;
}
/**
* 订单描述,可以对交易或商品进行一个详细地描述,比如填写"购买商品2件共15.00元"
* @param body
*/
public void setBody(String body) {
this.body = body;
}
/**
*商户操作员编号,添加此参数可以为商户操作员做销售统计
* @return
*/
public String getOperatorId() {
return operatorId;
}
/**
*商户操作员编号,添加此参数可以为商户操作员做销售统计
* @param operatorId
*/
public void setOperatorId(String operatorId) {
this.operatorId = operatorId;
}
/**
* (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
* @return
*/
public String getStoreId() {
return storeId;
}
/**
* (必填) 商户门店编号,通过门店号和商家后台可以配置精准到门店的折扣信息,详询支付宝技术支持
* @param storeId
*/
public void setStoreId(String storeId) {
this.storeId = storeId;
}
/**
*支付超时如:“120m”,定义为120分钟
* @return
*/
public String getTimeoutExpress() {
return timeoutExpress;
}
/**
*支付超时如:“120m”,定义为120分钟
* @param timeoutExpress
*/
public void setTimeoutExpress(String timeoutExpress) {
this.timeoutExpress = timeoutExpress;
}
/**
*商品明细列表,需填写购买商品详细信息,
* @return
*/
public List<GoodsDetail> getGoodsDetailList() {
return goodsDetailList;
}
/**
*商品明细列表,需填写购买商品详细信息,
* @param goodsDetailList
*/
public void setGoodsDetailList(List<GoodsDetail> goodsDetailList) {
this.goodsDetailList = goodsDetailList;
}
/**
*支付成功之后 支付宝异步调用的接口地址;
* @return
*/
public String getNotifyUrl() {
return NotifyUrl;
}
/**
*支付成功之后 支付宝异步调用的接口地址;
* @param notifyUrl
*/
public void setNotifyUrl(String notifyUrl) {
NotifyUrl = notifyUrl;
}
/**
* 手机支付后跳转的页面地址
* @return
*/
public String getMoblieReturnUrl() {
return MoblieReturnUrl;
}
/**
* 手机支付后跳转的页面地址
* @return
*/
public void setMoblieReturnUrl(String moblieReturnUrl) {
MoblieReturnUrl = moblieReturnUrl;
}
}
根据键值获取配置文件内容方法
public static String getZFBinfoValue(String name){
try(InputStream inputStream = CommonUtils.class.getClassLoader().getResourceAsStream("config/zfbinfo.properties")) {
if(properties==null){
properties = new Properties();
properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
}
return properties.getProperty(name,"");
} catch (Exception e) {
log.error(e.getMessage(),e);
return "";
}
}
获取二维码接口
public static String getZFBPreorder(ZFBFaceToFaceModel zfbFaceToFaceModel) throws AlipayApiException {
CommonUtils commonUtils = new CommonUtils();
/** 支付宝网关 **/
String URL = commonUtils.getZFBinfoValue("open_api_domain");
/** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
String APP_ID = commonUtils.getZFBinfoValue("appid");
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
String APP_PRIVATE_KEY = commonUtils.getZFBinfoValue("private_key");
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
String ALIPAY_PUBLIC_KEY = commonUtils.getZFBinfoValue("alipay_public_key");
/** 初始化 **/
AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
/** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.precreate(统一收单线下交易预创建(扫码支付)) **/
AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
/** 设置业务参数 **/
AlipayTradePrecreateModel model = new AlipayTradePrecreateModel();
/** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
model.setOutTradeNo(zfbFaceToFaceModel.getOutTradeNo());
/**订单标题 **/
model.setSubject(zfbFaceToFaceModel.getSubject());
/** 订单金额,精确到小数点后两位 **/
model.setTotalAmount(zfbFaceToFaceModel.getTotalAmount());
/** 订单描述 **/
model.setBody(zfbFaceToFaceModel.getBody());
/** 将业务参数传至request中 **/
request.setBizModel(model);
/** 异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
request.setNotifyUrl(zfbFaceToFaceModel.getNotifyUrl());
/** 通过alipayClient调用API,获得对应的response类 **/
AlipayTradePrecreateResponse response = alipayClient.execute(request);
/** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/101 **/
System.out.println(response.getBody());
return response.getBody();
}
退款接口
public static String ZFBTradeRefund(ZFBFaceToFaceModel zfbFaceToFaceModel) throws AlipayApiException {
CommonUtils commonUtils = new CommonUtils();
/** 支付宝网关 **/
String URL = commonUtils.getZFBinfoValue("open_api_domain");
/** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
String APP_ID = commonUtils.getZFBinfoValue("appid");
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
String APP_PRIVATE_KEY = commonUtils.getZFBinfoValue("private_key");
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
String ALIPAY_PUBLIC_KEY = commonUtils.getZFBinfoValue("alipay_public_key");
/** 初始化 **/
AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
/** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.refund(统一收单交易退款接口) **/
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
/** 设置业务参数 **/
AlipayTradeRefundModel model = new AlipayTradeRefundModel ();
/** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
model.setOutTradeNo(zfbFaceToFaceModel.getOutTradeNo());
model.setTradeNo(zfbFaceToFaceModel.getTradeNo());
// 设置退款金额
model.setRefundAmount(zfbFaceToFaceModel.getTotalAmount());
// 设置退款原因说明
model.setRefundReason(zfbFaceToFaceModel.getRefundReason());
// 设置退款请求号 退款请求号。 标识一次退款请求,需要保证在交易号下唯一
model.setOutRequestNo(UUID.randomUUID().toString());
/** 将业务参数传至request中 **/
request.setBizModel(model);
/** TODO暂时不用退款通知 异步通知地址,以http或者https开头的,商户外网可以post访问的异步地址,用于接收支付宝返回的支付结果,如果未收到该通知可参考该文档进行确认:https://opensupport.alipay.com/support/helpcenter/193/201602475759 **/
request.setNotifyUrl("");
AlipayTradeRefundResponse response = alipayClient.execute(request);
/** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/101 **/
System.out.println(response.getBody());
if (response.isSuccess()) {
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
return response.getBody();
}
查询订单状态接口
public static String ZFBTradeQuery(ZFBFaceToFaceModel zfbFaceToFaceModel) throws AlipayApiException {
CommonUtils commonUtils = new CommonUtils();
/** 支付宝网关 **/
String URL = commonUtils.getZFBinfoValue("open_api_domain");
/** 应用id,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/190/201602493024 **/
String APP_ID = commonUtils.getZFBinfoValue("appid");
/** 应用私钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602469554 **/
String APP_PRIVATE_KEY = commonUtils.getZFBinfoValue("private_key");
/** 支付宝公钥,如何获取请参考:https://opensupport.alipay.com/support/helpcenter/207/201602487431 **/
String ALIPAY_PUBLIC_KEY = commonUtils.getZFBinfoValue("alipay_public_key");
/** 初始化 **/
AlipayClient alipayClient = new DefaultAlipayClient(URL, APP_ID, APP_PRIVATE_KEY, "json", "UTF-8", ALIPAY_PUBLIC_KEY, "RSA2");
/** 实例化具体API对应的request类,类名称和接口名称对应,当前调用接口名称:alipay.trade.refund(统一收单交易退款接口) **/
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest ();
/** 设置业务参数 **/
AlipayTradeQueryModel model = new AlipayTradeQueryModel ();
/** 商户订单号,商户自定义,需保证在商户端不重复,如:20200612000001 **/
model.setOutTradeNo(zfbFaceToFaceModel.getOutTradeNo());
model.setTradeNo(zfbFaceToFaceModel.getTradeNo());
/** 将业务参数传至request中 **/
request.setBizModel(model);
AlipayTradeQueryResponse response = alipayClient.execute(request);
/** 获取接口调用结果,如果调用失败,可根据返回错误信息到该文档寻找排查方案:https://opensupport.alipay.com/support/helpcenter/101 **/
//解析json数据
JSONObject jsonObject=JSONObject.parseObject(response.getBody());
//得到alipay_trade_query_response数据后再强转JSONObject
JSONObject jsonobj_two=(JSONObject)jsonObject.get("alipay_trade_query_response");
//再通过jsonobj_two获取到二维码地址
String code=jsonobj_two.get("code").toString();
//交易状态:WAIT_BUYER_PAY(交易创建,等待买家付款)、TRADE_CLOSED(未付款交易超时关闭,或支付完成后全额退款)、TRADE_SUCCESS(交易支付成功)、TRADE_FINISHED(交易结束,不可退款)
String trade_status=jsonobj_two.get("trade_status").toString();
if (trade_status.equals("TRADE_SUCCESS")) {//用户已付款 直接调用回调
return "yzf";
}else {
return "wzf";
}
}