支付宝官方sdk笔记

公共配置

引入包:

<dependency>   
    <groupId>com.alipay.sdk</groupId>   
    <artifactId>alipay-sdk-java</artifactId>   
    <version>3.0.0</version> 
</dependency>

Alipay几个重要的对象:

  • AlipayClient 接口

    • 声明了调用各种请求的方法。

    • 主要实现类:DefaultAlipayClient

    • 实现类实现了接口中的各个方法

    • 主要封装支付请求的公共参数,如请求网关,签名等信息。

    • 主要方法:

      • excute(AlipayRequest request):发起请求
      • pageExcute(AlipayRequest request):网页支付的请求
  • AlipayRequest 接口

    • 声明了一些参数的get 和 set 方法

    • 主要实现类:AlipayTrade***Request

      • 封装了各个请求的业务参数。
    • 主要方法:

      • setBizContent(String jsonContent):设置请求的业务参数
      • setNotifyUrl(String url):设置异步通知的地址
      • setReturnUrl(String url):设置同步通知的地址
  • AlipayResponse 类

    • 声明了返回的 code,错误信息 和一些返回参数

    • 主要子类:AlipayTrade***Response

      • 提供了对各类请求的返回数据进行处理的方法
    • 主要方法:

      • getSubCode:获取错误代码(官网上可对照,以ACQ开头)

      • getMsg:获取错误原因

      • getBody:获取返回内容,封装了响应内容

      • getParams:获取传入的请求业务参数

      • isSuccess:判断本次请求是否调用成功。是判断 subCode 是否为空
        在这里插入图片描述
        配置支付宝参数:

// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号 
public static String APP_ID = "20132101000652145"; 
// 商户私钥,您的PKCS8格式RSA2私钥 
public static String MERCHANT_PRIVATE_KEY = ""; 
// 支付宝公钥,查看地址:https://openhome.alipay.com/platform/keyManage.htm 对应APPID下的支付宝公钥。 
public static String ALIPAY_PUBLIC_KEY = ""; 
/** * 异步通知,这里我们设计自己的后台代码 */ 
public static String notify_url = "http://127.0.0.1:8003/order/notifyUrl"; 
// 页面跳转同步通知页面路径 需http://格式的完整路径,不能加?id=123这类自定义参数,必须外网可以正常访问
public static String return_url = "http://127.0.0.1:8003/order/returnUrl"; 
// 签名方式 
public static String SIGN_TYPE = "RSA2"; 
// 字符编码格式 
public static String CHARSET = "utf-8"; 
// 支付宝网关 
public static String GATEWAYURL = "https://openapi.alipaydev.com/gateway.do";
public static String SUBJECT = "我的订单";

使用流程(以电脑网站发起支付请求为例):

  • 初始化一个 AlipayClient客户端
AlipayClient alipayClient = new DefaultAlipayClient(URL,APP_ID,APP_PRIVATE_KEY,FORMAT,CHARSET,ALIPAY_PUBLIC_KEY,SIGN_TYPE);
配置参数示例值解释获取方式/示例值
URL支付宝网关(固定)https://openapi.alipay.com/gateway.do
APPIDAPPID 即创建应用后生成获取见上方创建应用
APP_PRIVATE_KEY开发者私钥,由开发者自己生成获取见配置密钥
FORMAT参数返回格式,只支持 json;默认jsonjson(固定)
CHARSET编码集,支持 GBK/UTF-8开发者根据实际工程编码配置
ALIPAY_PUBLIC_KEY支付宝公钥,由支付宝生成获取详见配置密钥
SIGN_TYPE商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2;默认是 RSARSA2
  • 声明发向支付宝的请求 request
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); 
//设置请求的同步返回地址 
alipayRequest.setReturnUrl(AlipayConfig.return_url); 
//设置请求的异步返回地址 
alipayRequest.setReturnUrl(AlipayConfig.notify_url); 
//设置业务请求参数,方式1(推荐)
AlipayTradePagePayModel model = new AlipayTradePagePayModel();
model.setOutTradeNo("xxxxx");
model.setTotalAmount("33.2");
alipayRequest.setBizModel(model);
//设置业务请求参数 ,方式2
alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","       
                            + "\"total_amount\":\"" + totalAmount + "\","       
                            + "\"subject\":\"" + subject + "\","      
                            + "\"body\":\"商品名称\","       
                            + "\"timeout_express\":\"90m\","      
                            + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); 
