SpringBoot 集成支付宝支付

网页操作步骤

1.进入支付宝开发平台—沙箱环境

使用开发者账号登录开放平台控制平台

2.点击沙箱进入沙箱环境

图片

 

说明:沙箱环境支持的产品,可以在沙箱控制台 沙箱应用 > 产品列表 中查看。

3.进入沙箱,配置接口加签方式

图片

 

在沙箱进行调试前需要确保已经配置密钥/证书用于加签,支付宝提供了 系统默认密钥 及 自定义密钥 两种方式进行配置。这里我采取的是默认方式:

开发者如需使用系统默认密钥/证书,可在开发信息中选择系统默认密钥。注意:使用API在线调试工具调试OpenAPI必须使用系统默认密钥。

4.配置应用网关

图片

 

应用网关用于接收支付宝沙箱环境的异步通知(对接 From 蚂蚁消息),如创建门店的被动通知。

注意:仅 HTTP 订阅模式的 From 蚂蚁消息才需要配置应用网关,WebSocket 订阅模式的 From 蚂蚁消息无需配置应用网关。

5.生成自己的密钥

图片

 

至此,网页操作完成

2idea操作步骤

1.导入依赖
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.22.110.ALL</version>
</dependency>
2.在 application.yml 里面进行配置
alipay:appId: appPrivateKey: alipayPublicKey: notifyUrl: (回调接口)
3.alipay的JAVA配置:AlipayConfig.java

读取yml中的配置信息,自动填充到对应的属性

@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {private String appId;private String appPrivateKey;private String alipayPublicKey;private String notifyUrl;}
4.支付接口 新建一个 AliPayController.java

1、 在Controller中配置gateway_url(调用支付宝url的一个网关地址)、format(JSON形式)、charset(UTF-8)、sign_type(签名方式-rsa2;
2、 编写一个Get请求,(方法参数是一个AliPay的配置类里面包括自己生成的订单号、总金额、支付的名称、支付宝交易凭证号和HttpServletResponse);
3、 创建Client(他是由通用SDK提供的Client,负责调用支付宝的API,设置参数包含网关地址、appid、密钥、公钥、format、charset、签名方式)----------------------->创建Client,他是由通用SDK提供的Client,负责调用支付宝的API;
4、 创建AlipayTradePagePayRequest,配置notifyUrl并设置Request参数(参数包含订单号、总金额、支付的名称)(格式:JSON格式)------------------------->创建Request并设置Request参数;
5、 通过AlipayClient执行request调用SDK生成表单,用HttpServletResponse(浏览器响应的一个流)写表单的内容,创建一个html的网页)--------------------------->执行请求,拿到响应的结果,返回给浏览器;

@Data
public class AliPay {private String traceNo;private double totalAmount;private String subject;private String alipayTraceNo;
}
private static final String GATEWAY_URL = "https://openapi.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 OrdersMapper ordersMapper;@GetMapping("/pay") // &subject=xxx&traceNo=xxx&totalAmount=xxx
public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的APIAlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);// 2. 创建 Request并设置Request参数AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();  // 发送请求的 Request类request.setNotifyUrl(aliPayConfig.getNotifyUrl());JSONObject bizContent = new JSONObject();bizContent.set("out_trade_no", aliPay.getTraceNo());  // 我们自己生成的订单编号bizContent.set("total_amount", aliPay.getTotalAmount()); // 订单的总金额bizContent.set("subject", aliPay.getSubject());   // 支付的名称bizContent.set("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置request.setBizContent(bizContent.toString());// 执行请求,拿到响应的结果,返回给浏览器String form = "";try {form = alipayClient.pageExecute(request).getBody(); // 调用SDK生成表单} catch (AlipayApiException e) {e.printStackTrace();}httpResponse.setContentType("text/html;charset=" + CHARSET);httpResponse.getWriter().write(form);// 直接将完整的表单html输出到页面httpResponse.getWriter().flush();httpResponse.getWriter().close();
}
5.在拦截器里面加上 忽略alipay接口的配置

遇到的坑:

url中有中文字符报错,更换依赖

官网提供有easy版和正式版

easy-sdk 好像不太支持中文的subject,否则 biz_content就会乱码,那我索性就用了 alipay-sdk 正式版的

