SpringBoot整合支付宝沙箱支付
环境说明:SpringBoot3.0.2
支付宝沙箱地址:沙箱地址
获取配置信息
因支付需要回调地址,回调地址必须是公网,如果有公网的话,那直接在下面配置文件填写自己的公网,没有的话,就需要我们借助第三方工具来进行回调。具体操作请看这篇博客
引入依赖
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.22.110.ALL</version>
</dependency>
配置文件
yz:alipay:gatewayUrl: https://openapi-sandbox.dl.alipaydev.com/gateway.doappId: 你的appidprivateKey: 你的私钥format: jsonpublicKey: 你的公钥charset: UTF-8signType: RSA2returnUrl: http://xxxxxx.natappfree.cc/api/pay/finish # 回调成功后,调用的地址notifyUrl: http://xxxxxx.natappfree.cc/api/pay/notify # 回调地址expireTime: 15mreturn:url: http://localhost:8000/account/center # 这个就写你支付成功跳转的页面
配置类
@Data
@Configuration
@ConfigurationProperties(prefix = "yz.alipay")
public class AliPayProperties {private String gatewayUrl;private String appId;private String privateKey;private String format;private String publicKey;private String charset;private String signType;private String notifyUrl;private String returnUrl;private String expireTime;
}
@Data
@Configuration
@ConfigurationProperties(prefix = "yz.return")
public class ReturnProperties {private String url;
}
订单信息
@Data
public class PayOrderRequest {private static final long serialVersionUID = 3191241716373120793L;@Schema(description = "订单号")private Long id;@Schema(description = "用户id")private Long uid;@Schema(description = "主题")private String subject;@Schema(description = "充值金额")private Long amount;@Schema(description = "实际金额")private Float realAmount;@Schema(description = "优惠率")private Float discountRate;
}
支付的回调信息,封装成类,
@Data
public class AlipayNotifyDto {private String gmt_create;private String charset;private String gmt_payment;private String notify_time;private String subject;private String sign;private String buyer_id;private String invoice_amount;private String version;private String notify_id;private String fund_bill_list;private String notify_type;private String out_trade_no;private String total_amount;private String trade_status;private String trade_no;private String auth_app_id;private String receipt_amount;private String point_amount;private String buyer_pay_amount;private String app_id;private String sign_type;private String seller_id;
}
Facade接口
@Tag(name = "支付接口")
public interface PayFacade {@Operation(summary = "支付")@Parameters(value = {@Parameter(name = "uid", description = "用户id", in = ParameterIn.HEADER)})@PostMapping("/pay/")BaseResponse<String> reCharge(@RequestHeader Long uid, @RequestBody PayOrderRequest payOrderRequest);@Operation(summary = "支付宝异步通知,支付宝支付后,会回调该接口")@PostMapping("/pay/notify")String notify(AlipayNotifyDto alipayNotifyDto);@Operation(summary = "同步跳转,告诉你是否调用成功,不能拿来判断支付成功")@GetMapping("/pay/finish")void finish(HttpServletResponse response);
}
Controller类
@Slf4j
@RestController
@RequiredArgsConstructor
public class PayController implements PayFacade {private final PayService payService;@Overridepublic BaseResponse<String> reCharge(Long uid, PayOrderRequest payOrderRequest) {if(payOrderRequest == null || uid == null){throw new RuntimeException("参数不能为空");}String res = payService.reCharge(uid, payOrderRequest);return ResultUtils.success("",res);}public String notify(AlipayNotifyDto alipayNotifyDto) {if(alipayNotifyDto == null){throw new RuntimeException("参数不能为空");}String res = payService.notifyUrl(alipayNotifyDto);return res;}public void finish(HttpServletResponse response) {try{response.sendRedirect(returnProperties.getUrl());} catch (Exception e){log.error("【同步跳转,告诉你是否调用成功,不能拿来判断支付成功】",e);}}
}
Service类
@Slf4j
@Service
@RequiredArgsConstructor
public class PayServiceImpl extends ServiceImpl<PayMapper, PayFlow> implements PayService {private final AliPayProperties aliPayProperties;private final PayMessageProducer payMessageProducer;private final UserMessageProducer userMessageProducer;private final PromotionMessageProducer promotionMessageProducer;private final OrderMessageProducer orderMessageProducer;// 携带订单信息获取支付url@Overridepublic String reCharge(Long uid, PayOrderRequest payOrderRequest) {try{log.info("payOrderRequest支付信息:{}", payOrderRequest);//保存流水---交给mq处理payMessageProducer.sendMessage(JSON.toJSONString(payOrderRequest));// 交易String path = sendPayment(payOrderRequest);return path;}catch (Exception e){log.info("支付异常", e);throw new RuntimeException("系统出错");}}// 处理回调逻辑@Overridepublic String notifyUrl(AlipayNotifyDto alipayNotifyDto) {log.info("setTradeStatus: {}", alipayNotifyDto.getTrade_status());log.info("回调了");String payStatus = "fail";boolean signVerified = false;Map<String, String> mp = JSON.parseObject(JSON.toJSONString(alipayNotifyDto), Map.class);try {signVerified = AlipaySignature.rsaCheckV1(mp, aliPayProperties.getPublicKey(), aliPayProperties.getCharset(), aliPayProperties.getSignType());log.info("【异步通知签名验证】" + signVerified);}catch (AlipayApiException e){System.out.println("【异步签名异常】" + e.getErrMsg());return payStatus;}if(signVerified && "TRADE_SUCCESS".equals(alipayNotifyDto.getTrade_status())){// 更新流水---这块应该也交给mq处理,不想写了,就这样吧updatePayFlowSuccess(alipayNotifyDto.getOut_trade_no());// 更新订单---交给mq处理orderMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());// 消费优惠卷---交给mq处理promotionMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());// 用户金币新增---交给mq处理userMessageProducer.sendMessage(alipayNotifyDto.getOut_trade_no());payStatus = "success";}log.info("【异步通知签名验证】" + payStatus);return payStatus;}@Overridepublic void returnUrl(HttpServletRequest request) throws UnsupportedEncodingException {}// 更新支付流水private void updatePayFlowSuccess(String outTradeNo){QueryWrapper<PayFlow> queryWrapper = new QueryWrapper<>();queryWrapper.eq("out_trade_no", Long.parseLong(outTradeNo));PayFlow payFlow = PayFlow.builder().build();payFlow.setTradeStatus(PayConstant.TRADE_SUCCESS);payFlow.setPaySuccess(true);boolean update = this.update(payFlow, queryWrapper);if(!update){log.info("更新流水失败");throw new RuntimeException("更新流水失败");}}// 支付配置private AlipayConfig getAlipayConfig() {AlipayConfig alipayConfig = new AlipayConfig();alipayConfig.setServerUrl(aliPayProperties.getGatewayUrl());alipayConfig.setAlipayPublicKey(aliPayProperties.getPublicKey());alipayConfig.setPrivateKey(aliPayProperties.getPrivateKey());alipayConfig.setAppId(aliPayProperties.getAppId());alipayConfig.setFormat(aliPayProperties.getFormat());alipayConfig.setCharset(aliPayProperties.getCharset());alipayConfig.setSignType(aliPayProperties.getSignType());return alipayConfig;}// 返回支付urlprivate String sendPayment(PayOrderRequest payOrderRequest){try {AlipayClient alipayClient = new DefaultAlipayClient(this.getAlipayConfig());AlipayTradePagePayRequest request = this.getAlipayTradePagePayRequest(payOrderRequest);request.setReturnUrl(aliPayProperties.getReturnUrl());request.setNotifyUrl(aliPayProperties.getNotifyUrl());// 调用SDK生成表单AlipayTradePagePayResponse alipayTradePagePayResponse = alipayClient.pageExecute(request, "GET");String body = alipayTradePagePayResponse.getBody();return body;} catch (Exception e) {e.printStackTrace();}return null;}private AlipayTradePagePayRequest getAlipayTradePagePayRequest(PayOrderRequest payOrderRequest) {AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();//异步接收地址,仅支持http/https,公网可访问request.setNotifyUrl("");//同步跳转地址,仅支持http/httpsrequest.setReturnUrl("");/******必传参数******/JSONObject bizContent = new JSONObject();//商户订单号,商家自定义,保持唯一性bizContent.put("out_trade_no", payOrderRequest.getId());//支付金额,最小值0.01元bizContent.put("total_amount", payOrderRequest.getRealAmount());//订单标题,不可使用特殊符号bizContent.put("subject", payOrderRequest.getSubject());//电脑网站支付场景固定传值FAST_INSTANT_TRADE_PAYbizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");bizContent.put("timeout_express", aliPayProperties.getExpireTime());request.setBizContent(bizContent.toString());return request;}
}
相关文章:

