SpringBoot整合alipay
本文最后更新于 2024-04-24,欢迎来到我的Blog! https://www.zpeng.site/
SpringBoot整合alipay
1、简介
服务端 SDK
支付宝将与服务端交互的接口(OpenAPI)封装在开发工具包(SDK)中,开发者无需自行实现同服务端交互的复杂逻辑,直接将 SDK 导入自己的工程后,通过 OpenAPI 的示例代码实现同支付宝服务端的交互。根据开发者的使用习惯,支付宝开放平台共推出了通用版 SDK 及轻量化的 Easy SDK,两个版本的 SDK 可以共存,并无冲突。
通用版:适用所有场景及功能,推荐使用。
Easy 版:适用于 Java、C#、PHP,轻量化裁剪。
客户端 SDK
开发者的移动应用接入支付宝开放平台提供的部分产品(如 App 支付 和 分享到支付宝 等),需要集成支付宝提供的客户端 SDK。
App 支付
分享到支付宝
2、配置沙箱账号
需要获取:AppId、支付宝网关地址、应用私钥、支付宝公钥。
3、配置内网穿透账号
1、注册账号
2、开通免费隧道
3、natapp下载
4、配置启动
新建start.bat natapp.exe -authtoken=4f64a746e1f1173 双击启动
把本地的服务暴露到公网,让支付宝可以调用我们的接口给我们传递数据
5、配置yml
4、SpringBoot整合
支付宝sdk
<!-- 支付宝SDK -->
<dependency>
<groupId>com.alipay.sdk</groupId>
<artifactId>alipay-sdk-java</artifactId>
<version>4.35.79.ALL</version>
</dependency>
其它
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
准备工作
前端代码以及order、product表的基本查询(controller、service、mapper、xml等)见gitee项目
https://gitee.com/pengqaq/learn
sql语句
/*
Navicat Premium Data Transfer
Source Server : localhost_3306
Source Server Type : MySQL
Source Server Version : 80034 (8.0.34)
Source Host : localhost:3306
Source Schema : alipay
Target Server Type : MySQL
Target Server Version : 80034 (8.0.34)
File Encoding : 65001
Date: 19/11/2023 17:06:28
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for goods
-- ----------------------------
DROP TABLE IF EXISTS `goods`;
CREATE TABLE `goods` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品名称',
`no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品编号',
`price` decimal(10, 2) NULL DEFAULT NULL COMMENT '商品价格',
`date` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '生产日期',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '商品表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of goods
-- ----------------------------
INSERT INTO `goods` VALUES (1, 'CHERRY樱桃MX10.0游戏竞技超薄机械键盘', 'CHERRY MX10.0', 1399.00, '2023-11-19');
INSERT INTO `goods` VALUES (2, '达尔优61蓝牙机械键盘', 'RK61', 473.00, '2023-11-19');
INSERT INTO `goods` VALUES (3, '樱桃cherry轴RK机械键盘', '987/988樱桃', 229.00, '2023-11-19');
-- ----------------------------
-- Table structure for orders
-- ----------------------------
DROP TABLE IF EXISTS `orders`;
CREATE TABLE `orders` (
`id` int NOT NULL AUTO_INCREMENT COMMENT 'ID',
`order_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单编号',
`goods_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '商品名称',
`num` int NULL DEFAULT NULL COMMENT '商品数量',
`total` decimal(10, 2) NULL DEFAULT NULL COMMENT '总价格',
`create_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '创建时间',
`pay_no` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '支付编号',
`pay_time` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '支付时间',
`status` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL COMMENT '订单状态',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci COMMENT = '订单表' ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of orders
-- ----------------------------
SET FOREIGN_KEY_CHECKS = 1;
application.yml
alipay:
appId: xxx
appPrivateKey: xxx
alipayPublicKey: xxx
notifyUrl: http://xxx/alipay/notify
server:
port: 9090
spring:
application:
name: pay
# 配置数据源
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/learn?useUnicode=true&characterEncoding=utf-8
username: root
password: root
#mybatis配置信息
mybatis:
# xml映射文件所在的路径,一般用模糊匹配来指定最终的xml文件
mapper-locations: classpath:/mapper/*.xml
configuration:
#采用驼峰形式将数据表中以‘_’分隔的字段映射到java类的某个属性,比如表字段user_name可以映射为类里面的userName属性
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
alipay:
appId: xxx
appPrivateKey: xxx
alipayPublicKey: xxx
notifyUrl: http://xxx/alipay/notify
appId:⽀付宝沙箱appid
appPrivateKey:应⽤私钥
alipayPublicKey:⽀付宝公钥
notifyUrl格式:natapp代理的url + /alipay/notify,例如:
配置类AliPayConfig
package com.example.pay.alipay.common;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 阿里支付配置组件,用于存储支付宝的配置信息。
* 该类通过@Component和@ConfigurationProperties注解,使得它成为一个Spring组件,
* 并且可以从配置文件中自动加载以"alipay"为前缀的配置属性。
*/
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
// 支付宝分配给开发者的应用ID
private String appId;
// 应用的私钥,用于和支付宝进行RSA256加密通信
private String appPrivateKey;
// 支付宝的公钥,用于验证支付宝的签名
private String alipayPublicKey;
// 支付宝异步通知的URL地址,必须是公网可访问的接口地址
private String notifyUrl;
/**
* 获取支付宝的应用ID
*
* @return 返回支付宝的AppId字符串
*/
public String getAppId() {
return appId;
}
/**
* 设置支付宝的应用ID
*
* @param appId 支付宝分配的应用ID
*/
public void setAppId(String appId) {
this.appId = appId;
}
/**
* 获取应用的私钥
*
* @return 返回应用的私钥字符串
*/
public String getAppPrivateKey() {
return appPrivateKey;
}
/**
* 设置应用的私钥
*
* @param appPrivateKey 应用的私钥字符串
*/
public void setAppPrivateKey(String appPrivateKey) {
this.appPrivateKey = appPrivateKey;
}
/**
* 获取支付宝的公钥
*
* @return 返回支付宝的公钥字符串
*/
public String getAlipayPublicKey() {
return alipayPublicKey;
}
/**
* 设置支付宝的公钥
*
* @param alipayPublicKey 支付宝的公钥字符串
*/
public void setAlipayPublicKey(String alipayPublicKey) {
this.alipayPublicKey = alipayPublicKey;
}
/**
* 获取支付宝异步通知的URL地址
*
* @return 返回支付宝异步通知的URL地址字符串
*/
public String getNotifyUrl() {
return notifyUrl;
}
/**
* 设置支付宝异步通知的URL地址
*
* @param notifyUrl 支付宝异步通知的URL地址字符串
*/
public void setNotifyUrl(String notifyUrl) {
this.notifyUrl = notifyUrl;
}
}
AliPayController
package com.example.pay.alipay.controller;
import cn.hutool.json.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 com.example.pay.alipay.common.AliPayConfig;
import com.example.pay.alipay.entity.Orders;
import com.example.pay.alipay.service.OrdersService;
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 {
// 支付宝网关URL
private static final String GATEWAY_URL = "https://openapi-sandbox.dl.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;
@Resource
private OrdersService ordersService;
/**
* 用户支付接口
*
* @param orderNo 订单号
* @param httpResponse 响应对象
* @throws Exception 异常
*/
@GetMapping("/pay")
public void pay(String orderNo, HttpServletResponse httpResponse) throws Exception {
// 根据订单号查询订单信息
Orders orders = ordersService.selectByOrderNo(orderNo);
if (orders == null) {
return;
}
// 创建支付宝客户端
AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
// 创建页面支付请求,并设置相关参数
AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
request.setNotifyUrl(aliPayConfig.getNotifyUrl());
JSONObject bizContent = new JSONObject();
bizContent.set("out_trade_no", orders.getOrderNo());
bizContent.set("total_amount", orders.getTotal());
bizContent.set("subject", orders.getGoodsName());
bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");
request.setBizContent(bizContent.toString());
request.setReturnUrl("http://localhost:8080/orders");
// 执行支付请求,生成表单并返回给客户端
String form = "";
try {
form = alipayClient.pageExecute(request).getBody();
} catch (AlipayApiException e) {
e.printStackTrace();
}
httpResponse.setContentType("text/html;charset=" + CHARSET);
httpResponse.getWriter().write(form);
httpResponse.getWriter().flush();
httpResponse.getWriter().close();
}
/**
* 支付宝异步通知接口
*
* @param request 请求对象
* @throws Exception 异常
*/
@PostMapping("/notify")
public void payNotify(HttpServletRequest request) throws Exception {
// 验证交易状态
if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
System.out.println("=========支付宝异步回调========");
// 构建参数map
Map<String, String> params = new HashMap<>();
Map<String, String[]> requestParams = request.getParameterMap();
for (String name : requestParams.keySet()) {
params.put(name, request.getParameter(name));
}
// 验证签名
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"));
// 更新订单支付状态
String tradeNo = params.get("out_trade_no");
String gmtPayment = params.get("gmt_payment");
String alipayTradeNo = params.get("trade_no");
Orders orders = ordersService.selectByOrderNo(tradeNo);
orders.setStatus("已支付");
orders.setPayTime(gmtPayment);
orders.setPayNo(alipayTradeNo);
ordersService.updateById(orders);
}
}
}
}
测试
点击购买
查看订单
点击支付
输入账号密码
输入支付密码
付款成功
触发回调函数
更新数据库成功
商品已支付
- 感谢你赐予我前进的力量