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. 算法介绍 回溯算法是一种经典的递归算法,通常被用来解决排列问题、组合问题和搜索问题 基本思想 从一个初始状态开始,按一定的规则向前搜索&…...
Linux C应用编程:MQTT物联网
1 MQTT通信协议 MQTT(Message Queuing Telemetry Transport,消息队列遥测传 输)是一种基于客户端-服务端架构的消息传输协议,如今,MQTT 成为了最受欢迎的物联网协议,已广泛应用于车联网、智能家居、即时聊…...
企业常用Linux文件命令相关知识+小案例
远程连接工具无法连接VMWARE: 如果发现连接工具有时连不上,ip存在,这时候我们查看网络编辑器,更多配置,看vnet8是不是10段,nat设置是否是正确的? 软件重启一下虚机还原一下网络编辑器 查看文件…...
Istio介绍
1.什么是Istio Istio是一个开源的服务网格(Service Mesh)框架,它提供了一种简单的方式来为部署在Kubernetes等容器编排平台上的微服务应用添加网络功能。Istio的核心功能包括: 服务治理:Istio能够帮助管理服务之间的…...
代码随想录算法训练营第四十七天|leetcode115、392题
一、leetcode第392题 本题要求判断s是否为t的子序列,因此设置dp数组,dp[i][j]的含义是下标为i-1的子串与下标为j-1的子串相同字符的个数,可得递推公式是通过s[i-1]和t[j-1]是否相等区分。 具体代码如下: class Solution { publ…...
将Ubuntu18.04默认的python3.6升级到python3.8
1、查看现有的 python3 版本 python3 --version 2、安装 python3.8 sudo apt install python3.8 3、将 python3.6 和 3.8 添加到 update-alternatives sudo update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.6 1 sudo update-alternatives --insta…...
Python和Java哪个更适合后端开发?
Python和Java都是强大的后端开发语言,它们各自有鲜明的特点和适用场景。选择哪一个更适合后端开发,主要取决于具体的项目需求、团队技术栈、个人技能偏好以及长期发展考虑等因素。 下面是两者在后端开发中的优势和劣势: 「Python࿱…...
Python+pytest接口自动化之cookie绕过登录(保持登录状态)
前言 我们今天来聊聊pythonpytest接口自动化之cookie绕过登录(保持登录状态),在编写接口自动化测试用例或其他脚本的过程中,经常会遇到需要绕过用户名/密码或验证码登录,去请求接口的情况,一是因为有时验证…...
什么数据集成(Data Integration):如何将业务数据集成到云平台?
说到数据集成(Data Integration),简单地将所有数据倒入数据湖并不是解决办法。 在这篇文章中,我们将介绍如何轻松集成数据、链接不同来源的数据、将其置于合适的环境中,使其具有相关性并易于使用。 数据集成࿱…...
国外EDM邮件群发多少钱?哪个软件好?
在当今全球化市场环境下,电子邮件营销作为最有效的数字营销渠道之一,其影响力不容忽视。而高效精准的EDM(Electronic Direct Mail)邮件营销策略更是企业拓展海外市场、提升品牌知名度的关键手段。云衔科技以其创新的智能EDM邮件营…...
C语言入门算法——回文数
题目描述: 若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。 例如:给定一个十进制数 56,将 56 加 65(即把 56 从右向左读),得到 121 是一个…...
湿地公园网站开发招标/营销型网站建设步骤
momis home链接:http://www.geocities.jp/momi619jp/来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/39335/viewspace-351259/,如需转载,请注明出处,否则将追究法律责任。 转载于:http://blog.itpub.net/39335/vi…...
用php做网站/网站权重划分
点击蓝色字免费订阅,每天收到这样的好资讯本文将完全卷积神经网络应用于Phenoliner表型平台,并检测捕获的图像中的单个葡萄浆果,植物表型资讯介绍如下:在葡萄育种栽培领域,产量估算和预测具有重要意义,每株…...
做整合营销的网站/今天实时热搜榜排名
转自:http://mces89.yo2.cn/articles/fibonacci%e5%ba%8f%e5%88%97.html [定理1] 标准Fibonacci序列(即第0项为0,第1项为1的序列)当N大于1时,一定有f(N)和f(N-1)互质 其实,结合“互质”的定义,和…...
做家纺的网站/2022年国际十大新闻
2019独角兽企业重金招聘Python工程师标准>>> 如果在移动端的话,由于移动端操作相对比较单一,因此loading形式也比较简单。通常做法是在请求发出时页面正中位置弹出一个loading的 toast,请求结束隐藏 toast 。 这种做法大家接受度比…...
淘宝客网站建设详细教程/网络营销推广方案论文
mysql中,同一个表多个timesatmp字段设置default的时候,经常会报错。 一个表只能有一个设置default的字段。 但是有时只有一个字段设置default也会报错。 会报:Incorrect table definition; there can be only one TIMESTAMP column with CURR…...
北京住房和经济建设发展委员会网站/厦门网站建设平台
Spring-Boot 1.x版本 传送门:https://gitee.com/didispace/SpringBoot-Learning/tree/master/1.x 快速入门 提示:我们在学习Spring Boot、Spring Cloud的时候,一定要知道它们的版本关系,以避免不必要的困恼。 Spring Cloud Alib…...