支付的大体流程
配置应用、
APPID
注册完成以后添加应用就可以获得,没有可以使用沙箱模式中提供的测试应用
然后根据需求签约功能,开启使用,功能【添加能力】
支付宝网关(固定)
应用网关(可选)
回调地址
支付回调地址
,支付以后,支付宝会将支付结
果进行请求
传达到我们定义的回调地址
之上,这个地址必须是线上我们开发好的一个接口,用以接收支付结果;
商家私钥&支付宝公钥
支付宝采用RSA非对称性加密以保证数据的安全,这里我们可以使用支付宝提供的密钥生成工具进行生成
步骤如下:
如此便得到了应用公钥
以及应用私钥
上面提到的商家私钥
就是应用私钥
这个参数了,两种称呼而已
支付宝公钥
需要使用商家公钥(应用公钥)
进行换取,
商家公钥换取流程:
网页与移动应用–>应用信息–>查看应用公钥–>验证信息
然后在此用我们刚才申请的应用公钥
替换其中的内容,点击确认,此时会出现按钮查看支付宝公钥
点击即可查看
业务对接
这里我们使用电脑pc网页支付以及app支付为例
pc网页支付
Controller部分
/**
* 电脑网页支付
* @throws IOException
* @throws AlipayApiException
*/
@GetMapping("/pcPagePay")
public void pcPagePay() throws IOException, AlipayApiException {
String oderId = UUID.randomUUID().toString();
// 修改为以页面形式进行响应
response.setContentType("text/html;charset=utf-8");
// 获取响应目标
PrintWriter writer = response.getWriter();
// 将生成的支付页面展示给前端页面
writer.write(pcPagePay.creatOder(oderId).getBody());
// 执行关流
flushAndClose(writer);
}
Service部分
/**
* 获取支付页面
*/
public AlipayTradePagePayResponse creatOder(String oderId) throws AlipayApiException {
// 填写基本信息
AlipayClient alipayClient = new DefaultAlipayClient(
payGetWay, // 支付宝网关,注意。沙箱环境的网关和正式环境有所不同,错误的当导致单号无效或者404
appId, // appid就是我们注册应用的appid
appPrivateKey, // app私钥
"json", //
charSet, // 字符集
alipayPublicKey, // 阿里支付公钥
"RSA2" // 加密方式
);
// 创建支付宝交易页面支付请求对象
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
// 填入回调地址,支付成功以后支付结果将会响应到这里
request.setNotifyUrl(notifyUrl);
// 支付成功以后跳转的页面,页面跳转时同时也会携带支付结果参数,可填可不填
request.setReturnUrl("https://www.baidu.com");
// 创建请求体
JSONObject bizContent = new JSONObject();
// 填入商家方的唯一单号,稍后将用以保证订单不重复支付
bizContent.put("out_trade_no", oderId);
// 订单价格,精确到两位
bizContent.put("total_amount", 0.01);
// 商品标题
bizContent.put("subject", "测试商品");
// 产品代码
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");
//bizContent.put("time_expire", "2022-08-01 22:00:00");
商品明细信息,按需传入
//JSONArray goodsDetail = new JSONArray();
//JSONObject goods1 = new JSONObject();
//goods1.put("goods_id", "goodsNo1");
//goods1.put("goods_name", "子商品1");
//goods1.put("quantity", 1);
//goods1.put("price", 0.01);
//goodsDetail.add(goods1);
//bizContent.put("goods_detail", goodsDetail);
扩展信息,按需传入
//JSONObject extendParams = new JSONObject();
//extendParams.put("sys_service_provider_id", "2088511833207846");
//bizContent.put("extend_params", extendParams);
// 最后将信息写入请求对象
request.setBizContent(bizContent.toString());
// 执行请求创建支付页面
AlipayTradePagePayResponse response = alipayClient.pageExecute(request);
if (response.isSuccess()) {
System.out.println("调用成功");
// 调用成功则获得支付页面,其中的body即为页面信息,可以在这里get或者在用的时候再get。万万不可URL转码
return response;
} else {
System.out.println("调用失败");
throw new RuntimeException("支付调用失败");
}
}
此时访问接口即可获取支付页面
APP支付
App支付的基本流程和网页支付差不多,区别就是不用响应页面到前端,我们将获取到的响应信息直接给前端进行响应,前端根据响应体中的包地址拉起支付宝。并附上参数,则可拉取支付信息
代码:
Controller部分
/**
* app支付
* @throws IOException
* @throws AlipayApiException
*/
@GetMapping("/appPay")
public AlipayTradeAppPayResponse appPay() throws IOException, AlipayApiException {
return appPay.creatOder(UUID.randomUUID().toString());
}
Service部分
public AlipayTradeAppPayResponse creatOder(String oderId) throws AlipayApiException {
AlipayClient alipayClient = new DefaultAlipayClient(
payGetWay,appId,appPrivateKey,"json",charSet,alipayPublicKey,"RSA2");
AlipayTradeAppPayRequest request = new AlipayTradeAppPayRequest();
request.setNotifyUrl(notifyUrl);
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", oderId);
bizContent.put("total_amount", 0.01);
bizContent.put("subject", "测试商品");
bizContent.put("product_code", "QUICK_MSECURITY_PAY");
//bizContent.put("time_expire", "2022-08-01 22:00:00");
商品明细信息,按需传入
//JSONArray goodsDetail = new JSONArray();
//JSONObject goods1 = new JSONObject();
//goods1.put("goods_id", "goodsNo1");
//goods1.put("goods_name", "子商品1");
//goods1.put("quantity", 1);
//goods1.put("price", 0.01);
//goodsDetail.add(goods1);
//bizContent.put("goods_detail", goodsDetail);
扩展信息,按需传入
//JSONObject extendParams = new JSONObject();
//extendParams.put("sys_service_provider_id", "2088511833207846");
//bizContent.put("extend_params", extendParams);
request.setBizContent(bizContent.toString());
AlipayTradeAppPayResponse response = alipayClient.sdkExecute(request);
if(response.isSuccess()){
System.out.println("调用成功");
return response;
} else {
System.out.println("调用失败");
throw new RuntimeException();
}
}
参数都一样,就不做注释了,这里会获得一个AlipayTradeAppPayResponse
将对象响应到前端即可完成后端流程;
前端可根据信息拉起支付宝进行支付
支付结果的回调通知
在用户完成支付以后,支付宝会对我们填写的回调地址进行通知请求,我们需要创建我们在回调中填写的接口进行接收参数
接口类型:POST
传参类型:FORMDATA
这里需要对请求进行验签,以保证支付结果的真实性;
验签代码
@PostMapping("/notifyUr")
public void notifyUr() throws AlipayApiException {
// 创建结果集MAP
Map<String, String> params = new HashMap<>();
// 获取form表单参数
Map requestParams = request.getParameterMap();
log.info("回调触发了,请求体:{}", requestParams);
// 遍历Map从新组合写入新Map
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);
}
//切记alipaypublickey是支付宝的公钥,请去open.alipay.com对应应用下查看。
//boolean AlipaySignature.rsaCheckV1(Map<String, String> params, String publicKey, String charset, String sign_type)
boolean flag = AlipaySignature.rsaCheckV1
(
params, // 取出的参数
alipayPublicKey, // 阿里支付公钥
charSet, // 字符集
"RSA2" // 加密方式
);
if (!flag)
throw new RuntimeException("验签未通过");
log.info("验签通过");
// 此时验签通过,params参数里包含了订单的所有参数,可以进行入库,
}
支付完成时接口会被支付宝请求,
我们对其验签以后就可以执行自己的操作了
,
App支付包含一个同步通知,建议还是采用异步通知,同步通知仅作为支付结束的标志;
什么?你问我为啥?支付宝这么说的~