支付宝 - 支付接口沙箱接入

[toc]

零、资料

一、通用的环境搭建

NatAPP 实现内网穿透

(1)进入NatAPP 官网,实名注册,购买免费线路(最多2条免费),把本地线路的端口改为项目的端口8080,记录下authToken

(2)下载内网穿透工具:NATAPP-内网穿透 基于ngrok的国内高速内网映射工具

(3)在下载好的软件的start.bat内,末尾加上刚才复制的authToken

(4)双击运行start.bat文件,启动内网穿透,记录下Fordwarding这一行的URL用于配置支付宝的回调地址notify_url

1
natapp.exe -authtoken=网站里的authToken

二、简易版

1、导入 Maven 依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
<!--        支付宝-完整版-->
<!-- <dependency>-->
<!-- <groupId>com.alipay.sdk</groupId>-->
<!-- <artifactId>alipay-sdk-java</artifactId>-->
<!-- <version>4.33.12.ALL</version>-->
<!-- </dependency>-->

<!-- 支付宝-简易版-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.2.0</version>
</dependency>

2、编写配置文件

1
2
3
4
5
6
7
8
alipay:
# 支付接口请求的地址
gateway: https://openapi.alipay.com/gateway.do
appId: 你的appId
appPrivateKey: 你的app私钥地址
alipayPublicKey: 你的支付宝公钥地址
notifyUrl: 你刚才记录的内网穿透地址

3、编写配置类

(1)封装前端的请求参数的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@AllArgsConstructor
@NoArgsConstructor
public class AlipayObj {
private String outTradeNo;
private String totalAmount;
private String subject;
private String productCode;
}

(2)封装前端的请求参数的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
package com.cyw.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
public String appId;
public String appPrivateKey;
public String alipayPublicKey;
public String gateway ;
public String notifyUrl;
public String return_url;
public String charset = "UTF-8";
public String format = "json";
public String logPath = "/log";
public String signType = "RSA2";


@PostConstruct
public void init() {
// 设置参数(全局只需设置一次)
Config config = new Config();
config.protocol = "http";
config.gatewayHost = "openapi.alipay.com";
config.signType = "RSA2";
config.appId = this.appId;
config.merchantPrivateKey = this.appPrivateKey;
config.alipayPublicKey = this.alipayPublicKey;
config.notifyUrl = this.notifyUrl;
Factory.setOptions(config);
System.out.println("=======支付宝SDK初始化成功=======");
}

}

4、接口使用

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package com.cyw.controller;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.cyw.pojo.AlipayObj;
import com.cyw.pojo.Rst;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;

/**
* @author cyw
*/
@RestController
@RequestMapping("/alipay")
public class AliPayController {

@GetMapping("/pay")
public Rst pay(AlipayObj alipayObj){
AlipayTradePagePayResponse response;
try {
// 发起API调用(以创建当面付收款二维码为例)
response = Factory.Payment.Page()
.pay(URLEncoder.encode(alipayObj.getSubject(), "UTF-8"),
alipayObj.getOutTradeNo(),
alipayObj.getTotalAmount(),
"");
} catch (Exception e) {
System.err.println("调用遭遇异常,原因:" + e.getMessage());
throw new RuntimeException(e.getMessage(), e);
}
return Rst.ok("支付成功!",response.getBody());
}


@PostMapping("/notify")
public Rst notify(HttpServletRequest request) throws Exception {
if ("TRADE_SUCCESS".equals(request.getParameter("trade_status"))) {
System.out.println("=========支付宝异步回调========");

Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}

String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
// 支付宝验签
if (Factory.Payment.Common().verifyNotify(params)) {
// 验签通过
System.out.println("交易名称: " + params.get("subject"));
System.out.println("交易状态: " + params.get("trade_status"));
System.out.println("支付宝交易凭证号: " + params.get("trade_no"));
System.out.println("商户订单号: " + params.get("out_trade_no"));
System.out.println("交易金额: " + params.get("total_amount"));
System.out.println("买家在支付宝唯一id: " + params.get("buyer_id"));
System.out.println("买家付款时间: " + params.get("gmt_payment"));
System.out.println("买家付款金额: " + params.get("buyer_pay_amount"));

// 更新订单,未支付 =》已支付
System.out.println("将未支付的订单改为已支付!");
}
}
return Rst.ok("支付成功-返回通知");
}


}

5、测试

url请求的地址:

1
2
3
4
5
6
http://localhost:8080/alipay/pay?outTradeNo=12220
&totalAmount=240
&subject=zs
&productCode=iphone

// http://localhost:8080/alipay/pay?outTradeNo=12220&totalAmount=240&subject=zs&productCode=iphone

商家账号:

1
2
3
商户账号:rshfvw6245@sandbox.com
登录密码:111111
商户PID:2088102181149041

顾客账号:

1
2
3
4
5
买家账号:fgrotp0827@sandbox.com
登录密码:111111
支付密码:111111
用户UID:2088622954862264
用户名称:fgrotp0827

6、每次打开需要修改:

  • 打开NatApp
  • 将NatAPP的转发地址复制到项目的支付配置notifyUrl配置中
  • 将NatAPP的转发地址复制到支付宝官网的沙箱配置notifyUrl配置中

三、通用版