SpringBoot整合支付宝沙箱支付
环境说明:SpringBoot3.0.2 支付宝沙箱地址:沙箱地址 获取配置信息 因支付需要回调地址,回调地址必须是公网,如果有公网的话,那直接在下面配置文件填写自己的公网,没有的话,就需要我们借助第三…...

探索进程控制第一弹(进程终止、进程等待)
文章目录 进程创建初识fork函数fork函数返回值fork常规用法fork调用失败的原因 写时拷贝进程终止进程终止是在做什么?进程终止的情况代码跑完,结果正确/不正确代码异常终止 如何终止 进程等待概述进程等待方法wait方法waitpid 进程创建 初识fork函数 在…...
在mac环境下使用shell脚本实现tree命令
文章目录 使用ls实现tree使用find实现tree 使用ls实现tree 实现思路 使用ls -F 打印文件类型,如果是目录后面跟/,如果是可执行文件后面跟*;使用grep -v /$ 筛选文件排除目录,-v为反向筛选;使用grep /$ 仅筛选目录&am…...
递归时间复杂度分析方法:Master 定理
编写算法时,可能因为对自己代码的复杂度的不清晰而导致错失良机,对于普通的递推或者说循环的代码,仅用简单的调和级数或者等差数列和等比数列即可分析,但是对于递归的代码,简单的递归树法并不方便,理解并记…...
实例名不规范导致mds创建失败
概述 在部署ceph集群时,规划主机名、关闭防火墙、配置免密、关闭selinux,配置hosts文件这几步同样重要,都是初期部署一次麻烦,方便后续运维的动作。遇到过很多前期稀里糊涂部署,后续运维和配置时候各种坑。 近期遇到…...
OpenGL中的纹理过滤GL_NEAREST和GL_LINEAR
一、GL_NEAREST(最近邻插值) 1.1 原理 当需要从纹理中采样颜色时,GL_NEAREST模式会选择离采样点最近的纹理像素(通常是最接近采样点的纹理元素的中心),并直接使用该像素的颜色值作为输出。这种模式不进行任…...
vue 性能优化
data 层级不要太深 data 层级太深会增加响应式监听的计算,导致页面初次渲染时卡顿。 合理使用 v-show 和 v-if 频繁切换时,使用 v-show无需频繁切换时,使用 v-if 合理使用 computed computed 有缓存,data 不变时不会重新计算&…...

