一、生成秘钥

1.1 登录平台

登录支付宝开放平台:https://open.alipay.com/
完善账户信息后;
1)点击控制台:

2)找到开发工具推荐,控制台下方的沙箱:

3)进入如下页面;

1.2 生成秘钥

注意:生成秘钥方式只要选择一种即可,“系统默认秘钥”比较简单,自定义秘钥需要使用工具生成;

1.2.1 系统默认秘钥

(这是第一种方式)

点击“查看”,可以看到如下界面;
这个 “应用私钥” 和 “支付宝公钥” 在之后的步骤中需要配置到Java程序

1.2.2 自定义秘钥

这是第二种方式:这个步骤需要生成工具!!!
二选一即可,此种方式暂时可以不用

点击“自定义秘钥”

下载秘钥生成工具


安装成功之后,点击生成秘钥

回到沙箱应用,填入公钥并确定完成;

注意:↑ 这个页面的网关地址和授权回调地址填入:https://www.alipay.com
点击上图的”设置并查看” 填入自己本地的“应用公钥”,就可以得到”支付宝公钥“;
这个”支付宝公钥“ 和 保存在我们本地的“应用私钥” 就是我们要配置到Java程序中的。

在沙箱账号中支付宝给我们提供了商家和买家账号:在支付环节需要用到

1.3 开发文档
可以参考官方文档进行调试(此步非必须,可以直接跳到 二、配置环境)

二、配置环境

2.1 沙箱环境准备

登录沙箱地址

保证接口加签方式已经启用:

官方文档

账号准备

2.2 内网穿透工具

注册一个账号,后期会要求实名认证,照做即可。

购买穿透隧道,可以选择免费一个月的。


购买成功后看下面的列表,点击配置:

会有生成认证令牌:复制并保存
注意:端口改为此时正在启动服务的端口,比如现在IDEA的Springboot项目中 tomcat使用的是9999端
口,则此时这里本地端口要改为9999


在官网右上角点击下载客户端工具: 根据你电脑情况选择合适的版本下载,这里我选用Windows64位


客户端启动需要一个config.ini文件,放到和下载的客户端natapp.exe文件同一个文件夹下,authtoken
的值粘贴为之前这里复制的令牌:



启动客户端:windows下,直接双击natapp.exe 即可。红框内就是我们的隧道通信地址。

注意:每次启动客户端都会分配一个新的隧道地址:要注意后期更换程序中配置 的地址。
测试:此时 这个穿透地址是临时域名就是代表了本地应用程序的访问地址http://localhost:9999
可以直接使用此域名来访问应用程序下的任意一个接口,如能访问,则环境OK。
比如: 我现在springboot应用启动了,那么输入这个临时域名 + 访问资源路径:
http://f55v9f.natappfree.cc/user/findAll 查询所有用户,能正常访问,就是测试成功!

三、Java程序配置

3.1 添加依赖

刷新maven,直到把资源下载下来为止。 也可以选择其他版本

1
2
3
4
5
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.13.ALL</version>
</dependency>

3.2 配置 application.yml

增加如下信息:

1
2
3
4
5
6
alipay:
appId: 这里配置的是“沙箱应用”中的APPID号,如下图
appPrivateKey: 配置应用私钥,之前有获得过
alipayPublicKey: 配置“支付宝公钥”,之前有获得过,注意:不是“应用公钥”
notifyUrl: 你自己的隧道通信地址/alipay/notify
# 比如我这里配置为: http://muaqx9.natappfree.cc/alipay/notify

配置成这样:

3.3 编写Java程序

1)新Alipay类,用于前后端交互,注意加上@Data注解(或者自行加上 gettersetter 也可以)

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @ClassName 和阿里交互的对象(用于前端和后端交互,字段名最好严格按照规范)
* @Author 小温哥 @Version 1.0
* 功能说明:
**/
@Data
public class AliPay {
private String traceNo; //我们的订单号
private Double totalAmount; //总金额
private String subject; //主题
private String alipayTraceNo;//阿里的流水号
}

2)新增AlipayConfig配置类,增加如下注解,读取yaml中关于alipay的配置信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @ClassName
* @Author 小温哥 @Version 1.0
* 功能说明:
**/
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AlipayConfig {
private String appId;
//应用私钥
private String appPrivateKey;
//阿里公钥
private String alipayPublicKey;
//阿里调用我们的地址【内网穿透】
private String notifyUrl;
}

