基于 Spring Boot 支付宝沙箱支付(Java 版本)

基于 Spring Boot 支付宝沙箱支付(Java 版本)

  • 步骤
    • 第一步:使用支付宝账户登录,打开控制台,进入沙箱环境
    • 第二步:配置内网穿透账号
    • 第三步:引入支付宝 SDK
    • 第四步: 配置 SpringBoot
    • 第五步: AliPayConfig.java 读取配置
    • 第六步: AliPayController

步骤

第一步:使用支付宝账户登录,打开控制台,进入沙箱环境

打开沙箱地址:https://open.alipay.com/develop/sandbox/app
在这里插入图片描述
在这里插入图片描述需要获取:AppId、支付宝网关地址、应用私钥、支付宝公钥

第二步:配置内网穿透账号

  1. 注册 https://natapp.cn/

  2. 购买免费隧道
    在这里插入图片描述在这里插入图片描述注意:需要记住这个 authtoken,配置文件用得到

  3. 配置隧道
    在这里插入图片描述

  4. 文件 config 配置

#将本文件放置于natapp同级目录 程序将读取 [default] 段
#在命令行参数模式如 natapp -authtoken=xxx 等相同参数将会覆盖掉此配置
#命令行参数 -config= 可以指定任意config.ini文件
[default]
authtoken= 将隧道的authtoken填进去               #对应一条隧道的authtoken
clienttoken=                    #对应客户端的clienttoken,将会忽略authtoken,若无请留空,
log=none                        #log 日志文件,可指定本地文件, none=不做记录,stdout=直接屏幕输出 ,默认为none
loglevel=ERROR                  #日志等级 DEBUG, INFO, WARNING, ERROR 默认为 DEBUG
http_proxy=                     #代理设置 如 http://10.123.10.10:3128 非代理上网用户请务必留空
  1. 配置文件需要与 natapp 放在同级目录下
    在这里插入图片描述
  2. 启动 natapp
    在这里插入图片描述

为什么要使用 NATAPP?
因为要把本地的服务暴露到公网,让支付宝可以调用我们的接口给我们传递数据

第三步:引入支付宝 SDK

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

第四步: 配置 SpringBoot

alipay:
  appId: xxx
  #  应用私钥
  appPrivateKey: xxx
  # 支付宝公钥
  alipayPublicKey:xxx
  #  每次重启会变化
  notifyUrl: http://ju2jpk.natappfree.cc/api/notify
  #natapp 代 理 的 url +/alipay/notify,这个是用于启动支付宝回调函数 notify 的接口

应用私钥和支付宝公钥可以用默认的,也可以自己配置,若自己配置的话需要使用支付宝开放平台密钥工具
在这里插入图片描述

第五步: AliPayConfig.java 读取配置

package com.projects.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties(prefix = "alipay") //读取配置文件中的alipay
public class AliPayConfig {

    private String appId; //支付宝APPID
    private String appPrivateKey; //应用私钥
    private String alipayPublicKey; //支付宝公钥
    private String notifyUrl; //支付宝通知本地接口完整地址

    public String getAppId() {
        return appId;
    }

    public void setAppId(String appId) {
        this.appId = appId;
    }

    public String getAppPrivateKey() {
        return appPrivateKey;
    }

    public void setAppPrivateKey(String appPrivateKey) {
        this.appPrivateKey = appPrivateKey;
    }

    public String getAlipayPublicKey() {
        return alipayPublicKey;
    }

    public void setAlipayPublicKey(String alipayPublicKey) {
        this.alipayPublicKey = alipayPublicKey;
    }

    public String getNotifyUrl() {
        return notifyUrl;
    }

    public void setNotifyUrl(String notifyUrl) {
        this.notifyUrl = notifyUrl;
    }

}

第六步: AliPayController

package com.example.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.common.AliPayConfig;
import com.example.entity.Orders;
import com.example.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;

//  https://natapp.cn/
// ekihat7647@sandbox.com
@RestController
@RequestMapping("/alipay")
public class AliPayController {

    // 支付宝沙箱网关地址
    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;

