2024年最新版 springboot+vue整合支付宝沙箱支付功能,一步一步带您实现完整的支付宝支付功能

目录

1、进入支付宝开放平台

1.1 登录支付宝账号后下拉选择网页/移动应用开发​编辑

1.2 创建网页应用​编辑

1.3 创建成功后进入沙箱 

1.4 点击启用公钥(有重要作用!springboot整合时会用到)​编辑

2、开始springboot与支付宝沙箱的整合

2.1导入支付宝api的依赖

2.2 配置 application.yml 沙箱参数

         2.3 引入支付宝沙箱的配置代码

2.3.1 引入alipay的java配置:AplipayConfig.java 

2.3.2 在过滤器和拦截器中忽略掉alipay的系列端口

2.3.3 新建AliPayController.java,定义了支付接口与支付回调接口:

2.3.4 编写AliPay.java  接收前端传来的参数

3、使用natapp进行内网穿透

3.1 进入natapp官网注册账号,并进行实名认证、与支付宝账号进行绑定。

3.2 下载指定版本的natapp应用

​3.2.1 运行natapp.exe

3.2.2 配置natapp中的隧道

​3.2.3 启动自己本机的web服务

3.3 配置application.yml中notifyUrl参数

4、支付宝沙箱支付前端Vue代码

5、启动项目并测试功能

1、进入支付宝开放平台

支付宝开发者平台icon-default.png?t=N7T8https://openhome.alipay.com/

1.1 登录支付宝账号后下拉选择网页/移动应用开发
1.2 创建网页应用
1.3 创建成功后进入沙箱 

        沙箱比较不好找到 沙箱地址在这里:

登录 - 支付宝欢迎登录支付宝,支付宝-全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验以及转账收款/水电煤缴费/信用卡还款等生活服务应用;为广大为从事电子商务的网站提供支付产品/支付服务的在线订购和技术支持等服务,帮助商家快速接入支付工具,高效、安全、快捷地开展电子商务。icon-default.png?t=N7T8https://open.alipay.com/develop/sandbox/app

1.4 点击启用公钥(有重要作用!springboot整合时会用到)

2、开始springboot与支付宝沙箱的整合

2.1导入支付宝api的依赖
         <!--引入支付宝支付 -->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-easysdk</artifactId>
            <version>2.2.1</version>
        </dependency>

        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.22.113.ALL</version>
        </dependency>
2.2 配置 application.yml 沙箱参数
#支付宝
alipay:
  appId: 
  appPrivateKey: 
  alipayPublicKey: 
  notifyUrl: 
  returnUrl: 

 这五个参数都是什么意思呢?

  •   appId:  沙箱中的应用id
  •   appPrivateKey:  应用私钥
  •   alipayPublicKey: 支付宝公钥
  •   notifyUrl: 调用支付宝支付接口后产生的回调,需要内网穿透,后面详细讲,先不配置
  •   returnUrl: 支付成功后的页面跳转,设置成你项目中的成功支付界面(可不填)

 appPrivateKey:  应用私钥与  alipayPublicKey: 支付宝公钥在这里:点击查看

2.3 引入支付宝沙箱的配置代码
2.3.1 引入alipay的java配置:AplipayConfig.java 
package com.songqiao.waimai.alipay.common;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
 
import javax.annotation.PostConstruct;
 
/**
 * @Author 
 * @Date Created in  2023/1/13 15:06
 * @DESCRIPTION:
 * @Version V1.0
 */
 
@Data
@Component
//读取yml文件中alipay 开头的配置
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
   private String appId;
   private String appPrivateKey;
   private String alipayPublicKey;
   //异步通知回调地址(可选)
   private String notifyUrl;
   //支付成功后的回调地址
   private String returnUrl;
 
 
   @PostConstruct
   public void init() {
      // 设置参数(全局只需设置一次)
      Config config = new Config();
      config.protocol = "https";
      config.gatewayHost = "openapi.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初始化成功=======");
   }
}
2.3.2 在过滤器和拦截器中忽略掉alipay的系列端口

2.3.3 新建AliPayController.java,定义了支付接口支付回调接口:
package com.songqiao.waimai.alipay.controller;

import com.alipay.easysdk.factory.Factory;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.songqiao.waimai.alipay.common.AliPayConfig;
import com.songqiao.waimai.alipay.payparameter.AliPay;
import com.songqiao.waimai.common.BaseContext;
import com.songqiao.waimai.common.R;
import com.songqiao.waimai.entity.AddressBook;
import com.songqiao.waimai.entity.Orders;
import com.songqiao.waimai.mapper.AddressBookMapper;
import com.songqiao.waimai.mapper.OrderMapper;
import com.songqiao.waimai.service.impl.OrderServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
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 com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePagePayRequest;
 
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
 * @Author 
 * @Date Created in  2023/5/5 15:23
 * @DESCRIPTION:
 * @Version V1.0
 */
