最近在开发一款预约停车小程序, 记录一下使用支付宝支付api的流程,本文涉及到的是 公钥 加签方式
1.开发前的配置准备
1.1 创建小程序并上传审核
1.2 生成秘钥并上传
生成秘钥地址:跟着流程走即可
签名完成之后会自动生成支付宝公钥,需要记录保存
注释:在配置完签名之后可以获取支付宝公钥, 支付宝公钥唯一, 不会因为私钥和公钥的变换而改变
关于支付宝公钥的问题链接
如果做的项目是第三方平台(ISV)代替商户收款, 还是需要商户授权的(我做的就是这个)
2.通用配置
2.1 引入 maven 依赖
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.79.ALL</version>
</dependency>
添加配置信息
wensi:
alipay:
gatewayUrl: https://openapi.alipay.com/gateway.do
appid: 小程序id
appPrivateKey: 你的应用私钥
alipayPublicKey: 生成的阿里公钥
2.2 AlipayProperties
@Data
@ConfigurationProperties(prefix = "pay.alipay")
public class AlipayProperties {
/**
* 支付宝gatewayUrl
*/
private String gatewayUrl;
/**
* 商户应用id
*/
private String appid;
/**
* RSA私钥,用于对商户请求报文加签
*/
private String appPrivateKey;
/**
* 支付宝RSA公钥,用于验签支付宝应答
*/
private String alipayPublicKey;
/**
* 签名类型
*/
private String signType = "RSA2";
/**
* 格式
*/
private String formate = "json";
/**
* 编码
*/
private String charset = "UTF-8";
/**
* 同步地址
*/
private String returnUrl;
/**
* 异步地址
*/
private String notifyUrl;
}
AlipayClient
@Autowired
private AlipayProperties properties;
/**
* 支付宝接口加签模式为公钥时使用
*/
@Bean
public AlipayClient alipayClient() {
return new DefaultAlipayClient(properties.getGatewayUrl(), // 支付宝网关 唯一
properties.getAppid(), // 小程序的appid
properties.getAppPrivateKey(), // 生成的私钥
properties.getFormate(),
properties.getCharset(),
properties.getAlipayPublicKey(), // 阿里公钥
properties.getSignType());
}
调取支付接口
//将 alipayClient 注入进来
// 建议对入参进行验证
// 创建订单请求
AlipayTradeCreateRequest request = new AlipayTradeCreateRequest();
// 使用第三方代商户收款的时候传入
String appAuthToken = model.getAppAuthToken();
log.info("第三方授权token: {}", appAuthToken);
request.putOtherTextParam ("app_auth_token", appAuthToken );
//异步回掉地址
request.setNotifyUrl(notifyUrlConfig.getSelf());
//不想自己拼接 json 也可以使用对应的 model: AlipayTradeCreateModel
// 拼接请求 json
request.setBizContent("{" +
"\"out_trade_no\":\""+thirdReq.getOutTradeNo()+"\"," + // 自己生产的订单号
"\"total_amount\":"+realAmount.divide(new BigDecimal(100)).toString()+"," + // 金额
"\"buyer_id\": "+ thirdReq.getBuyerId() + "," + // 购买者id,可以在授权的时候获取
"\"subject\":\""+thirdReq.getSubject()+"\"" + "}"); // 支付标题
try {
AlipayTradeCreateResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 创建订单成功 进行相应操作
// tradeNo 需要给到前端,唤起支付请求
String tradeNo = response.getTradeNo();
log.info("创建当面付订单返回成功:订单编号:{}" , tradeNo);
}else{
// 创建订单失败 进行相应操作
log.info("创建当面付订单返回失败,返回信息:{}" , response.getMsg());
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
buyer_id 在小程序支付中必须传入
退款接口
// 建议对入参进行验证
// 创建退款请求
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
// 拼接退款 json
request.setBizContent("{" +
"\"out_trade_no\":\""+h5Req.getOrderId()+"\"," + // 退款订单号, 建议使用 trade_no
"\"refund_amount\":"+totalAmount.divide(new BigDecimal(100)).toString()+" "+"}"); // 退款金额
// 如果是第三方代商户收款, 需要传入授权token
String appAuthToken = tenantConfig.getAppAuthToken();
request.putOtherTextParam ("app_auth_token", appAuthToken );
try {
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 退款成功之后的相应操作
log.info("退款接口成功返回:{}", response);
}else {
// 退款失败之后的相应操作
log.info("退款接口返回失败:{}", response);
}
} catch (AlipayApiException e) {
e.printStackTrace();
}
订单查询接口
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest();
request.setBizContent("{" +
"\"out_trade_no\":\"20150320010101001\"," +
"\"trade_no\":\"2014112611001004680 073956707\"," +
"\"org_pid\":\"2088101117952222\"," +
" \"query_options\":[" +
" \"trade_settle_info\"" +
" ]" +
" }");
AlipayTradeQueryResponse response = alipayClient.execute(request);
if(response.isSuccess()){
System.out.println("调用成功");
} else {
System.out.println("调用失败");
}
异步回调通知
public String notify(HttpServletRequest request, HttpServletResponse httpServletResponse) {
log.info("-----------支付异步通知----------------");
// 获取支付宝回调通知参数
Map requestParams = request.getParameterMap();
log.info(">>>支付宝回调参数:{}", requestParams);
Map<String, String> params = new HashMap<>();
for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
String name = (String) iter.next();
String[] values = (String[]) 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);
}
log.info(">>>支付宝回调参数解析:{}", params);
try {
// 验签
boolean signVerified = AlipaySignature.rsaCheckV1(params,
mp.getAlipayPublicKey(),
mp.getCharset(),
mp.getSignType());
if (signVerified) {
log.info(">>>支付宝回调签名认证成功");
//商户订单号
String outTradeNo = params.get("out_trade_no");
log.info("商户订单号===================>: {}", outTradeNo);
//阿里订单号
String tradeNo = params.get("trade_no");
log.info("阿里订单号===================>: {}", tradeNo);
//交易状态
String trade_status = params.get("trade_status");
log.info("回调的状态=============> {}", trade_status);
String totalAmount = params.get("total_amount");
BigDecimal a = new BigDecimal(totalAmount);
log.info("总金额(单位:分)=================> {}", totalAmount);
String buyerId = params.get("buyer_id");
log.info("buyerId======================{}", buyerId);
// 支付宝官网说订单状态只要为 TRADE_SUCCESS 即可
if ("TRADE_SUCCESS".equals(trade_status) || "TRADE_FINISHED".equals(trade_status)) {
log.info("-----------^v^支付成功^v^------------");
// 更改订单状态,编写相应逻辑
}
} else {
log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
//return "failure";
}
} catch (AlipayApiException e) {
e.printStackTrace();
log.error(e.getMessage(), e);
log.info("支付宝回调签名认证失败,signVerified=false, params:{}", params);
//return "failure";
}
return "success";
}
支付宝说必须要打印 success ,才会停止发送异步通知,但是我在这边打印了反而还是显示错误.直接返回 string 类型的 success 反而没问题
异步查看回调结果,可以使用云排查
云排查连接
好记性不如烂笔头, 记录 加油