支付宝小程序流程简介图
开发步骤
- 创建小程序: 登入支付宝开发平台,创建支付宝小程序;
- 配置公钥密钥: 下载支付宝提供的支付宝开发平台开发助手生成“商户应用公钥”和“商户应用私钥”,然后将“商户应用公钥”去支付宝开发平台换取“支付宝公钥”;
- . 功能列表添加相关功能: 登入支付宝开发平台,进入小程序,在开发管理的功能列表中添加相关功能;
- 开始开发小程序: 根据小程序的需求开发小程序接口;
小程序授权
- 第一步:URL拼接与scope详解:
url拼接规则:https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?app_id=APPID&scope=SCOPE&redirect_uri=ENCODED_URL
- 第二步:获取auth_code:
http或https打头的授权回调地址? app_id=2016032301002387 &scope=auth_user&auth_code=10e20498fe5d42f18427d893fc06WX59
- 第三步:auth_code换取access_token与user_id:
package com.xzb.base.util.AliPay;
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.AlipayOpenAppQrcodeCreateRequest;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipayOpenAppQrcodeCreateResponse;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 支付宝认证接口
*/
public class AliAuthUtil {
private static String serverUrl = "https://openapi.alipay.com/gateway.do";
private static final Logger logger = LoggerFactory.getLogger(AliAuthUtil.class);
public static AlipayClient getAlipayClient(String appId, String privateKey, String publicKey) {
return new DefaultAlipayClient(serverUrl, appId, privateKey, "json", "utf-8", publicKey, "RSA2");
}
// 服务端获取access_token、user_id
public static String getAccessToken(String authCode, String appId, String privateKey,
String publicKey){
try {
AlipayClient alipayClient = getAlipayClient(appId, privateKey, publicKey);
AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
request.setGrantType("authorization_code");
request.setCode(authCode);
logger.warn("服务端获取access_token、user_id请求参数:{}",JSONObject.toJSONString(request));
AlipaySystemOauthTokenResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
logger.warn("服务端获取access_token、user_id调用成功,返回参数:{}",response.getBody());
return response.getBody();
} else {
logger.error("服务端获取access_token、user_id调用失败,appid:{}",appId);
}
} catch (AlipayApiException e) {
logger.error("服务端获取access_token、user_id调用异常,appid:{}",appId);
e.printStackTrace();
}
return null;
}
}
- 至此,用户信息授权流程已结束,如果只想拿到user_id(支付宝用户唯一标识符),则无需看下一步。
说明
- 用户授权auth_code: auth_code一次有效,auth_code有效期为3分钟到24小时(开放平台规则会根据具体的业务场景动态调整auth_code的有效期,但是不会低于3分钟,同时也不会超过24小时),超过有效期的auth_code即使未使用也将无法使用 ,用户的每次授权动作都会生成一个新的auth_code。
小程序二维码
/**
* 小程序二维码
* @param appId
* @param privateKey 私钥
* @param publicKey 公钥
* @param urlParam 小程序中能访问到的页面路径。
* @param queryParam 小程序的启动参数,打开小程序的query,在小程序onLaunch的方法中获取。
* @param describe 对应的二维码描述。
*/
public static String create(String appId, String privateKey, String publicKey,String urlParam,String queryParam,String describe) {
try {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayOpenAppQrcodeCreateRequest request = new AlipayOpenAppQrcodeCreateRequest();
JSONObject jsonObject = new JSONObject();
jsonObject.put("url_param",urlParam);
jsonObject.put("query_param",queryParam);
jsonObject.put("describe",describe);
request.setBizContent(jsonObject.toJSONString());
logger.warn("获取小程序二维码请求参数:{}",JSONObject.toJSONString(request));
AlipayOpenAppQrcodeCreateResponse response = alipayClient.execute(request);
if(response.isSuccess()){
logger.warn("调用支付宝小程序二维码成功,返回参数{}",response.getBody());
return response.getBody();
} else {
logger.error("调用支付宝小程序二维码失败,启动参数:{}",queryParam);
}
} catch (AlipayApiException e) {
logger.error("调用支付宝小程序二维码异常,启动参数:{}",queryParam);
e.printStackTrace();
}
return null;
}
资金冻结
/**
* 线上资金授权冻结
*
* @param appId appid
* @param privateKey 秘钥
* @param publicKey 公钥
* @param orderNo 订单号
* @param totalAmount 冻结金额
* @param outStoreCode 商户的门店编号
* @param orderName 订单名称
* @param notify_url 异步回调通知地址
* @param category 租赁行业的类型(如:充电宝,手机....)
* @param serviceId 信用场景下必传,具体值需要联系芝麻客服
* @return
* @throws AlipayApiException
*/
public static String frozen(String appId, String privateKey, String publicKey, String orderNo,
String totalAmount, String outStoreCode, String orderName, String notify_url,
String payeeUserId, String payeeLogonId,String outRequestNo,String category,String serviceId) throws AlipayApiException {
try {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayFundAuthOrderAppFreezeRequest request = new AlipayFundAuthOrderAppFreezeRequest();
AlipayFundAuthOrderAppFreezeModel model = new AlipayFundAuthOrderAppFreezeModel();
model.setOrderTitle("租赁商城-商品租赁押金冻结");
model.setOutOrderNo(orderNo);//实际订单号
model.setPayTimeout("31m");//订单过期时间
model.setOutRequestNo(outRequestNo);//替换为实际请求单号,保证每次请求都是唯一的
//payee_user_id(商户PID),payee_logon_id(商户登录ID)不能同时为空;
model.setPayeeUserId(payeeUserId);
model.setPayeeLogonId(payeeLogonId);
model.setProductCode("PRE_AUTH_ONLINE");//PRE_AUTH_ONLINE为固定值,不要替换
model.setAmount(totalAmount);
//如果是信用授权 则下面注释的必须传
Map<String, String> extraParam = new HashMap<>();
//category为业务分类 地址:https://docs.open.alipay.com/10719
extraParam.put("category", category);
extraParam.put("serviceId", serviceId);
extraParam.put("outStoreCode", outStoreCode);
extraParam.put("outStoreAlias", orderName);
model.setExtraParam(JSON.toJSONString(extraParam));
request.setBizModel(model);
request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知
logger.info("线上资金冻结请求参数:{}",JSONObject.toJSONString(request));
AlipayFundAuthOrderAppFreezeResponse response = alipayClient.sdkExecute(request);//注意这里是sdkExecute,可以获取签名参数
if (response.isSuccess()) {
logger.info("线上资金授权冻结调用成功,返回参数: {}" + response.getBody());//签名后的参数,直接入参到
return response.getBody();
}else {
logger.info("线上资金授权冻结调用失败,orderNo:{}",orderNo);
}
} catch (AlipayApiException e) {
logger.info("线上资金授权冻结调用异常,orderNo:{}",orderNo);
e.printStackTrace();
}
return null;
}
资金解冻
/**
* 资金授权解冻
*
* @param appId appid
* @param privateKey 私钥
* @param publicKey 公钥
* @param notify_url 回调地址
* @param authNo 支付宝授权成功订单号
* @param outRequestNo 商户资金操作流水号
* @param totalAmount 解冻金额
* @return
* @throws Exception
*/
public static boolean fundAuthOrderUnFreeze(String appId, String privateKey, String publicKey, String notify_url, String authNo, String outRequestNo, String totalAmount) {
try {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayFundAuthOrderUnfreezeRequest request = new AlipayFundAuthOrderUnfreezeRequest();
AlipayFundAuthOrderUnfreezeModel model = new AlipayFundAuthOrderUnfreezeModel();
model.setAuthNo(authNo); // 支付宝资金授权订单号,在授权冻结成功时返回需要入库保存
model.setOutRequestNo(outRequestNo);//同一商户每次不同的资金操作请求,商户请求流水号不能重复,且与冻结流水号不同
model.setAmount(totalAmount); // 本次操作解冻的金额,单位为:元(人民币),精确到小数点后两位
model.setRemark("租赁商城-商品租赁押金解冻"); // 商户对本次解冻操作的附言描述,长度不超过100个字母或50个汉字
//选填字段,信用授权订单,针对信用全免订单,传入该值完结信用订单,形成芝麻履约记录
model.setExtraParam("{\"unfreezeBizInfo\":\"{\\\"bizComplete\\\":\\\"true\\\"}\"}");
request.setBizModel(model);
request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知
logger.warn("资金授权解冻请求参数: {}" + JSONObject.toJSONString(request));
AlipayFundAuthOrderUnfreezeResponse response = alipayClient.execute(request);
logger.warn("资金授权解冻返回参数: {}" + response.getBody());
return response.isSuccess();
} catch (AlipayApiException e) {
logger.error("资金授权解冻调用异常,authNo:{}",authNo);
e.printStackTrace();
}
return false;
}
资金授权操作查询
/**
* 资金授权操作查询
* 功能:通过该接口可以查询单笔明细的详细信息,细分到每一次操作,如冻结、解冻。
*
* @param appId appid
* @param privateKey
* @param publicKey
* @param authNo
* @param outOrderNo
* @param operationId
* @param outRequestNo
* @return
*/
public static String fundAuthQuery(String appId, String privateKey, String publicKey, String authNo, String outOrderNo, String operationId, String outRequestNo) {
try {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayFundAuthOperationDetailQueryRequest request = new AlipayFundAuthOperationDetailQueryRequest();
AlipayFundAuthOperationDetailQueryModel model = new AlipayFundAuthOperationDetailQueryModel();
model.setAuthNo(authNo); // 支付宝资金授权订单号,在授权冻结成功时返回参数中获得
model.setOutOrderNo(outOrderNo); //商户的授权资金订单号,与支付宝的授权资金订单号不能同时为空
model.setOperationId(operationId); //支付宝的授权资金操作流水号,冻结成功同步返回
model.setOutRequestNo(outRequestNo);//商户的授权资金操作流水号,与支付宝的授权资金操作流水号不能同时为空,该值为冻结或解冻是的outRequestNo
request.setBizModel(model);
logger.warn("资金授权操作查询请求参数:{}",JSONObject.toJSONString(request));
AlipayFundAuthOperationDetailQueryResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
logger.warn("资金授权操作查询调用成功,返回参数:{}",response.getBody());
return response.getBody();
}else {
logger.error("资金授权操作查询失败,outOrderNo:{}",outOrderNo);
}
} catch (AlipayApiException e) {
logger.error("资金授权操作查询异常,outOrderNo:{}",outOrderNo);
e.printStackTrace();
}
return null;
}
授权转支付
/**
* 授权转支付
*
* @param appId
* @param privateKey
* @param publicKey
* @param outTradeNo 商户订单号
* @param authNo 支付宝授权成功订单号
* @param sellerId 卖家支付宝账户pid
* @param payUserId 预授权用户uid,通过预授权冻结接口返回的payer_user_id字段获取
* @param storeId 与预授权的outStoreCode保持一致即可
* @param totalAmount 结束支付金额
* @param notifyUrl 回调地址
* @return
* @throws AlipayApiException
*/
public static boolean tradePay(String appId, String privateKey, String publicKey, String outTradeNo,
String authNo, String sellerId, String payUserId, String storeId, String totalAmount, String notifyUrl) {
try {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayTradePayRequest request = new AlipayTradePayRequest();
AlipayTradePayModel model = new AlipayTradePayModel();
model.setOutTradeNo(outTradeNo); // 预授权转支付商户订单号,为新的商户交易流水号
model.setProductCode("PRE_AUTH_ONLINE"); // 固定值PRE_AUTH_ONLINE
model.setAuthNo(authNo); // 填写预授权冻结交易号
model.setSubject("租赁支付"); // 解冻转支付标题,用于展示在支付宝账单中
model.setTotalAmount(totalAmount); // 结算支付金额
model.setSellerId(sellerId); // 填写卖家支付宝账户pid
model.setBuyerId(payUserId); // 填写预授权用户uid,通过预授权冻结接口返回的payer_user_id字段获取
model.setStoreId(storeId); // 填写实际交易发生的终端编号,与预授权的outStoreCode保持一致即可
model.setBody("租赁支付"); // 可填写备注信息
model.setAuthConfirmMode("COMPLETE");//传入COMPLETE时,用户剩余金额会自动解冻
request.setBizModel(model);
request.setNotifyUrl(notifyUrl);//异步通知地址,必填,该接口只通过该参数进行异步通知
logger.warn("授权转支付请求参数:{}",JSONObject.toJSONString(request));
AlipayTradePayResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
logger.warn("授权转支付调用成功,返回参数: {}" + response.getBody());
return true;
} else {
logger.error("授权转支付调用失败, authNo:{}" + authNo);
}
} catch (AlipayApiException e) {
logger.error("授权转支付调用异常, authNo:{}" + authNo);
e.printStackTrace();
}
return false;
}
统一收单交易创建接口(支付)
/**
* 中文名:(统一收单交易创建接口)
* 接口英文名:alipay.trade.create
* @param appId
* @param privateKey
* @param publicKey
* @param outTradeNo 商户订单号
* @param totalAmount 支付金额
* @param subject 订单标题
* @param buyer_id 是支付宝小程序授权登录成功后获取到的支付宝 user_id
* @param notify_url 回调地址
* @return
*/
public static String create(String appId, String privateKey, String publicKey,String outTradeNo,String totalAmount,String subject,String buyer_id, String notify_url) {
AlipayClient alipayClient = AliAuthUtil.getAlipayClient(appId, privateKey, publicKey);
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
JSONObject jsonObject = new JSONObject();
jsonObject.put("out_trade_no",outTradeNo);
jsonObject.put("total_amount",totalAmount);
jsonObject.put("subject",subject);
jsonObject.put("buyer_id",buyer_id);
jsonObject.put("timeout_express","31m");
request.setBizContent(jsonObject.toJSONString());
request.setNotifyUrl(notify_url);//异步通知地址,必填,该接口只通过该参数进行异步通知
logger.warn("统一收单交易创建接口请求参数:{}",JSONObject.toJSONString(request));
try {
//使用的是execute
AlipayTradeCreateResponse response = alipayClient.execute(request);
String tradeNo = response.getTradeNo();//获取返回的tradeNO。
return tradeNo;
} catch (AlipayApiException e) {
e.printStackTrace();
}
return null;
}
自定义工具方法
/**
* 验证
*
* @param params
* @param publicKey
* @return
*/
public static boolean rsaCheckV1(Map<String, String> params, String publicKey, String signType) {
boolean b = false;
try {
b = AlipaySignature.rsaCheckV1(params, publicKey, "utf-8", signType);
} catch (AlipayApiException e) {
e.printStackTrace();
}
return b;
}
/**
* 生成随机流水号
*
* @return
*/
public static String genOrderNo() {
long num = System.currentTimeMillis() + (long) (Math.random() * 10000000L);
return String.valueOf(num);
}
接收回调
/**
* 支付宝支付回调
*
* @return
*/
@RequestMapping("/alipayCallback")
public void aliCallback(HttpServletRequest request, HttpServletResponse response) {
Map<String, String[]> notifyParams = request.getParameterMap();
String notifyParamStr = JSONObject.toJSONString(notifyParams);
logger.warn("回调通知参数:{}", notifyParamStr);
//验证入参
Map<String, String> params = new HashMap<String, String>();
for (Iterator<String> iter = notifyParams.keySet().iterator(); iter.hasNext(); ) {
String name = iter.next();
String[] values = notifyParams.get(name);
String valueStr = "";
for (int i = 0; i < values.length; i++) {
valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
}
params.put(name, valueStr);
}
// getAliPublicKey() 自定义方法获取支付宝公钥
boolean b = AliPayUtil.rsaCheckV1(params, getAliPublicKey(), "RSA2");
if (!b) {
logger.error("验证失败,验签参数:{}", JSON.toJSONString(params));
return;
}
JSONObject jsonObject = JSONObject.parseObject(notifyParamStr);
//业务处理
.....
//向芝麻反馈处理是否成功
PrintWriter writer = null;
try {
writer = response.getWriter();
writer.write("success"); //一定要打印success
writer.flush();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (writer != null) {
writer.close();
}
}
}
来源:CSDN
作者:布衣斋
链接:https://blog.csdn.net/weixin_43759423/article/details/103459595