6.回调接口

1、 使用的Post接口,首先验证交易状态是否成功,获取request里面的信息;
2、 支付宝验签(使用的是AlipaySignature(通用SDK提供的类)获取一个String字符串将其与sign签名验证),通过后,使用OrderMapper更新到数据库);

使用的Post接口,因为官方建议处理付款成功后的操作在异步调用方法中,异步调用为post请求,异步回调方法必须为公网IP,因为支付宝是基于公网访问,访问不了localhost,需要代理,设置公网IP有两种方案,1、内网穿透,2、将项目部署到服务器,我们项目使用的是内网穿透,使用的是natapp,配置一条免费的隧道,在idea中配置notifyurl接口

@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");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"));// 更新订单未已支付ordersMapper.updateState(tradeNo, "已支付", gmtPayment, alipayTradeNo);}}return "success";
}

3退款流程

1、 创建Client(他是由通用SDK提供的Client,负责调用支付宝的API)(参数包含网关地址、appid、密钥、公钥、format、charset、签名方式)---------------------->创建Client,通用SDK提供的Client,负责调用支付宝的API;

2、 创建AlipayTradePagePayRequest,设置Request参数(参数包含支付宝回调的订单流水号、总金额、我的订单编号)(格式:JSON格式)---------------------------->创建Request,设置参数;
3、 通过AlipayClient执行request获取response,通过isSuccess判断是否成功,成功后更新数据库状态------------->执行请求,更新数据库;

