Springboot整合支付宝支付

news2025/2/13 6:00:14

支付宝支付功能

  • 步骤一:沙箱配置
    • 支付宝沙箱配置
  • 步骤二:使用内网穿透
  • 步骤三:开始对接
    • SDK
    • 配置文件
    • 支付

步骤一:沙箱配置

支付宝沙箱配置

需要有支付宝沙箱:提供一个虚拟的支付环境,用于测验调试,点击这里进入沙箱环境,可以打开支付宝开放平台
支付宝开放平台
image.png
在这里我们只需要里面的几个数据,分别为:

  1. 支付宝网关地址
  2. 支付宝的公钥和私钥
  3. 支付宝的APPID
  4. 支付宝提供的SDK

步骤二:使用内网穿透

目的是为了允许外部网络用户访问,这里可以使用natapp
为什么需要内网穿透呢?因为本质上调用人家的服务,当请求以后,支付宝需要返回给你信息,这就需要你的地址。这样才能找到我们的接口,我们才能根据他返回的信息做出一些业务处理。
natapp官网
image.png
使用免费的即可,需要进行实名认证
image.png
填写信息
image.png
在我的隧道中查看
image.png
下载客户端,根据自己需要下载我是windows64的
image.png
运行natapp
image.png
image.png
双击natapp
注意:需要将本地的web服务端口改为80,也就是将我们的项目端口改为80端口,这个80端口可以在natapp-》我的隧道-》隧道配置中进行修改
image.png
然后启动自己的web项目就可以访问到了,注意隧道的80端口一定要和项目的端口一样也是80,如果要修改,则去natapp中修改完再和项目保持一致

步骤三:开始对接

SDK

<dependency>
	<groupId>com.alipay.sdk</groupId>
	<artifactId>alipay-sdk-java</artifactId>
	<version>4.9.28.ALL</version>
</dependency>

配置文件

server:
        port: 80
        alipay:
        # appid
        appId: 自己的支付宝APPID
        # 应用私钥
        appPrivateKey: 支付宝开放平台应用私钥,前面已经介绍
        # 支付宝公钥
        alipayPublicKey: 支付宝开放平台应用公钥,前面已经介绍
        # 回调接口,支付宝通过什么接口通知你,这里就是填写具体接口地址,我们使用公网的地址以及接口uri /公网地址/uri
	# http://iw3naq.natappfree.cc是内网穿透的路径
        notifyUrl: http://iw3naq.natappfree.cc/alipay/notify
/**
 * 读取yml中的配置信息,自动填充到对应的属性
 */
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;

}

支付

1.具体步骤

  • 必须传递如下参数(支付订单号(必须唯一), 订单名称,订单金额)
  • 创建支付客户端 设定appid 公钥密钥等等信息,用于知道这个订单谁发出的,钱给到谁的账户
  • 将请求的订单号等等写入支付的请求对象中 并且请求对象设置回调接口以及支付后的接口
  • 支付客户端对象根据支付请求对象去执行,调用支付宝API
  • 这个API接口会返回一个表单页面,让用户去输入帐号密码(也就是谁来支付),成功显示金额等等信息,填写支付密码进行转账
  • 转账以后无论成功与否,支付宝都会调用你的回调接口,传入数据
    2.代码
    业务参数
/**
 * 支付宝支付请求对象 所需要的参数
 */
@Data
public class PayVO {
    private String out_trade_no; // 商户订单号 必填
    private String subject; // 订单名称 必填
    private BigDecimal total_amount; // 付款金额 必填
    private String body; // 商品描述 可空
}

支付宝客户端执行

@RestController
@RequestMapping("/alipay")
@Transactional(rollbackFor = Exception.class)
public class AliPayController {

    @Resource
    AliPayConfig aliPayConfig;

    @Resource
    private ShopOrderDao shopOrderMapper;
    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";

    /**
     * 支付接口 传入业务参数
     * 支付是一个我向你要钱的过程,设置api参数就是为了,知道收钱的人是谁,
     * 当执行以后支付宝会返回一个登录页面,支付的人输入帐号密码。并且确定金额输入支付密码进行支付
     * @param aliPay
     * @param httpResponse
     * @throws Exception
     */
    // 这里使用Get其实不是很恰当,应该使用post,这里为了调试方便使用Get
    @GetMapping("/pay")
    public void pay(PayVO aliPay, HttpServletResponse httpResponse) throws Exception {
        // 1、根据支付宝的配置生成一个支付客户端 客户端用于去调用支付宝的API
        // 官方写法
        AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);