//执行request获得结果,会获取到一个form 表单,前端只需将form 表单提交就可跳转到支付宝支付 
String result = alipayClient.pageExecute(alipayRequest).getBody(); AlipayTradeRefundRequest alipayRequest = new AlipayTradeRefundRequest(); Order orderByOrderId = orderService.getOrderByOrderId(outTradeNo); /** 调取接口*/ alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","       
        + "\"refund_amount\":\"" + orderByOrderId.getOrderPrice() + "\","       
        + "\"refund_reason\":\"" + "不想要了" + "\","      
        + "\"out_request_no\":\"" + outTradeNo + "\"}");

电脑网站支付

1、发起支付:

1.1、支付请求

调用支付宝接口及对应请求:alipay.trade.page.pay -----> AlipayTradePagePayRequest

在这里插入图片描述

注意:

  • 支付结果必须以异步通知、查询结果为准
  • 收到结果后必须验签
  • 验签通过后,要对比请求中的 app_id、out_trade_no、total_amout与之前请求的是否一致
  • out_trade_no 为本地上传的订单号,必须保证不可重复

请求参数说明:

参数类型是否必填最大长度描述示例值
out_trade_noString必选64商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复20150320010101001
product_codeString必选64销售产品码,与支付宝签约的产品码名称。注:目前仅支持FAST_INSTANT_TRADE_PAYFAST_INSTANT_TRADE_PAY
total_amountPrice必选11订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]。88.88
subjectString必选256订单标题Iphone6 16G
bodyString可选128订单描述Iphone6 16G
timeout_expressString可选6该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m90m

业务参数错误:

后端收不到错误信息,错误信息只会显示在前端,对照错误码可差错。
在这里插入图片描述

常见错误码

错误码错误描述解决方案
ACQ.SYSTEM_ERROR接口返回错误请立即调用查询订单API,查询当前订单的状态,并根据订单状态决定下一步的操作,如果多次调用依然报此错误码,请联系支付宝客服。
ACQ.INVALID_PARAMETER参数无效检查请求参数,修改后重新发起请求
ACQ.ACCESS_FORBIDDEN无权限使用接口未签约条码支付或者合同已到期
ACQ.PARTNER_ERROR应用APP_ID填写错误联系支付宝小二点这里,确认APP_ID的状态
ACQ.TOTAL_FEE_EXCEED订单总金额不在允许范围内修改订单金额再发起请求

公共参数错误:

在这里插入图片描述

  • 私钥或公钥配置错误(直接报错)
    在这里插入图片描述

编码步骤

发起支付请求:

//1、封装client客户端 
DefaultAlipayClient alipayClient = new DefaultAlipayClient(AlipayConfig.GATEWAYURL, AlipayConfig.APP_ID, AlipayConfig.MERCHANT_PRIVATE_KEY, "json", AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGN_TYPE); 
//2、封装 Request 
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest(); alipayRequest.setNotifyUrl(AlipayConfig.notify_url); alipayRequest.setReturnUrl(AlipayConfig.return_url); 
alipayRequest.setBizContent("{\"out_trade_no\":\"" + outTradeNo + "\","    
                            + "\"total_amount\":\"" + totalAmount + "\","    
                            + "\"subject\":\"" + subject + "\","    
                            + "\"body\":\"商品名称\","   
                            + "\"timeout_express\":\"90m\","    
                            + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}"); 
//3、封装 Response,也就是返回给前端的数据。此 Response 是ali sdk封装的 
AlipayTradePagePayResponse payResponse = alipayClient.pageExecute(alipayRequest); 
//4、获取 responseBody 返回给前端即可
String responseBody = payResponse.getBody();

支付宝的支付时序图感觉不是很清楚,所以我就自己画了一个。
而且在支付宝发起电脑网页,手机网页支付的请求是,后端发起的Request并未真正发起请求,只是将所有请求参数封装成了表单,然后将表单返回给前端,由前端提交表单,才会跳转到支付页面。

在这里插入图片描述

  • 支付页面
    在这里插入图片描述

支付发起请求后返回的表单:

<form name='punchout_form' method='post'
      action='https://openapi.alipaydev.com/gateway.do'>  
    <input type='hidden' name='biz_content' value=''>  
    <input type='submit' value='立即支付' style='display:none' > 
</form> 
<script>document.forms[0].submit();</script>
  • biz_content 的内容为上面封装 AlipayTradePagePayRequest 时设置的请求参数。

  • action 的URL后面还会加上配置的公共参数,以及请求的接口。会将下面的封装成请求参数并进行url编码后加到网关地址的后面

charset=utf-8 
method=alipay.trade.page.pay
sign=签名 
return_url=http://127.0.0.1:8003/order/returnUrl 
notify_url=http://127.0.0.1:8003/order/notifyUrl 
version=1.0 
app_id=2016101000652345 
sign_type=RSA2 
timestamp=2019-12-19 14:18:38 
alipay_sdk=alipay-sdk-java-dynamicVersionNo 
format=json

1.2、支付校验