@RestController
@RequestMapping("alipay")
@Transactional(rollbackFor = Exception.class)
public class AliPayController {
 
   @Resource
   AliPayConfig aliPayConfig;

   @Resource
   AddressBookMapper addressBookMapper;

   @Autowired
   OrderServiceImpl orderServiceImpl;

   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";

   @GetMapping("/pay") // 前端路径参数格式?subject=xxx&traceNo=xxx&totalAmount=xxx
   public void pay(AliPay aliPay, HttpServletResponse httpResponse) throws Exception {
      AlipayClient alipayClient = new DefaultAlipayClient(GATEWAY_URL, aliPayConfig.getAppId(),
              aliPayConfig.getAppPrivateKey(), FORMAT, CHARSET, aliPayConfig.getAlipayPublicKey(), SIGN_TYPE);
      AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
      request.setNotifyUrl(aliPayConfig.getNotifyUrl());
      request.setReturnUrl(aliPayConfig.getReturnUrl());
      request.setBizContent("{\"out_trade_no\":\"" + aliPay.getTraceNo() + "\","
              + "\"total_amount\":\"" + aliPay.getTotalAmount() + "\","
              + "\"subject\":\"" + aliPay.getSubject() + "\","
              + "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}");
      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();
   }

   @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));
         }
 
         String tradeNo = params.get("out_trade_no");
         String gmtPayment = params.get("gmt_payment");
         String alipayTradeNo = params.get("trade_no");
         // 支付宝验签
         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"));

            // 更新订单已支付的逻辑代码
           
         }
      }
      return "success";
   }

}

 注意!在notify接口中的支付宝验签通过后,编写支付成功的逻辑。例如:修改订单状态、更新菜品销量、清空购物车等等。

2.3.4 编写AliPay.java  接收前端传来的参数
package com.songqiao.waimai.alipay.payparameter;
 
import lombok.Data;
 
/**
 * @Author 
 * @Date Created in  2024/1/13 15:26
 * @DESCRIPTION: alipay接口参数
 * @Version V1.0
 */
@Data
public class AliPay {
   //订单编号
   private String traceNo;
   //商品金额
   private double totalAmount;
   //商品名称
   private String subject;
   //订单追踪号,商户自己生成,可已不使用
   private String alipayTraceNo;
}

 所有后端java代码已经over 你的代码结构应该是这样的:
 

        别忘了!咱们在application.yml中还有一个重要的参数 notifyUrl 没有配置,这个参数是支付成功后支付宝的回调函数访问本地系统的路径,需要以内网穿透的方式让支付宝访问本地系统。

3、使用natapp进行内网穿透

3.1 进入natapp官网注册账号,并进行实名认证、与支付宝账号进行绑定。

NATAPP-内网穿透 基于ngrok的国内高速内网映射工具natapp是基于ngrok的国内高速内网穿透专业服务商,独家彻底解决ngrok1.7内存泄漏问题.稳定拒绝掉线,适用于微信开发调试,本地架设演示服务器,外网可以访问,远程服务器,远程桌面,远程办公,游戏联机等icon-default.png?t=N7T8https://natapp.cn/

3.2 下载指定版本的natapp应用

我这里选用的是Windows 64位下载,下载并解压成功后的内容为:
3.2.1 运行natapp.exe

出现以下界面

3.2.2 配置natapp中的隧道

回到natapp官网,点击购买隧道->免费隧道->创建隧道并配置程序中的端口等信息


创建成功后点击我的隧道->点击配置->点击复制获取authtoken

 3.2.3 启动自己本机的web服务

在natapp.exe启动后的命令行输入natapp -authtoken=刚刚复制的token,就会与本机的8080端口映射成功!

出现如图所示状态后,那么恭喜你!外网即可访问你的本机的8080端口,支付宝api支付成功后即可完成回调!

3.3 配置application.yml中notifyUrl参数

把图中的代理地址填入即可完成全部后端的准备工作!咱们就可以去专心搞前端部分啦! 

4、支付宝沙箱支付前端Vue代码

调用后端接口并拼接get请求的参数,完成!