        // 2、创建一个支付请求对象
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        // 设置回调接口
        request.setNotifyUrl(aliPayConfig.getNotifyUrl());
        // 商户订单号,商户网站订单系统中唯一订单号,必填,支付宝不允许有两个相同的订单号
        // 使用uuid生成 避免重复
        aliPay.setOut_trade_no(UUID.randomUUID().toString());
        String out_trade_no = aliPay.getOut_trade_no();
        // 付款金额,必填
        BigDecimal total_amount = aliPay.getTotal_amount();
        // 订单名称,必填
        String subject = aliPay.getSubject();
        // 商品描述,可空
        String body = aliPay.getBody();
        // 设置 业务参数 是一个json对象
        // 这个json对象 支付宝后台回去识别,根据这些参数进行处理,例如 金额,订单名称,商品描述
        request.setBizContent("{"out_trade_no":"" + out_trade_no + "","
                + ""total_amount":"" + total_amount + "","
                + ""subject":"" + subject + "","+ ""body":""+ body +"","
                + ""product_code":"FAST_INSTANT_TRADE_PAY"}");
        // 支付完以后跳转的地址
        request.setReturnUrl("http://loaclhost:9090/hello/pay");

        // 3. 客户端执行请求
        // 客户端执行请求,拿到响应的结果,返回给浏览器
        String form = "";
        try {
            // 调用阿里的SDK生成表单
            // 会收到支付宝的响应,响应的是一个页面,一开始是登陆,然后显示金额,让用户输入密码进行付款
            form = alipayClient.pageExecute(request).getBody();
        } catch (AlipayApiException e) {
            e.printStackTrace();
        }
        httpResponse.setContentType("text/html;charset=" + CHARSET);
        // 直接将完整的表单html输出到页面
        httpResponse.getWriter().write(form);
        httpResponse.getWriter().flush();
        httpResponse.getWriter().close();
    }

3.效果
输入地址
http://localhost:80/alipay/pay?subject=测试商品&total_amount=1000
支付宝返回页面
image.png
输入帐号密码(沙箱有测试的密码)
image.png
image.png
输入支付密码支付
image.png
image.png
4.回调接口
支付宝返回信息
image.png

"gmt_create" -> "2024-03-16 22:40:26"
        "charset" -> "utf-8"
        "gmt_payment" -> "2024-03-16 22:40:30"
        "notify_time" -> "2024-03-16 22:40:31"
        "subject" -> "测试商品"
        "sign" -> "XfBcgT1lIYpxYm0DzaBtLz7WjzxHxhBK4gUdmDCtD/JTAwhohqu"
        "buyer_id" -> "2088722031942622"
        "body" -> "null"
        "invoice_amount" -> "1000.00"
        "version" -> "1.0"
        "notify_id" -> "2024031601222224031142620502419"
        "fund_bill_list" -> "[{"amount":"1000.00","fundChannel":"ALIPAYACCOUNT"}]"
        "notify_type" -> "trade_status_sync"
        "out_trade_no" -> "96b14931-b0a7-49bb-aa93-498432247a4"
        "total_amount" -> "1000.00"
        "trade_status" -> "TRADE_SUCCESS"
        "trade_no" -> "20240316220014426205023040"
        "auth_app_id" -> "9021000135634074"
        "receipt_amount" -> "1000.00"
        "point_amount" -> "0.00"
        "buyer_pay_amount" -> "1000.00"
        "app_id" -> "90210001354"
        "sign_type" -> "RSA2"
        "seller_id" -> "20887976059"

5.具体实现

@PostMapping("/notify")  // 注意这里必须是POST接口
public String payNotify(HttpServletRequest request) throws Exception {
        // 判断返回状态trade_status 支付成功是TRADE_SUCCESS
        if (request.getParameter("trade_status").equals("TRADE_SUCCESS")) {
        System.out.println("=========支付宝异步回调========");

        Map<String, String> params = new HashMap<>();
        // 返回的所有元素 其中有gmt_create=2024-03-16 22:26:17, charset=utf-8, gmt_payment=2024-03-16 22:26:21, notify_time=2024-03-16 22:26:23, subject=测试商品
        Map<String, String[]> requestParams = request.getParameterMap();
        for (String name : requestParams.keySet()) {
        // servlet写法 通过key获取value
        params.put(name, request.getParameter(name));
        }
        System.out.println(params);
        System.out.println(params.size());
        String tradeNo = params.get("out_trade_no");
        String gmtPayment = params.get("gmt_payment");
        // 支付宝验签
        // 这里必须要初始化不然报错
        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"));
        // 更新订单未已支付
        // 做一些业务上的处理 例如说支付成功以后 更新订单状态 改为已支付等等
        ShopOrder order = new ShopOrder();
        order.setId(tradeNo);
        order.setStatus("1");
        order.setZhhifuTime(gmtPayment);
        shopOrderMapper.save(order);
        }
        }
        return "success";
        }