如果这个类的上方有警告关于注解处理器配置问题,则增加依赖并刷新maven:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
</dependency>

3)编写控制器类AlipayController

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
package com.cykj.controll;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipaySignature;
import com.alipay.api.request.AlipayTradePagePayRequest;
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.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* @ClassName
* @Author 小温哥 @Version 1.0
* 功能说明:
**/
@RestController
@RequestMapping("/alipay")
public class AliPayController {
//阿里网关地址
private static final String GATEWAY_URL =
"https://openapi.alipaydev.com/gateway.do";
//数据格式
private static final String FORMAT = "JSON";
//编码格式
private static final String CHARSET = "UTF-8";
//签名方式
private static final String SIGN_TYPE = "RSA2";
@Resource
private AlipayConfig alipayConfig;


@GetMapping("/pay") // ?subject=xxx&traceNo=xxx&totalAmount=xxx
public void pay(AliPay aliPay, HttpServletResponse response) throws
IOException {
System.out.println(aliPay);
System.out.println("alipayConfig:" + alipayConfig);
//1.创建client,通过阿里SDK提供的client,负责调用支付宝的API
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,
alipayConfig.getAppId(),
alipayConfig.getAppPrivateKey(),
FORMAT,
CHARSET,
alipayConfig.getAlipayPublicKey(),
SIGN_TYPE);
//2.创建request,并设置request参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(alipayConfig.getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.put("out_trade_no", aliPay.getTraceNo());//我们自己生成的订单编号
bizContent.put("total_amount", aliPay.getTotalAmount());//订单总金额
bizContent.put("subject", aliPay.getSubject());//支付名称
bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");//固定配置
request.setBizContent(bizContent.toString());
//执行请求,拿到响应的结果,返回给浏览器
String form = "";
try {
form = alipayClient.pageExecute(request).getBody();//调用SDK生成表单
} catch (AlipayApiException e) {
e.printStackTrace();
}
//设置响应结果,将返回的内容写出到浏览器
response.setContentType("text/html;charset=" + CHARSET);
response.getWriter().write(form);//直接将完整的表单html输出到页面
response.getWriter().flush();
response.getWriter().close();
}
/**
* 支付宝异步回调【必须是POST】
*
* @return
*/
@PostMapping("/notify")
public String payNotify(HttpServletRequest request) throws
AlipayApiException {
System.out.println("异步回调了。" + request);
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("-------------支付宝异步回调----");
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
System.out.println("-----params-----------");
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
System.out.println(name + " " + request.getParameter(name));
}
String outTradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");//支付时间
String alipayTradeNo = params.get("trade_no");
String sign = params.get("sign");//拿到签名
String content = AlipaySignature.getSignCheckContentV1(params);
boolean checkSignature = AlipaySignature.rsa256CheckContent(content,
sign,
alipayConfig.getAlipayPublicKey(),
"UTF-8");//验证签名
//支付宝验签
if (checkSignature) {
//验签通过
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"));
// 查询订单
//TODO 支付成功,操作数据库,创建对应订单,修改对应商品数据
}
}
return "success";
}
}






四、前端程序编写

新建Alipay.vue,并且给他配置对应的路由。

因为支付宝给我们返回的数据是一个form表单,所以我们直接以form表单中的a标签进行提交:

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

<template>
<div>
<h3>测试支付宝支付</h3>
<el-form label-width="80px" :model="aliPay">
<el-form-item label="订单id">
<el-input v-model="aliPay.traceNo" ></el-input>
</el-form-item>
<el-form-item label="订单价格">
<el-input v-model="aliPay.totalAmount" ></el-input>
</el-form-item>
</el-form>
<a :href="payURL">确定支付</a>
</div>
</template>
<script>
export default {
data() {
return {
// 提交的流水和金额
aliPay: {
traceNo: "",
totalAmount: 0.0
},
};
},
// 计算属性
computed:{
payURL:function(){
return "http://localhost:9999/alipay/pay?subject=收购阿里&traceNo=" +
this.aliPay.traceNo + "&totalAmount=" + this.aliPay.totalAmount
}
}
};
</script>

点击支付:

五、沙箱支付宝付款

沙箱环境是模拟环境,所以要使用沙箱版支付宝进行支付,下载安装:

此时回到
\

回到沙箱账号充钱!!

打开沙箱支付宝客户端,输入买家账号和密码,
打开“沙箱支付宝”, 登录方式选择“ 其他方式登录”

然后扫支付二维码: