一、支付环境准备
先提一嘴几个重要的参数
- 支付宝的公钥和私钥
- 支付的网关
- 支付的APPID
1、配置沙箱应用环境
1)打开支付宝开放平台,官网:https://open.alipay.com/
2)登录个人账户,然后点击控制台找到里面的沙箱
3)这里能够找到APPID
和支付宝网关地址
和密钥
注意:我们接入的时候最好选择自定义密钥,自定义密钥需要我们下载密钥工具
2、下载密钥工具
下载地址:https://opendocs.alipay.com/common/02kipk?pathHash=0d20b438
1)选择自己的操作系统下载即可,我这里是 Windows
2)下载完成后,生成密钥
3)生成应用公钥和应用私钥
3、配置接口加签方式
1)按步骤 查看 -> 复制刚刚生成的应用公钥到下图 -> 保存
2)然后我们就接入了支付宝开放平台
二、设置内网穿透环境
NATAPP:https://natapp.cn/
1、创建隧道
1)官网右上角注册,先注册账户
2)登录后,购买一个免费隧道
3)购买成功后,会在下图的最下面出现一条刚刚购买的数据
记住这里有个 authtoken,等下有用
2、修改服务器端口号
1)点击右侧的配置
2)改为你后端要提供服务的端口
3、下载客户端
1)点击右上角客户端,下载对应的版本
2)下载完成之后为下图的 natapp.exe
4、运行 natapp.exe
注意:不要直接双击启动
1)我们需要在目录上 输入 cmd,如下图
2)在命令行窗口中输入如下命令
natapp.exe authtoken=你的authtoken
3)启动成功如下图
注:这里的地址会因为网络环境的不同,每次启动该地址都会变化
其实这里就是将项目运行的地址代理到了内网穿透的地址,但是因为每次启动都会变化,所以还是建议使用 localhost:8081
三、实际后端开发
1、引入依赖
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.28.ALL</version>
</dependency>
2、服务端代码配置
接口环境调试接口是,开发者需要调整如下代码配置
- 支付宝网关地址:https://openapi-sandbox.dl.alipaydev.com/gateway.do
- APPID:支付宝开发平台中的APPID
- 签名方式:RSA2
- 应用公钥、应用私钥:存在于 密钥工具中
1)创建沙箱支付配置文件
alipay:
appId: 你的APPID
merchantPrivateKey: 你的应用私钥
alipayPublicKey: 你的应用公钥
notifyUrl: http://内网穿透地址/api/alipay/notify
returnUrl: http://member.zyz.com/memberOrder.html
signType: RSA2
charset: utf-8
# 我的支付宝网关地址
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
2)订单实体类
package com.wei.weiapicommon.model.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 接口次数订单表
* @TableName order
*/
@TableName(value ="`order`")
@Data
public class Order implements Serializable {
/**
* 订单Id
*/
@TableId(type = IdType.ASSIGN_UUID)
private Long id;
/**
* 用户Id
*/
private Long userId;
/**
* 接口Id
*/
private Long interfaceInfoId;
/**
* 支付金额
*/
private Double money;
/**
* 支付方式
*/
private String paymentMethod;
/**
* 0 - 未支付 1 - 已支付
*/
private Integer status;
/**
* 创建时间
*/
private Date createTime;
/**
* 更新时间
*/
private Date updateTime;
/**
* 是否删除
*/
private Integer isDelete;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
这里为了方便测试,就不去调用数据库了
3)创建支付配置类,使用@Value
注解将配置文件中的属性值映射到对应的属性中
package com.wei.project.manager;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.wei.weiapicommon.model.entity.Order;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = "alipay")
@Component
@Data
public class AlipayTemplate {
// 应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
@Value("{alipay.appId}")
public String appId;
// 应用私钥,就是工具生成的应用私钥
@Value("{alipay.merchantPrivateKey}")
public String merchantPrivateKey;
// 支付宝公钥,对应APPID下的支付宝公钥。
@Value("{alipay.alipayPublicKey}")
public String alipayPublicKey;
// 支付宝会悄悄的给我们发送一个请求,告诉我们支付成功的信息
@Value("{alipay.notifyUrl}")
public String notifyUrl;
//同步通知,支付成功,一般跳转到成功页
@Value("{alipay.returnUrl}")
public String returnUrl;
// 签名方式
@Value("{alipay.signType}")
private String signType;
// 字符编码格式
@Value("{alipay.charset}")
private String charset;
//订单超时时间
private String timeout = "1m";
// 支付宝网关;https://openapi-sandbox.dl.alipaydev.com/gateway.do
@Value("{alipay.gatewayUrl}")
public String gatewayUrl;
public String pay(Order order) throws
AlipayApiException {
//1、根据支付宝的配置生成一个支付客户端
AlipayClient alipayClient = new
DefaultAlipayClient(gatewayUrl, appId, merchantPrivateKey,
"json", charset, alipayPublicKey, signType);
//2、创建一个支付请求,并设置请求参数
AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
alipayRequest.setReturnUrl(returnUrl);
alipayRequest.setNotifyUrl(notifyUrl);
Long id = order.getId();
Long interfaceInfoId = order.getInterfaceInfoId();
Double money = order.getMoney();
String paymentMethod = order.getPaymentMethod();
alipayRequest.setBizContent(" {\"out_trade_no\":\"" + id + "\","
+ "\"total_amount\":\"" + money + "\","
+ "\"subject\":\"" + interfaceInfoId
+ "\","
+ "\"body\":\"" + paymentMethod + "\","
+
"\"timeout_express\":\"" + timeout + "\","
+
"\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
String result = alipayClient.pageExecute(alipayRequest).getBody();
//会收到支付宝的响应,响应的是一个页面,只要浏览器显示这个页面,就会自动来到支付宝的收银台页面
System.out.println("支付宝的响应:" + result);
return result;
}
}
4)调用支付接口
package com.wei.project.controller;
import cn.hutool.core.bean.BeanUtil;
import com.alipay.api.AlipayApiException;
import com.alipay.easysdk.factory.Factory;
import com.wei.project.manager.AlipayTemplate;
import com.wei.project.mapper.OrderMapper;
import com.wei.project.model.dto.order.OrderRequest;
import com.wei.project.test.paymentbox.PayVO;
import com.wei.weiapicommon.model.entity.Order;
import org.springframework.web.bind.annotation.*;
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.util.HashMap;
import java.util.Map;
/**
* 支付宝接口
*/
@RestController
@RequestMapping("/alipay")
public class AliPayController {
@Resource
AlipayTemplate alipayTemplate;
@GetMapping(value = "/pay", produces = "text/html")
@ResponseBody
public String pay(@RequestParam long id) throws AlipayApiException {
Order order = new Order();
order.setId(120948748372234L);
order.setUserId(129904058947L);
order.setInterfaceInfoId(294389472934L);
order.setMoney(10.0);
order.setPaymentMethod("支付宝");
return alipayTemplate.pay(order);
}
@PostMapping("/notify") // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
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));
// System.out.println(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"));
// 更新订单状态
}
}
return "success";
}
}
3、前端请求
1)前端通过传入订单 id 的方式去支付订单
注意:订单号必须唯一
const toPayment = async () => {
window.open("http://localhost:8081/api/alipay/pay?id=1")
};
访问地址:http://localhost:8081/api/alipay/pay?id=100
2)弹出支付宝登录页面
3)来到支付宝开放平台,找到买家信息,登录进行支付
4)确认支付
5)支付成功
6)支付成功后,对比商家信息和买家信息中的账户余额