以上代码可能有问题,需要调整,sdk没有初始化
修改代码

/**
 * 读取yml中的配置信息,自动填充到对应的属性
 */
@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;

    /**
     * 初始化sdk 这样回调接口的时候 才能知道sdk的基础信息
     */
    @PostConstruct
    public void init() {
        // 设置参数(全局只需设置一次)
        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = "openapi-sandbox.dl.alipaydev.com";
        config.signType = "RSA2";
        config.appId = this.appId;
        config.merchantPrivateKey = this.appPrivateKey;
        config.alipayPublicKey = this.alipayPublicKey;
        config.notifyUrl = this.notifyUrl;
        Factory.setOptions(config);
        System.out.println("=======支付宝SDK初始化成功=======");
    }
}

完成

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

deepseek+kimi一键生成PPT

1、deepseek生成大纲内容 访问deepseek官方网站&#xff1a;https://www.deepseek.com/ 将你想要编写的PPT内容输入到对话框&#xff0c;点击【蓝色】发送按钮&#xff0c;让deepseek生成内容大纲&#xff0c;并以markdown形式输出。 等待deepseek生成内容完毕后&#xff0c…

基于ssm的超市订单管理系统

一、系统架构 前端&#xff1a;jsp | web components | jquery | css | ajax 后端&#xff1a;spring | springmvc | mybatis 环境&#xff1a;jdk1.8 | mysql | maven | tomcat 二、代码及数据 三、功能介绍 01. 登录 02. 首页 03. 订单管理 04. 供应…

AnyPlace:学习机器人操作的泛化目标放置

25年2月来自多伦多大学、Vector Inst、上海交大等机构的论文“AnyPlace: Learning Generalized Object Placement for Robot Manipulation”。 由于目标几何形状和放置的配置多种多样&#xff0c;因此在机器人任务中放置目标本身就具有挑战性。为了解决这个问题&#xff0c;An…

【DeepSeek】在本地计算机上部署DeepSeek-R1大模型实战(完整版)

【作者主页】Francek Chen 【专栏介绍】 ⌈ ⌈ ⌈人工智能与大模型应用 ⌋ ⌋ ⌋ 人工智能&#xff08;AI&#xff09;通过算法模拟人类智能&#xff0c;利用机器学习、深度学习等技术驱动医疗、金融等领域的智能化。大模型是千亿参数的深度神经网络&#xff08;如ChatGPT&…

基于全志T507的边缘计算机,推动光伏电站向智能运维转型

智能监控与维护 光伏电站通常分布在广阔的地域内&#xff0c;传统的监控方式往往需要大量的人力物力进行现场检查和数据采集。采用全志T507为核心的嵌入式工控机或边缘计算控制器可以实现光伏电站的实时监测&#xff0c;通过连接传感器网络收集电站各个组件的工作状态信息&…

用户认证练习实验

一.拓扑 二.sw2配置 三.ip配置 四.dhcp分配IP地址 五.安全区域配置 六.防火墙地址组信息 七.管理员 创建管理员角色 创建管理员 启动tenlnet 八.用户认证配置 认证策略 九.安全策略配置

【登录认证】

目录 一. 会话技术1.1 cookie1.2 session1.3 令牌方案 二. JWT令牌三. 过滤器Filter四. 拦截器Interceptor \quad 一. 会话技术 \quad \quad 1.1 cookie \quad \quad 1.2 session \quad \quad 1.3 令牌方案 \quad \quad 二. JWT令牌 \quad \quad 三. 过滤器Filter \quad \quad …

DeepSeek 赋能智慧教育 | 讯方“教学有方”大模型全面接入 DeepSeek!

国产 DeepSeek 大模型以强大的深度学习能力和广泛应用场景迅速火爆全球&#xff0c;其在智能对话、文本创作、语义解析、计算推理、代码生成与补全等多个应用领域&#xff0c;展现出了无与伦比的实力和魅力。2月10日 &#xff0c;由讯方技术自研的教育行业大模型“教学有方”全…

Unity中自定义协程的简单实现

在 Unity 中&#xff0c;协程&#xff08;Coroutine&#xff09;是一种非常强大的工具&#xff0c;它允许我们在不阻塞主线程的情况下&#xff0c;将代码的执行分成多个步骤&#xff0c;在不同的帧中执行。 Unity中协程实现原理 迭代器与状态机&#xff1a;本质上是基于C#的迭…