async goToPaySuccess(){
    //在这里我选择了window.open(url,'_self')形式,也就是不跳转新的页面,在本页面直接跳转
    window.open("http://127.0.0.1:8080/alipay/pay?subject="+"邬先生东北菜,"+this.note+"&traceNo="+Math.floor(Math.random() * 900000) + 100000+"&totalAmount="+this.goodsPrice,'_self')
 },

5、启动项目并测试功能

点击支付按钮后跳转支付界面,为了避免被当做违规图片,我把二维码遮盖了。

注意!大坑!此时要求你登录的支付宝账号密码是支付宝沙箱的账号密码!不要混淆! 

支付宝沙箱账号密码在沙箱中查看!登录 - 支付宝欢迎登录支付宝,支付宝-全球领先的独立第三方支付平台,致力于为广大用户提供安全快速的电子支付/网上支付/安全支付/手机支付体验以及转账收款/水电煤缴费/信用卡还款等生活服务应用;为广大为从事电子商务的网站提供支付产品/支付服务的在线订购和技术支持等服务,帮助商家快速接入支付工具,高效、安全、快捷地开展电子商务。icon-default.png?t=N7T8https://open.alipay.com/develop/sandbox/account

 输入账号密码后即可进行付款~

确认付款后会有两种结果:1.付款成功界面 2.付款成功后跳转到你指定的页面(在前面的application.yml的配置中设置) 如果没有配置就会展示成功界面,配置了就会在几秒后跳转到你配置的界面中去!

 大功告成!

         创作不易,如果您喜欢这篇文章请点赞关注,如果在跟着博主实操的过程中出现了问题可以在评论区说明,我会第一时间回复你!

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

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

相关文章

2024年【山东省安全员C证】考试及山东省安全员C证复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 山东省安全员C证考试是安全生产模拟考试一点通总题库中生成的一套山东省安全员C证复审考试&#xff0c;安全生产模拟考试一点通上山东省安全员C证作业手机同步练习。2024年【山东省安全员C证】考试及山东省安全员C证复…

电影《潜行》中说的蜜罐是什么(网络安全知识)

近期刘德华、彭于晏主演的电影《潜行》在网上掀起了轩然大波&#xff0c;电影中有提到网络蜜罐&#xff0c;这引起了很多观众的疑问&#xff0c;蜜罐到底是什么&#xff1f; 从字面意思上来看&#xff0c;蜜罐就是为黑客设下的诱饵。这是一种具有牺牲性质的计算机系统&#xff…

JS中的File(二):TypedArray和ArrayBuffer详解

目录 一、TypedArray 1、定义 2、注意事项 二、ArrayBuffer 1、定义和构造 2、属性 3、方法 4、使用意义 三、Blob、TypedArray和ArrayBuffer的互相转换 1、websocket接收arrayBuffer 2、blob转arrayBuffer 3、arrayBuffer to Blob 4、ArrayBuffer to Uint8数组&am…

机器人跟踪性能量化指标

衡量机械臂关节轨迹跟踪控制的性能可以通过以下几个方面来进行&#xff1a; 跟踪精度&#xff1a;这是衡量机械臂关节轨迹跟踪控制性能的最重要的指标。它反映了机械臂实际运动轨迹与期望运动轨迹之间的偏差。跟踪精度越高&#xff0c;说明机械臂的控制性能越好。运动范围&…

【数据开发】BI数据报表之数据可测试性设计与分析

文章目录 1、什么是BI&数据报表2、什么是可测试性3、数据测试与方法3.1 数据准确性与对比&#xff08;重要&#xff09;3.2 数据安全性 1、什么是BI&数据报表 数据报表是一种数据可视化工具 用于将数据以图表、表格和其他可视化形式呈现出来&#xff0c;以便用户可以…

BRC20通证的深度科普:它的潜力与如何导入到bitget

​BRC-20通证是什么&#xff1f; BRC-20通证&#xff1a;比特币上的“变形金刚”&#xff1f;&#xff01;不依赖智能合约&#xff0c;它们就像拥有超能力的外星人&#xff0c;直接在比特币的最小单位——聪上刻写JSON代码。哈哈&#xff0c;这比把房子建在乐高积木上还要刺激…

【信息论安全】:信源编码定理

一. 介绍 在点对点的通信中&#xff0c;信源编码定理&#xff08;source coding theorem&#xff09;满足可达性和可逆性。当信道是无噪声时&#xff0c;那么YX&#xff0c;这时就不需要信道编码。但是&#xff0c;信源编码依旧是有效的&#xff0c;可以提高数据传输效率&…

Java中的方法介绍