    @GetMapping("/pay")  //  /alipay/pay?orderNo=xxx
    public void pay(String orderNo, HttpServletResponse httpResponse) throws Exception {
        // 查询订单信息
        Orders orders = ordersService.selectByOrderNo(orderNo);
        if (orders == null) {
            return;
        }
        // 1. 创建Client,通用SDK提供的Client,负责调用支付宝的API
        AlipayClient 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.put("out_trade_no", orders.getOrderNo());  // 我们自己生成的订单编号
        bizContent.put("total_amount", orders.getTotal()); // 订单的总金额
        bizContent.put("subject", orders.getGoodsName());   // 支付的名称
        bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");  // 固定配置
        request.setBizContent(bizContent.toString());
        request.setReturnUrl("http://localhost:8080/orders"); // 支付完成后自动跳转到本地页面的路径
        // 执行请求,拿到响应的结果,返回给浏览器
        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();
    }

    @PostMapping("/notify")  // 注意这里必须是POST接口
    public void 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));
            }

            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);
            }
        }
    }

}

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Prometheus实战篇:Alertmanager配置概述及告警规则

Prometheus实战篇:Alertmanager配置概述及告警规则 在此之前,环境准备和安装我就不在重复一遍了.可以看之前的博客,这里我们直接步入正题. Alertmanager配置概述 Alertmanager主要负责对Prometheus产生的告警进行统一处理,因此在Alertmanager配置中一般会包含以下几个主要部分…

网安入门14-文件包含(file:// )

​ 什么是文件包含漏洞——来自ChatGPT4 文件包含漏洞是指应用程序在加载文件时&#xff0c;允许用户控制被加载文件的名称&#xff0c;从而导致恶意代码的执行或敏感信息的泄露。文件包含漏洞主要分为两种&#xff1a; 本地文件包含漏洞&#xff08;LFI&#xff09; &#…

无软件消抖的独立式键盘输入实验

#include<reg51.h> // 包含51单片机寄存器定义的头文件 sbit S1P1^4; //将S1位定义为P1.4引脚 sbit LED0P3^0; //将LED0位定义为P3.0引脚 void main(void) //主函数 { LED00; //P3.0引脚输出低电平 while(1) { if(S10) //P1.4引…

VSCode添加Python解释器并安装Python库

目录 一、安装VSCode 二、安装Python解释器 1、安装包链接 2、安装过程 3、测试 4、安装flake8和yapf两个包 &#xff08;1&#xff09;安装flake8包 &#xff08;2&#xff09;安装yapf包 三、VSCode中选择python解释器 一、安装VSCode VSCode安装教程&#xff08;默…

Java设计模式:责任链模式

❤ 作者主页&#xff1a;欢迎来到我的技术博客&#x1f60e; ❀ 个人介绍&#xff1a;大家好&#xff0c;本人热衷于Java后端开发&#xff0c;欢迎来交流学习哦&#xff01;(&#xffe3;▽&#xffe3;)~* &#x1f34a; 如果文章对您有帮助&#xff0c;记得关注、点赞、收藏、…

java基于SSM的旅游论坛设计与实现论文

目 录 目 录 I 摘 要 III ABSTRACT IV 1 绪论 1 1.1 课题背景 1 1.2 研究现状 1 1.3 研究内容 2 2 系统开发环境 3 2.1 vue技术 3 2.2 JAVA技术 3 2.3 MYSQL数据库 3 2.4 B/S结构 4 2.5 SSM框架技术 4 3 系统分析 5 3.1 可行性分析 5 3.1.1 技术可行性 5 3.1.2 操作可行性 5 3…

Python的安装与卸载【Windows系统】

在 Windows 上安装与卸载 Python Python的安装 下载Python 安装Python 下载完后打开安装包 注意最底下的"Add Python 3.8 to Path"&#xff08;将Python加入环境变量&#xff09;一定要勾选&#xff01;&#xff01;&#xff01;这样就可以免去之后环境配置的烦恼…

掌握视频节奏,玩转剪辑艺术!,轻松调整视频播放速度与秒数的技巧大揭秘

你是否经常觉得视频播放得太快或太慢&#xff0c;无法满足你的观看需求&#xff1f;或者想要控制视频的长度&#xff0c;却不知道该如何下手&#xff1f;今天&#xff0c;我们将为你揭秘几种简单又实用的方法&#xff0c;让你轻松调整视频的播放速度和秒数&#xff01; 首先&a…

Linux -- firewalld的富语言规则

1. Firewalld支持两种类型的NAT&#xff1a;IP地址伪装和端口转发。 &#xff08;1&#xff09;IP地址伪装 地址伪装&#xff08;masquerade)&#xff1a;通过地址伪装&#xff0c;NAT 设备将经过设备的包转发到指定接收方&#xff0c;同时将通过的数据包的源地址更改为其自己的…

【tensorflowflutterweb】机器学习模型怎样用到前端上(未写完)

书接上回 在上一章 我们谈了怎么根据项目需求构建一个简单的机器学习模型。 ​​​​​​ ​​​​​​【tensorflow&flutter】自己写个机器学习模型用在项目上&#xff1f;-CSDN博客文章浏览阅读852次&#xff0c;点赞22次&#xff0c;收藏15次。【tensorflow&flutter…

k8s的存储卷之静态

存储卷----数据卷 容器内的目录和宿主机的目录进行挂载 容器在系统上的生命周期是短暂的&#xff0c;delete&#xff0c;k8s用控制创建的pod&#xff0c;delete相当于重启&#xff0c;容器的状态也会回复到初始状态 一旦回到初始状态&#xff0c;所有的后天编辑的文件都会消…

C++力扣题目110--平衡二叉树

给定一个二叉树&#xff0c;判断它是否是高度平衡的二叉树。 本题中&#xff0c;一棵高度平衡二叉树定义为&#xff1a; 一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1 。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;t…

大数据系列之:腾讯云服务器性能和价格比较

大数据系列之&#xff1a;腾讯云服务器性能和价格比较 一、磁盘性能和价格比较二、高性能云硬盘三、ssd云硬盘四、极速型ssd云硬盘五、增强型ssd云硬盘六、查看腾讯云服务器价格 一、磁盘性能和价格比较 磁盘名称高性能ssd云硬盘极速型ssd云硬盘增强型ssd云硬盘规格500g 5800 …

UM2003A 一款200 ~ 960MHz ASK/OOK +18dBm 发射功率的单发射芯片

UM2003A 是一款工作于 200 ~ 960MHz 频段的单片集成、高性能、可独立运行的 OOK 发射器。内部集成的 OTP 方便用户对各种射频参数以及特色功能进行编程。该芯片以其高集成度和低功耗的设计&#xff0c;特别适用于低成本&#xff0c;低功耗&#xff0c;电池驱动的无线发射应用。…

Unity URP下阴影锯齿

1.概述 在Unity开发的URP项目中出现阴影有明显锯齿。如下图所示&#xff1a; 并且在主光源的Shadow Type已经是Soft Shadows模式了。 2.URP Asset 阴影出现锯齿说明阴影质量不高&#xff0c;所以要先找到URP Asset文件进行阴影质量参数的设置。 1.打开PlayerSetting找到Graph…

切分大文件sql为小份

数据库太大了&#xff0c;整个备份导入出问题或者慢&#xff0c;需要将整个库按照表分割&#xff08;一个表一个sql文件&#xff09; 环境 win10 工具&#xff1a;python3.7pycharm 要分割的文件大小&#xff1a;6G&#xff0c;sql文件import redbname with open(best**.sql,…

C++标准学习--多线程

在以往多线程的实现的时候&#xff0c;都是自己去亲自创建线程&#xff0c;采用特殊flag 及锁控制线程的运转状态。这无可厚非&#xff0c;但又似乎有重复造轮子的嫌疑。最近发现了一个线程池的轮子&#xff0c;很不错&#xff0c;ZZ一下。 C多线程线程池&#xff08;全详解&a…

理解Herbrand Equivalence

笔者最近在看GVN的一系列论文&#xff0c;总会看到一个概念叫Herbran Equivalence&#xff0c;依靠这种定义&#xff0c;能够判断一个GVN算法是否是complete的&#xff0c;也即检测一个算法是否是precise的&#xff0c;只有找到所有Herbrand Equivalence关系的算法才能称得上是…

Python基础知识:整理9 文件的相关操作

1 文件的打开 # open() 函数打开文件 # open(name, mode, encoding) """name: 文件名&#xff08;可以包含文件所在的具体路径&#xff09;mode: 文件打开模式encoding: 可选参数&#xff0c;表示读取文件的编码格式 """ 2 文件的读取 文…

18-链表-移除链表元素

这是链表的第18题&#xff0c;力扣链接。 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,…