在设置的同步、异步返回的url所对应的 Controller 中解析 Request作用域即可。以异步校验为准

对返回结果进行验签:

//支付返回结果都封装在 Request 作用域中。所以要对 request 进行解析 
Map<String, String[]> requestParams = request.getParameterMap(); 
for (String name : requestParams.keySet()) {    
    String[] values = requestParams.get(name);    
    String valueStr = "";    
    for (int i = 0; i < values.length; i++) {        v
        alueStr = (i == values.length-1) ? valueStr+values[i] : valueStr+values[i] + ",";  		}    
    params.put(name, valueStr); 
} 
//验签 
boolean signVerified = AlipaySignature.rsaCheckV1(params, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.CHARSET, AlipayConfig.SIGN_TYPE); 
if (signVerified) {    
    // TODO 验签成功后,按照支付结果异步通知中的描述,对支付结果中的业务内容进行二次校验,校验成功后在response中返回success并继续商户自身业务处理,校验失败返回failure 
}else{    
    // TODO 验签失败则记录异常日志,并在response中返回failure. 
}
//同步返回结果信息 
{    
    charset=utf-8,     
    out_trade_no=12019122014253806498300476623439, 
    method=alipay.trade.page.pay.return,     
    total_amount=38.70,     
    sign=xxxxxx,     
    trade_no=2019122022001483381000111417,   
    auth_app_id=2016101000652145,    
    version=1.0,   
    app_id=2016101000652145,   
    sign_type=RSA2xxxxx,     
    seller_id=2088102178915714,    
    timestamp=2019-12-20 14:34:09 
}

1.3、支付查询

调用支付宝接口及对应请求:alipay.trade.query-----> AlipayTradeQueryRequest

请求参数

参数类型是否必填最大长度描述示例值
out_trade_noString特殊可选64订单支付时传入的商户订单号,和支付宝交易号不能同时为空。trade_no,out_trade_no如果同时存在优先取trade_no20150320010101001
trade_noString特殊可选64支付宝交易号,和商户订单号不能同时为空2014112611001004680 073956707
org_pidString可选16银行间联模式下有用,其它场景请不要使用;双联通过该参数指定需要查询的交易所属收单机构的pid;2088101117952222
query_optionsString[]可选10查询选项,商户通过上送该字段来定制查询返回信息TRADE_SETTLE_INFO

代码示例:

AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key","RSA2"); 
AlipayTradeQueryRequest request = new AlipayTradeQueryRequest(); 
request.setBizContent("{" + 
                      "    \"out_trade_no\":\"20150320010101001\"," + 
                      "    \"trade_no\":\"2014112611001004680 073956707\"" + "  }"); 
AlipayTradeQueryResponse response = alipayClient.execute(request); if(response.isSuccess()){   
    System.out.println("调用成功"); 
} else {    
    System.out.println("调用失败");
}
//查询结果信息,如果失败会携带 sub_code,包含错误码
{    
    "alipay_trade_query_response":{       
        "code":"10000",     
        "msg":"Success",      
        "buyer_logon_id":"gtd***@sandbox.com",     
        "buyer_pay_amount":"0.00",     
        "buyer_user_id":"2088102178983386",    
        "buyer_user_type":"PRIVATE",   
        "invoice_amount":"0.00",       
        "out_trade_no":"12019122010290014797630089677739",     
        "point_amount":"0.00",      
        "receipt_amount":"0.00",    
        "send_pay_date":"2019-12-20 11:42:49",   
        "total_amount":"38.70",  
        "trade_no":"2019122022001483381000108109",    
        "trade_status":"TRADE_SUCCESS" 
    }
}
错误码错误描述解决方案
ACQ.SYSTEM_ERROR系统错误重新发起请求
ACQ.INVALID_PARAMETER参数无效检查请求参数,修改后重新发起请求
ACQ.TRADE_NOT_EXIST查询的交易不存在检查传入的交易号是否正确,修改后重新发起请求

2、退款

调用支付宝接口及对应请求:alipay.trade.refund -----> AlipayTradeRefundRequest

在这里插入图片描述

注意:

  • 同步返回结果也是准确的。

请求参数:

参数类型是否必填最大长度描述示例值
out_trade_noString特殊可选64订单支付时传入的商户订单号,不能和 trade_no同时为空。20150320010101001
trade_noString特殊可选64支付宝交易号,和商户订单号不能同时为空2014112611001004680073956707
refund_amountPrice必选9需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数200.12
refund_reasonString可选256退款的原因说明正常退款

代码示例:

AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do","app_id","your private_key","json","GBK","alipay_public_key"); 
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest(); request.setBizContent("{" + "    \"out_trade_no\":\"20150320010101001\","                                           + "    \"trade_no\":\"2014112611001004680073956707\","                                   + "    \"refund_amount\":200.12,"                                                   + "    \"refund_reason\":\"正常退款\","                                                  + "    \"out_request_no\":\"HZ01RF001\","                                                    + "    \"operator_id\":\"OP001\","                                                       + "    \"store_id\":\"NJ_S_001\","                                                          + "    \"terminal_id\":\"NJ_T_001\""                                                                               + "  }"); 
AlipayTradeRefundResponse response = alipayClient.execute(request); if(response.isSuccess()){ 
    System.out.println("调用成功");
} else { 
    System.out.println("调用失败"); 
}

常见错误码:

错误码错误描述解决方案
ACQ.SYSTEM_ERROR系统错误请使用相同的参数再次调用
ACQ.INVALID_PARAMETER参数无效请求参数有错,重新检查请求后,再调用退款
ACQ.SELLER_BALANCE_NOT_ENOUGH卖家余额不足商户支付宝账户充值后重新发起退款即可
ACQ.REFUND_AMT_NOT_EQUAL_TOTAL退款金额超限检查退款金额是否正确,重新修改请求后,重新发起退款
ACQ.REASON_TRADE_BEEN_FREEZEN请求退款的交易被冻结联系支付宝小二,确认该笔交易的具体情况
ACQ.TRADE_NOT_EXIST交易不存在检查请求中的交易号和商户订单号是否正确,确认后重新发起

退款查询:

调用支付宝接口及对应请求:alipay.trade.fastpay.refund.query -----> AlipayTradeFastpayRefundQueryRequest

请求参数:

参数类型是否必填最大长度描述示例值
trade_noString特殊可选64支付宝交易号,和商户订单号不能同时为空20150320010101001
out_trade_noString特殊可选64订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no如果同时存在优先取trade_no2014112611001004680073956707
out_request_noString必选64请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号2014112611001004680073956707
org_pidString可选16银行间联模式下有用,其它场景请不要使用;双联通过该参数指定需要查询的交易所属收单机构的pid;2088101117952222

常见错误码:

错误码错误描述解决方案
ACQ.SYSTEM_ERROR系统错误重新发起请求
ACQ.INVALID_PARAMETER参数无效检查请求参数,修改后重新发起请求
TRADE_NOT_EXIST查询退款的交易不存在确认交易号是否为正确的支付宝交易号,修改后重新查询

3、下载账单

调用支付宝接口及对应请求: alipay.data.dataservice.bill.downloadurl.query -----> AlipayDataDataserviceBillDownloadurlQueryRequest

请求参数:

参数类型是否必填最大长度描述示例值
bill_typeString必选10账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型:trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单。trade
bill_dateString必选15账单时间:日账单格式为yyyy-MM-dd,最早可下载2016年1月1日开始的日账单;月账单格式为yyyy-MM,最早可下载2016年1月开始的月账单。2016-04-05
AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", APP_ID, APP_PRIVATE_KEY, "json", CHARSET, ALIPAY_PUBLIC_KEY, "RSA2"); 
//获得初始化的
AlipayClient AlipayDataDataserviceBillDownloadurlQueryRequest request = new AlipayDataDataserviceBillDownloadurlQueryRequest();
//创建API对应的request类 
request.setBizContent("{" + "    \"bill_type\":\"trade\"," +  //账单类型,必填 " 
                      \"bill_date\":\"2016-04-05\"" //账单时间,获取多少时间以后的账单 
                      "}");
//设置业务参数 
AlipayDataDataserviceBillDownloadurlQueryResponse response = 	alipayClient.execute(request); 
System.out.print(response.getBody()); //根据response中的结果继续业务逻辑处理

错误码(全部):

错误码错误描述解决方案
INVAILID_ARGUMENTS入参不合法确认参数后重新查询
BILL_NOT_EXIST账单不存在确认参数后重新查询
UNKNOWN_ERROR未知错误稍后重试或联系小二排查问题

常用接口:

API列表描述
alipay.trade.create支付订单创建接口,线上支付一般不用管,这个接口是用于线下用户端发起调用的。
alipay.trade.pay当面付支付接口
alipay.trade.page.pay电脑网站下单并支付页面接口(pageExecute调用)
alipay.trade.wap.pay手机网站支付接口(pageExecute调用)
alipay.trade.app.pay手机 app 支付接口
alipay.trade.query统一支付交易查询接口
alipay.trade.refund统一交易退款接口
alipay.trade.fastpay.refund.query统一交易退款查询接口
alipay.trade.query统一支付交易查询接口
alipay.trade.refund统一交易退款接口
alipay.trade.fastpay.refund.query统一交易退款查询接口
alipay.trade.close统一交易关闭接口

版权声明:本文为qq_35751014原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。