@GetMapping("/return")
public Result returnPay(AliPay aliPay) throws AlipayApiException {// 7天无理由退款String now = DateUtil.now();Orders orders = ordersMapper.getByNo(aliPay.getTraceNo());if (orders != null) {// hutool工具类,判断时间间隔long between = DateUtil.between(DateUtil.parseDateTime(orders.getPaymentTime()), DateUtil.parseDateTime(now), DateUnit.DAY);if (between > 7) {return Result.error("-1", "该订单已超过7天,不支持退款");}}// 1. 创建Client,通用SDK提供的Client,负责调用支付宝的APIAlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL,aliPayConfig.getAppId(), aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET,aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);// 2. 创建 Request,设置参数AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();JSONObject bizContent = new JSONObject();bizContent.set("trade_no", aliPay.getAlipayTraceNo());  // 支付宝回调的订单流水号bizContent.set("refund_amount", aliPay.getTotalAmount());  // 订单的总金额bizContent.set("out_request_no", aliPay.getTraceNo());   //  我的订单编号// 返回参数选项,按需传入//JSONArray queryOptions = new JSONArray();//queryOptions.add("refund_detail_item_list");//bizContent.put("query_options", queryOptions);request.setBizContent(bizContent.toString());// 3. 执行请求AlipayTradeRefundResponse response = alipayClient.execute(request);if (response.isSuccess()) {  // 退款成功,isSuccess 为trueSystem.out.println("调用成功");// 4. 更新数据库状态ordersMapper.updatePayState(aliPay.getTraceNo(), "已退款", now);return Result.success();} else {   // 退款失败,isSuccess 为falseSystem.out.println(response.getBody());return Result.error(response.getCode(), response.getBody());}}
订单三十分钟未支付自动取消

使用消息队列

我们可以采用rabbitMQ的延时队列。RabbitMQ具有以下两个特性,可以实现延迟队列

RabbitMQ可以针对Queue和Message设置 x-message-tt,来控制消息的生存时间,如果超时,则消息变为dead letter

RabbitMQ的Queue可以配置x-dead-letter-exchange 和x-dead-letter-routing-key(可选)两个参数,用来控制队列内出现了deadletter,则按照这两个参数重新路由。结合以上两个特性,就可以模拟出延迟消息的功能

优缺点

  • 优点: 高效,可以利用rabbitmq的分布式特性轻易的进行横向扩展,消息支持持久化增加了可靠性。

  • 缺点: 本身的易用度要依赖于rabbitMq的运维.因为要引用rabbitMq,所以复杂度和成本变高。

用户下单之后,投递一个msg消息存放在msg服务器daunt,该消息msg消息过期时间为30分钟,一直未被订单消费者消费,消息会转移到死信交换机路由到死信队列中,被我们的死信消费者30分钟后消息。

死信消费者在根据订单号码查询支付订单状态,如果是未支付情况下,则将该订单设置未超时。

对筛选出来的订单号码进行核对校验:

1、 订单中是否存在;
2、 携带订单号码调用支付宝查询订单支付状态是否为待支付;
3、 更新该订单号码状态;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/230068.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习|10.2 边缘检测示例 10.3 更多边缘检测

文章目录 如何在编程中实现卷积运算使用卷积实现边缘检测结果矩阵的元素正负性质的意义水平分类器如何构造卷积运算使用的矩阵 原矩阵通过一个过滤器&#xff08;filter&#xff09;/核心&#xff08;kernel&#xff09;来生成一个新的矩阵。 如何在编程中实现卷积运算 使用卷积…

LAYABOX:2024新年寄语

2024新年寄语 过去的一年&#xff0c;尽管许多行业面临严峻挑战和发展压力&#xff0c;小游戏领域却逆势上扬&#xff0c;年产值首次突破400亿元大关&#xff0c;众多优质小游戏企业收获颇丰。 对此&#xff0c;祝福大家&#xff0c;2024一定更好&#xff01; 过去的一年&#…

跨站脚本攻击漏洞XSS绕过22种方式总结

XSS漏洞简介 跨站脚本攻击在目前这个时间节点还是属于一个排位比较高的漏洞&#xff0c;在OWASP TOP10 2021中隶属于注入型漏洞&#xff0c;高居TOP3的排位&#xff0c;可见这个漏洞的普遍性。跨站脚本攻击的学习中我们主要需要明白的是跨站的含义&#xff0c;以及XSS的核心。…

如何自动生成 API 接口文档 - 一份详细指南

本篇文章详细教你如何使用 Apifox 的 IDEA 插件实现自动生成接口代码。好处简单总结有以下几点&#xff1a; 自动生成接口文档&#xff1a; 不用手写&#xff0c;一键点击就可以自动生成文档&#xff0c;当有更新时&#xff0c;点击一下就可以自动同步接口文档&#xff1b;代码…

关于MIPS上手应知应会-如何把C语言改写为MIPS!

文章目录 寄存器指令使用技巧翻译C/Cif/else语句switch语句for循环while 循环do...while循环一维数组定义与使用二维数组定义与使用例 &#xff1a;哈密顿回路 注意立即数被符号位扩展 参考链接 寄存器 NameReg. NumUsage z e r o zero zero0constant value 0(恒为0) a t at a…

学习使用wps将ppt的页面保存为图片的方法

学习使用wps将ppt的页面保存为图片的方法 方案 方案 1、打开ppt&#xff0c;点击文件&#xff0c;另存为&#xff0c;选择文件类型为图片格式&#xff0c;jpg或者png&#xff0c;如下图&#xff1a; 2、点击每张幻灯片

2023启示录丨自动驾驶这一年

图片&#xff5c;《老人与海》插图 过去的20年&#xff0c;都没有2023年如此动荡。 大模型犹如一颗原子弹投入科技圈&#xff0c;卷起万里尘沙&#xff0c;传统模式瞬间被夷为平地&#xff0c;在耀眼的白光和巨大的轰鸣声之下&#xff0c;大公司、创业者、投资人甚至是每一位观…

大语言模型LLM微调技术:P-Tuning

1 引言 Bert时代&#xff0c;我们常做预训练模型微调&#xff08;Fine-tuning&#xff09;&#xff0c;即根据不同下游任务&#xff0c;引入各种辅助任务loss和垂直领域数据&#xff0c;将其添加到预训练模型中&#xff0c;以便让模型更加适配下游任务的方式。每个下游任务都存…

四、HTML 属性

属性是 HTML 元素提供的附加信息。 一、HTML 属性 HTML 元素可以设置属性属性可以在元素中添加附加信息属性一般描述于开始标签属性总是以名称/值对的形式出现&#xff0c;比如&#xff1a;name"value"。 二、 属性实例 HTML 链接由 <a> 标签定义。链接的地…

python设计模式:模板方法模式

更多Python学习内容&#xff1a;ipengtao.com 软件设计和编程中&#xff0c;设计模式是一种有助于解决常见问题的强大工具。其中之一是"模板方法模式"&#xff0c;它是一种行为型设计模式&#xff0c;允许你定义一个算法的骨架&#xff0c;但将一些步骤的具体实现延迟…

声明式管理方(yaml)文件

声明式管理方(yaml)文件: 1、适合对资源的修改操作 2、声明式管理依赖于yaml文件&#xff0c;所有的内容都在yaml文件当中。 3、编辑好的yaml文件需要依靠陈述是还是要依靠陈述式的命令发布到k8s集群当中 create只能创建&#xff0c;不能更新。从指定yaml文件中读取配置&#…

静态代理、JDK动态代理、CGLIB动态代理以及JDK和CGLIB动态代理的区别

代理 什么是代理&#xff1f;两个设计原则三要素 静态代理静态代理的实现定义接口-定义行为静态代理 -> 目标角色静态代理-> 代理角色静态代理测试 特点 JDK动态代理newProxyInstance获取代理对象通过代理对象实现目标对象的功能特点 Java动态代理类中的invoke是怎么调用…

OpenAI GPT 模型 API 接口新增参数 top_logprobs 和 logprobs

文章目录 一、前言二、主要内容三、总结 &#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 一、前言 在最新的 OpenAI 官方 APIs 文档中&#xff0c;Create chat completion 中新增了 top_logprobs 和 logprobs 这两个关键参数。 官方文档地址&#xff…

06.02 customizing plots with style sheets

使用 style 来配置 pyplot 风格 import matplotlib.pyplot as plt import numpy as np%matplotlib inlinestyle 是 pyplot 的一个子模块&#xff0c;方便进行风格转换&#xff0c; pyplot 有很多的预设风格&#xff0c;可以使用 plt.style.available 来查看&#xff1a; plt.…

GO语言笔记1-安装与hello world

SDK开发工具包下载 Go语言官网地址&#xff1a;golang.org&#xff0c;无法访问Golang中文社区&#xff1a;首页 - Go语言中文网 - Golang中文社区下载地址&#xff1a;Go下载 - Go语言中文网 - Golang中文社区 尽量去下载稳定版本&#xff0c;根据使用系统下载压缩包格式的安装…

linux释放交换空间-Swap

确保剩余内存比swap内存空间大&#xff0c;再执行以下操作&#xff0c;否则会宕机&#xff01; 查看swap分区 swapon -s 会查看到你的swap分区位置 停止swap分区 停止swap分区是将swap内存释放到实际内存中 swapoff /dev/dm-1开启swap分区 swap分区内存成功释放到实际内…

【一文入门】Git常用命令集锦--分支操作和版本管理篇

前言 Git 是一种分布式版本控制系统&#xff0c;可以帮助团队协作开发、管理和维护代码&#xff0c;提高代码质量和效率&#xff0c;掌握常用版本管理命令可以帮助我们更好地管理代码变更和历史记录。下面我将介绍开发中常用的一些Git分支操作和版本管理命令 1 分支操作 1.1 …

diffusers 源码待理解之处

一、训练DreamBooth时&#xff0c;相关代码的细节小计 ** class_labels timesteps 时&#xff0c;模型的前向传播怎么走&#xff1f;待深入去看 ** 利用class_prompt去生成数据&#xff0c;而不是instance_prompt class DreamBoothDataset(Dataset):"""A dat…

CCNP课程实验-05-Comprehensive_Experiment

目录 实验条件网络拓朴 基础配置实现IGP需求&#xff1a;1. 根据拓扑所示&#xff0c;配置OSPF和EIGRP2. 在R3上增加一个网段&#xff1a;33.33.33.0/24 (用Loopback 1模拟) 宣告进EIGRP&#xff0c;并在R3上将EIGRP重分布进OSPF。要求重分布进OSPF后的路由Tag值设置为666&…

一款超酷的一体化网站测试工具:Web-Check

Web-Check 是一款功能强大的一体化工具&#xff0c;用于发现网站/主机的相关信息。用于检查网页的工具&#xff0c;用于确保网页的正确性和可访问性。它可以帮助开发人员和网站管理员检测网页中的错误和问题&#xff0c;并提供修复建议。 它只需要输入一个网站就可以查看一个网…