支付沙箱实验
一.入门
1.1 准备工作
登录官方网址,进入控制台
https://open.alipay.com/
1.2 密钥准备
点击上图中的【设置并查看】,会出来下图
此时需要下载 密钥工具,下载网址:https://opendocs.alipay.com/common/02kipk?pathHash=0d20b438
将密钥工具的生成的【应用公钥】填写到沙箱环境中,自动生成支付宝公钥
1.3 设置内网穿透
https://natapp.cn/
进入网址,完成注册、登录、实名认证
购买一个隧道(有免费的就有免费的)
进入刚才购买的隧道,进行配置
下载好客户端后,不要双击启动,用cmd命令行的方式打开
打开命令行窗口后,输入
natapp.exe -authtoken=your_authtoken
启动成功
1.4 SpringBoot集成
目录结构
【引入依赖】
<!--支付宝相关-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.9.28.ALL</version>
</dependency>
<!--支付宝依赖沙箱支付-->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-easysdk</artifactId>
<version>2.2.0</version>
</dependency>
如果报错控制台,导入以下依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-configuration-processor
</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>
mybatis-plus-boot-starter</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
【yml配置文件】
server:
port: 80
alipay:
# 支付宝应用ID
appId: 支付宝应用ID
# 商户私钥
merchantPrivateKey: 应用私钥
# 支付宝公钥
alipayPublicKey: 支付宝公钥
# 支付完成后的异步通知地址,用于接收支付结果通知
notifyUrl: http://127.0.0.1:80/api/alipay/notify
# 支付成功后返回的页面地址(同步回调)
returnUrl: http://127.0.0.1:80/index.html
# 签名方式
signType: RSA2
charset: utf-8
# 支付宝网关地址
gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.do
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/hz_security?useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull
username: xxxx
password: xxxxx
redis:
password: xxxxx
【配置类】
package com.hz.config;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
import com.hz.pojo.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;
}
}
【实体类】
package com.hz.pojo;
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;
@Data
@TableName(value ="`order`")
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;
}
【controlelr】
package com.hz.controller;
import com.alipay.api.AlipayApiException;
import com.alipay.easysdk.factory.Factory;
import com.hz.config.AlipayTemplate;
import com.hz.pojo.Order;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
/**
* 支付宝接口
*/
@RestController
@RequestMapping("/alipay")
@CrossOrigin
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(220948748372233L);
order.setUserId(129904058947L);
order.setInterfaceInfoId(294389472934L);
order.setMoney(20.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";
}
}
【测试】
http://localhost:80/alipay/pay?id=6