一、引入方法 /* 以下程序不使用方法&#xff0c;分析程序存在哪些缺点&#xff1f; *以下的代码都是完成两个int类型数据的和&#xff0c;相同的代码写了三遍&#xff08;只不过每一次参与求和的数据不同&#xff09; 代码没有得到重复使用。 *应该在java语言当中有这样的一种…

【Docker】镜像的构建与上传下载阿里云

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《Docker实战》。&#x1f3af;&#x1f3af; &…

SpringBoot视图渲染技术:整合Freemarker,常见指令和数据类型

目录 1.Freemarker 1.1.什么是Freemarker 1.2.Freemarker模板组成部分 1.3.优点 2.SpringBoot整合Freemarker 2.1.配置 2.2.数据类型 2.2.1.字符串 2.2.2.数值 2.2.3.布尔值 2.2.4.日期 2.3.常见指令 2.3.1.处理不存在的值 2.3.2.assign 2.3.3.if/elseif/else …

MongoDB - 库、集合、文档(操作 + 演示 + 注意事项)

目录 一、MongoDB 1.1、简介 a&#xff09;MongoDB 是什么&#xff1f;为什么要使用 MongoDB&#xff1f; b&#xff09;应用场景 c&#xff09;MongoDB 这么强大&#xff0c;是不是可以直接代替 MySQL &#xff1f; d&#xff09;MongoDB 中的一些概念 e&#xff09;Do…

FGSM方法生成交通信号牌的对抗图像样本

背景&#xff1a; 生成对抗样本&#xff0c;即扰动图像&#xff0c;让原本是“停车”的信号牌识别为“禁止驶入” 实验准备 模型&#xff1a;找一个训练好的&#xff0c;识别交通信号牌的CNN模型&#xff0c;灰度图像 模型地址&#xff1a;GitHub - Daulettulegenov/TSR_CNN:…

基于elementUI的el-table组件实现按住某一行数据上下滑动选中/选择或取消选中/选择鼠标经过的行

实现代码 <template><div :class"$options.name"><el-tablestyle"user-select: none"ref"table":data"tableData":row-class-name"row_class_name"mousedown.native"mousedownTable"row-click&q…

Elasticsearch 索引文档时create、index、update的区别【学习记录】

本文基于elasticsearch7.3.0版本。 一、思维导图 elasticsearch中create、index、update都可以实现插入功能&#xff0c;但是实现原理并不相同。 二、验证index和create 由上面思维导图可以清晰的看出create、index的大致区别&#xff0c;下面我们来验证下思维导图中的场景&…

树莓派ubuntu22桌面配置(一)

烧录系统至树莓派 下载系统&#xff1a;https://ubuntu.com/download/raspberry-pi 选择合适的版本下载 镜像安装器安装&#xff1a;终端输入&#xff1a; sudo snap install rpi-imager 打开镜像安装器&#xff0c;按照需求选择树莓派版本与要写入的系统还有安装的u盘 方案…

YOLOv5源码中的参数超详细解析(7)— yolo.py

前言:Hello大家好,我是小哥谈。YOLOv5是一种先进的目标检测算法,它可以实现快速和准确的目标检测。yolo.py是YOLOv5项目中的一个Python文件,用于实现目标检测算法。该文件包含了YOLOv5模型的定义、训练和推理过程。本节课就结合源码对yolo.py文件进行逐行解析~!🌈 前期…

【Vue3】2-12 : 【案例】搜索关键词加筛选条件的综合

本书目录&#xff1a;点击进入 一、【案例】搜索关键词加筛选条件的综合 1.1、逻辑 1.2、效果 1.3、json数据 - 02-data.json 1.4、代码 一、【案例】搜索关键词加筛选条件的综合 1.1、逻辑 计算属性 - 绑定list&#xff0c;并过滤 input 双向绑定 - 当input改变时&…

带你拿捏SpringBoot自动装配的核心技术?模块装配(@EnableXXX注解+@Import)+ 条件装配(@ConditionalXXX)

文章目录 Profile激活指定配置文件主配置文件中指定激活的profile命令行激活设置虚拟机参数激活 profile控制不到的地方 Spring原生的条件装配注解ConditionalConditional接口讲解案例讲解 Spring Boot封装的条件装配注解ConditionalXXX自己实现ConditionalOnBeanSpringBoot 源…

NLP论文阅读记录 - WOS | 2022 使用语言特征空间的抽象文本摘要的神经注意模型

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.相关工作三.本文方法3.1 总结为两阶段学习3.1.1 基础系统 3.2 重构文本摘要 四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 Neural A…