公共配置
引入包:
<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 |
| APPID | APPID 即创建应用后生成 | 获取见上方创建应用 |
| APP_PRIVATE_KEY | 开发者私钥,由开发者自己生成 | 获取见配置密钥 |
| FORMAT | 参数返回格式,只支持 json;默认json | json(固定) |
| CHARSET | 编码集,支持 GBK/UTF-8 | 开发者根据实际工程编码配置 |
| ALIPAY_PUBLIC_KEY | 支付宝公钥,由支付宝生成 | 获取详见配置密钥 |
| SIGN_TYPE | 商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA,推荐使用 RSA2;默认是 RSA | RSA2 |
- 声明发向支付宝的请求 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_no | String | 必选 | 64 | 商户订单号,64个字符以内、可包含字母、数字、下划线;需保证在商户端不重复 | 20150320010101001 |
| product_code | String | 必选 | 64 | 销售产品码,与支付宝签约的产品码名称。注:目前仅支持FAST_INSTANT_TRADE_PAY | FAST_INSTANT_TRADE_PAY |
| total_amount | Price | 必选 | 11 | 订单总金额,单位为元,精确到小数点后两位,取值范围[0.01,100000000]。 | 88.88 |
| subject | String | 必选 | 256 | 订单标题 | Iphone6 16G |
| body | String | 可选 | 128 | 订单描述 | Iphone6 16G |
| timeout_express | String | 可选 | 6 | 该笔订单允许的最晚付款时间,逾期将关闭交易。取值范围:1m~15d。m-分钟,h-小时,d-天,1c-当天(1c-当天的情况下,无论交易何时创建,都在0点关闭)。 该参数数值不接受小数点, 如 1.5h,可转换为 90m | 90m |
业务参数错误:
后端收不到错误信息,错误信息只会显示在前端,对照错误码可差错。
| 错误码 | 错误描述 | 解决方案 |
|---|---|---|
| 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_no | String | 特殊可选 | 64 | 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。trade_no,out_trade_no如果同时存在优先取trade_no | 20150320010101001 |
| trade_no | String | 特殊可选 | 64 | 支付宝交易号,和商户订单号不能同时为空 | 2014112611001004680 073956707 |
| org_pid | String | 可选 | 16 | 银行间联模式下有用,其它场景请不要使用;双联通过该参数指定需要查询的交易所属收单机构的pid; | 2088101117952222 |
| query_options | String[] | 可选 | 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_no | String | 特殊可选 | 64 | 订单支付时传入的商户订单号,不能和 trade_no同时为空。 | 20150320010101001 |
| trade_no | String | 特殊可选 | 64 | 支付宝交易号,和商户订单号不能同时为空 | 2014112611001004680073956707 |
| refund_amount | Price | 必选 | 9 | 需要退款的金额,该金额不能大于订单金额,单位为元,支持两位小数 | 200.12 |
| refund_reason | String | 可选 | 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_no | String | 特殊可选 | 64 | 支付宝交易号,和商户订单号不能同时为空 | 20150320010101001 |
| out_trade_no | String | 特殊可选 | 64 | 订单支付时传入的商户订单号,和支付宝交易号不能同时为空。 trade_no,out_trade_no如果同时存在优先取trade_no | 2014112611001004680073956707 |
| out_request_no | String | 必选 | 64 | 请求退款接口时,传入的退款请求号,如果在退款请求时未传入,则该值为创建交易时的外部交易号 | 2014112611001004680073956707 |
| org_pid | String | 可选 | 16 | 银行间联模式下有用,其它场景请不要使用;双联通过该参数指定需要查询的交易所属收单机构的pid; | 2088101117952222 |
常见错误码:
| 错误码 | 错误描述 | 解决方案 |
|---|---|---|
| ACQ.SYSTEM_ERROR | 系统错误 | 重新发起请求 |
| ACQ.INVALID_PARAMETER | 参数无效 | 检查请求参数,修改后重新发起请求 |
| TRADE_NOT_EXIST | 查询退款的交易不存在 | 确认交易号是否为正确的支付宝交易号,修改后重新查询 |
3、下载账单
调用支付宝接口及对应请求: alipay.data.dataservice.bill.downloadurl.query -----> AlipayDataDataserviceBillDownloadurlQueryRequest
请求参数:
| 参数 | 类型 | 是否必填 | 最大长度 | 描述 | 示例值 |
|---|---|---|---|---|---|
| bill_type | String | 必选 | 10 | 账单类型,商户通过接口或商户经开放平台授权后其所属服务商通过接口可以获取以下账单类型:trade、signcustomer;trade指商户基于支付宝交易收单的业务账单;signcustomer是指基于商户支付宝余额收入及支出等资金变动的帐务账单。 | trade |
| bill_date | String | 必选 | 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 | 统一交易关闭接口 |