互联网大厂ssp面经(操作系统:part1)
1. 什么是进程和线程?它们之间有什么区别? a. 进程是操作系统中运行的一个程序实例。它拥有独立的地址空间和资源,可以独立执行。 b. 线程是进程内的一个执行单元,一个进程可以包含多个线程。 c. 线程共享进程的资源,…...
Android Activity 启动涉及几个进程
Zygote进程: Zygote进程在Android系统启动时被初始创建,并且初始化了虚拟机(Dalvik或ART),预加载了Android系统的核心类库。所有的Android应用进程都是通过fork()从Zygote进程派生出来的,这允许应用快速启动࿰…...

说说你对链表的理解?常见的操作有哪些?
一、是什么 链表(Linked List)是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,由一系列结点(链表中每一个元素称为结点)组成 每个结点包括两个部分&…...

每天五分钟深度学习:逻辑回归算法的损失函数和代价函数是什么?
本文重点 前面已经学习了逻辑回归的假设函数,训练出模型的关键就是学习出参数w和b,要想学习出这两个参数,此时需要最小化逻辑回归的代价函数才可以训练出w和b。那么本节课我们将学习逻辑回归算法的代价函数是什么? 为什么不能平方差损失函数 线性回归的代价函数我们使用…...

llama-factory SFT系列教程 (二),大模型在自定义数据集 lora 训练与部署
文章目录 简介支持的模型列表2. 添加自定义数据集3. lora 微调4. 大模型 lora 权重,部署问题 参考资料 简介 文章列表: llama-factory SFT系列教程 (一),大模型 API 部署与使用llama-factory SFT系列教程 (二),大模型在自定义数…...
C语言游戏实战(11):贪吃蛇大作战(多人对战)
成果展示: 贪吃蛇(多人对战) 前言: 这款贪吃蛇大作战是一款多人游戏,玩家需要控制一条蛇在地图上移动,吞噬其他蛇或者食物来增大自己的蛇身长度和宽度。本游戏使用C语言和easyx图形库编写,旨在…...