打开Visual Studio Code的时候发现未检测到适用于linux的windows子系统,那么该问题要如何解决?

两个月没有使用vscode编写代码&#xff0c;今天使用的时候发现了以上的问题导致我的vscode无法编写程序&#xff0c;接下来我将本人解决该问题的思路分享给大家。 首先我们要清楚WSL是适用于linux的window的子系统&#xff0c;是一个在Windows 10\11上能够运行原生Linux二进制可…

Linux(socket网络编程)TCP连接

Linux&#xff08;socket网络编程&#xff09;TCP连接 基础文件目录函数系统进程控制函数fork()exec系列函数void abort(void)void assert(int expression)void exit(int status)void _exit(int status)int atexit(void (*func)(void))int on_exit(void (*function)(int,void*)…

Rust学习总结之所有权(一)

不管是计算机的哪种语言&#xff0c;都有内存的管理方式。主流有两种&#xff0c;一是以C为代表的由开发者来决定申请和释放内存&#xff0c;二是以Python为代表的通过语言本身的垃圾回收机制来自动管理内存。Rust开辟了第三种方式&#xff0c;通过所有权系统管理内存。 Rust所…

汇编简介常用语法

为什么要有汇编 因为Cortex-A芯片一上电SP指针还没初始化&#xff0c;C环境还没准备 好&#xff0c;所以肯定不能运行C代码&#xff0c;必须先用汇编语言设置好C环境&#xff0c;比如初始化DDR、设置SP 指针等等&#xff0c;当汇编把C环境设置好了以后才可以运行C代码 GNU语法…

ANR学习

一、ANR 概述 ANR 是 Android 系统用于监控应用是否及时响应的关键机制。形象地说&#xff0c;如同设置定时炸弹场景&#xff1a;系统的中控系统&#xff08;system_server 进程&#xff09;启动倒计时&#xff0c;若应用进程在规定时间内未完成特定任务&#xff0c;中控系统将…

Tcp_socket

Tcp不保证报文完整性&#xff08;面向字节流&#xff09; 所以我们需要在应用层指定协议&#xff0c;确保报文完整性 // {json} -> len\r\n{json}\r\n bool Encode(std::string &message) {if(message.size() 0) return false;std::string package std::to_string(m…

< 自用文儿 > 在 Ubuntu 24 卸载 Docker 应用软件与运行的容器

环境&#xff1a; Host: usw OS: Ubuntu 24.04 TLS 目标: 卸载在运行的 Docker APP。 &#xff08;上运行了一个 container: 可以在线看 WSJ RSS 新闻&#xff0c;都 docker 预装两个网口&#xff0c;今天发现路由表有些看不懂&#xff0c;决定卸载&#xff09; 卸载 Dock…

基于 SpringBoot 和 Vue 的智能腰带健康监测数据可视化平台开发(文末联系,整套资料提供)

基于 SpringBoot 和 Vue 的智能腰带健康监测数据可视化平台开发 一、系统介绍 随着人们生活水平的提高和健康意识的增强&#xff0c;智能健康监测设备越来越受到关注。智能腰带作为一种新型的健康监测设备&#xff0c;能够实时采集用户的腰部健康数据&#xff0c;如姿势、运动…

Python的那些事第十八篇:框架与算法应用研究,人工智能与机器学习

人工智能与机器学习&#xff1a;框架与算法应用研究 摘要 本文深入探讨了人工智能与机器学习领域的核心框架和技术&#xff0c;包括TensorFlow、PyTorch和Scikit-learn库。文章首先介绍了TensorFlow和PyTorch的安装与配置方法&#xff0c;详细阐述了它们的基础概念&#xff0c…

java微服务常用技术

Spring Cloud Alibaba 1 系统架构演进 随着互联网行业的发展,对服务的要求也越来越高,服务架构也从单体架构逐渐演变为现在流行的微服务架构。 1.1 单体架构 早期的软件系统通常是基于单体应用架构设计的,也就是将整个系统作为一个单一的、可执行的应用程序来构建和维护…

【Qt 常用控件】多元素控件(QListWidget、QTabelWidgt、QTreeWidget)

**View和**Widget的区别&#xff1f; **View的实现更底层&#xff0c;**Widget是基于**View封装实现的更易用的类型。 **View使用MVC结构 MVC是软件开发中 经典的 软件结构 组织形式&#xff0c;软件设计模式。 M&#xff08;model&#xff09;模型。管理应用程序的核心数据和…