腾讯测试岗位的面试经历与经验分享【一面、二面与三面】
腾讯两个月的实习一转眼就结束了,回想起当时面试的经过,感觉自己是跌跌撞撞就这么过了,多少有点侥幸.马上腾讯又要来校招了,对于有意愿想投腾讯测试岗位的同学们,写了一些那时候面试的经历和自己的想法,算不上经验,仅供参考吧! 一面 — —技术基础,全面…...
手机移动端网卡信息获取原理分析
有些场景我们需要获取当前手机上的网卡信息(如双卡双待、Wifi等)。本文准备研究一下这块的原理,以便更好的掌握相关技术原理。 1、底层系统接口 getifaddrs 使用 getifaddrs 接口可以达到我们的目的,该接口会返回本地所有网卡的信…...

无人新零售引领的创新浪潮
无人新零售引领的创新浪潮 在数字化时代加速演进的背景下,无人新零售作为商业领域的一股新兴力量,正以其独特的高效性和便捷性重塑着传统的购物模式,开辟了一条充满创新潜力的发展道路。 依托人脸识别、物联网等尖端技术,无人新…...

SD-WAN提升企业网络体验
在现代企业中,网络体验已成为提升工作效率与业务质量的关键因素。SD-WAN技术的出现,以其独特的优势,为企业提供了优化网络连接、加速数据传输、提升服务质量和应用访问体验,以及增强网络稳定性的解决方案。接下来,我们…...
Docker搭建Let‘s Encrypt
Let’s Encrypt是一个免费、开放和自动化的证书颁发机构(CA),它提供了一种简单、无需重复的机制来获取和更新SSL/TLS证书。Let’s Encrypt Docker镜像允许用户在容器化环境中轻松部署和使用Let’s Encrypt的服务。 主要功能包括:…...

单链表讲解
一.链表的概念以及结构 链表是一种物理结构上不连续,逻辑结构上连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的。 链表的结构与火车是类似的,一节一节的,数据就像乘客一样在车厢中一样。 与顺序表不同的…...

DFS算法系列 回溯
DFS算法系列-回溯 文章目录 DFS算法系列-回溯1. 算法介绍2. 算法应用2.1 全排列2.2 组合2.3 子集 3. 总结 1. 算法介绍 回溯算法是一种经典的递归算法,通常被用来解决排列问题、组合问题和搜索问题 基本思想 从一个初始状态开始,按一定的规则向前搜索&…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

vscode(仍待补充)
写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh? debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

LLMs 系列实操科普(1)
写在前面: 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容,原视频时长 ~130 分钟,以实操演示主流的一些 LLMs 的使用,由于涉及到实操,实际上并不适合以文字整理,但还是决定尽量整理一份笔…...

uniapp手机号一键登录保姆级教程(包含前端和后端)
目录 前置条件创建uniapp项目并关联uniClound云空间开启一键登录模块并开通一键登录服务编写云函数并上传部署获取手机号流程(第一种) 前端直接调用云函数获取手机号(第三种)后台调用云函数获取手机号 错误码常见问题 前置条件 手机安装有sim卡手机开启…...

uniapp 小程序 学习(一)
利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 :开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置,将微信开发者工具放入到Hbuilder中, 打开后出现 如下 bug 解…...