支付宝沙箱环境 支付
一 什么是沙箱:
沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境
支付宝正式和沙箱环境的区别 :
AI:
-
从沙箱到正式环境:
-
当应用程序开发完成后,需要将应用程序从沙箱环境迁移到正式环境。
-
这通常涉及到更新应用程序中的配置文件,更换正式的 AppID 和密钥等凭证。
二 注册使用
网址:登录 - 支付宝 点击 进行注册
查看信息:appid
点击查看 应用密钥与支付宝公钥 :appPrivateKey 与 publiceKey
记录一下卖家信息:
三 实现
支付实现的步骤:1.导入依赖 2.配置参数 3.调用方法(API调用) 4.处理响应或异常
具体实现可查看官网文档: 小程序文档 - 支付宝文档中心
小程序文档 - 支付宝文档中心
简易版概述小程序文档 - 支付宝文档中心
小程序文档 - 支付宝文档中心
查看api使用规范 根据需求选择对应的接口方法
比如下面我们要实现的电脑网站的支付功能
对应的就是 Factory.Payment.Page.pay()
Easy 版
有拦截器的 注意放开路径
3.1 导入项目依赖
<!-- https://mvnrepository.com/artifact/com.alipay.sdk/alipay-easysdk -->
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId><version>2.2.0</version>
</dependency>
3.2 编写配置信息:
其中关于//@PostConstruct 是一个 Java 注解,用于标记需要在依赖注入完成后执行的方法。它表示该方法应该在对象创建和属性注入完毕后由容器自动调用,以完成初始化工作。
@Component
@ConfigurationProperties(prefix = "alipay")
@Datapublic class AlipayConfig {// 应用Idprivate String appId;// 应用私钥private String appPrivateKey;// 支付宝公钥private String publiceKey;// 回调接口路径private String notifyUrl;// 支付宝网关地址private String gatewayHost;@PostConstruct//@PostConstruct 是一个 Java 注解,用于标记需要在依赖注入完成后执行的方法。// 它表示该方法应该在对象创建和属性注入完毕后由容器自动调用,以完成初始化工作。// 此注解的方法无参数,返回类型可为空或其他类型。主要用于确保对象完全初始化。public void init(){Config config = new Config();// 基础配置config.protocol = "https";config.gatewayHost = this.gatewayHost;// 支付宝网关地址config.signType = "RSA2";// 业务配置config.appId = this.appId;config.merchantPrivateKey = this.appPrivateKey;config.alipayPublicKey = this.publiceKey;config.notifyUrl = this.notifyUrl;// 将配置信息, 添加到相应的工厂类Factory.setOptions(config);System.out.println("支付宝初始化配置完成");}
}
application.properties
其中 appid appPrivateKey publiceKey 在开发者平台获取
gatewayHost 大家都一样 无需更改
notifyUrl 是内网穿透这里使用不到 现在随便写都可以
alipay.appid=9021000139682312
alipay.appPrivateKey=MIIEvwIBADANBgkqhkiG9w0BAQEFAAS...
alipay.publiceKey=MIIBIjANBgkqhkiG9w0BAQEFAAOC.......
alipay.notifyUrl=http://xxxxxxx/api/alipay/notify
alipay.gatewayHost=openapi-sandbox.dl.alipaydev.com
3.3 调用支付方法
我这里直接在cotroller层编写
@RestController
@RequestMapping("/api/alipay")
public class PayController {/*** 订单支付接口, 核心是调用支付宝的 Factory.Payment.Page().pay() 方法* @param subject 支付对象信息* @param outTradeNo 订单号* @param totalAmount 订单金额* @param returnUrl 支付成功以后返回的页面地址* @return*/@GetMapping("/pay")public void pay(String subject, String outTradeNo, String totalAmount, String returnUrl, HttpServletResponse httpResponse) throws Exception {// 使用支付宝支付页面接口进行支付AlipayTradePagePayResponse response = Factory.Payment.Page().pay(subject, outTradeNo, totalAmount, returnUrl);System.out.println(response);// response.getBody();// 设置HTTP响应内容类型为HTML,编码为UTF-8httpResponse.setContentType("text/html;charset=utf-8");// 向HTTP响应写入支付宝支付页面接口返回的响应体httpResponse.getWriter().write(response.getBody());// 刷新HTTP响应输出流,确保数据立即发送到客户端httpResponse.getWriter().flush();// 关闭HTTP响应输出流,释放资源httpResponse.getWriter().close();}}
Java
可以进行测试后端了!!!!!!!!
可以进行测试后端了!!!!!!!!
可以进行测试后端了!!!!!!!!
http://localhost:8080/api/alipay/pay?subject=%E7%81%AB%E8%BD%A6%E7%A5%A8%E6%94%AF%E4%BB%98&outTradeNo=63172637&totalAmount=16.8&returnUrl=http%3A%2F%2Flocalhost%3A8080%2Fpayok.html%3ForderId%3D312323
3.4 回调方法 配合内网穿透使用
回调就是支付宝在进行扣款操作之后 调用我们的后端 告诉我们支付结果
回调方法如下:
回调中有个验证操作来源于:调用官方给我们提供的方法来验证数据的真实性。
@PostMapping("/notify")public String notify(@RequestParam Map parameterMap) throws Exception {String tradeStatus = parameterMap.getOrDefault("trade_status","").toString();if (tradeStatus.trim().equals("TRADE_SUCCESS")) {// 验证请求的有效性if (Factory.Payment.Common().verifyNotify(parameterMap)) {System.out.println("通过支付宝的验证");System.out.println("订单id:" + parameterMap.get("out_trade_no"));}else {System.out.println("支付验证不通过");}}return "success";}
需要先开启内网穿透
服务器为localhost:8080 支付宝无法调用:
注意:如果是部署云服务器就不需要内网穿透了 只不过需要我我们对回调的参数进行相对应的修改!!!!
3.5 内网穿透工具
1.路由侠-局域网变公网
设置 信息 主机号
查看内网映射:
测试: 说明映射是没有问题的 成功调用了后端
修改 alipay.notifyUrl 的 配置信息
alipay.notifyUrl=http://xxxk.w1.luyouxia.net/api/alipay/notify
再次进行支付测试:s
这里加上vue进行测试:
前端 vue:
3.6 前端
<template><h2>支付</h2><el-form :inline="true" :model="form" class="demo-form-inline"><el-form-item label="支付对象信息"><el-input v-model="form.subject" placeholder="请输入" clearable /></el-form-item><el-form-item label="订单号"><el-input v-model="form.outTradeNo" placeholder="请输入" clearable /></el-form-item><el-form-item label="订单金额"><el-input-number v-model="form.totalAmount" placeholder="请输入" clearable /></el-form-item><el-form-item label="支付成功以后返回的页面地址"><el-input v-model="form.returnUrl" placeholder="请输入" clearable /></el-form-item><el-form-item><el-button type="primary" @click="onSubmit">提交</el-button></el-form-item></el-form><br><h2>退款</h2><el-form :inline="true" :model="form2" class="demo-form-inline"><el-form-item label="退款单号"><el-input v-model="form2.outTradeNo" placeholder="请输入" clearable /></el-form-item><el-form-item label="退款金额"><el-input-number v-model="form2.refundAmount" placeholder="请输入" clearable /></el-form-item><el-form-item><el-button type="primary" @click="onSubmit2">提交</el-button></el-form-item></el-form>
</template>
<script setup lang="ts">
import { onMounted, ref } from 'vue';
import dayjs from 'dayjs';
import router from '@/router';
import { ElNotification } from 'element-plus'
import { alipayApi } from '@/api';
const form = ref({subject: '小米su8',outTradeNo: dayjs().format('YYYYMMDDHHmmss'),totalAmount: 188888,returnUrl: 'http://localhost:5000/paysuccess'
})const form2 = ref({outTradeNo: '20220422164101',refundAmount: 18888,
})
const onSubmit = () => {let returnUrl = encodeURIComponent(form.value.returnUrl)window.location.href = "http://localhost:8080/api/alipay/pay?subject=" + `${form.value.subject}` + "&outTradeNo=" + `${form.value.outTradeNo}`+ "&totalAmount=" + `${form.value.totalAmount}` + "&returnUrl=" + `${returnUrl}`
}
const onSubmit2 = () => {alipayApi.refund.call({outTradeNo: form2.value.outTradeNo,refundAmount: form2.value.refundAmount}).then(_res => {ElNotification({title: '提示',message: '退款成功',type: 'success',})})
}</script>
测试结果
一方面 : 前端返回我们设置的 returnUrl 界面
另一方: 后端执行 配置的 alipay.notifyUrl=http://xxxk.w1.luyouxia.net/api/alipay/notify
成功
3.7 退款
调用 refund 交易退款方法
@GetMapping("/refund")public String refund( String outTradeNo,Float refundAmount) {try {
com.alipay.easysdk.payment.common.models.AlipayTradeRefundResponse response = Factory.Payment.Common().refund(outTradeNo, String.valueOf(refundAmount));System.out.println(response);if (response.msg.equals("Success")){return "退款成功";}else {throw new BizException(777, "退款失败");}}catch (Exception e){e.printStackTrace();throw new BizException(777, "退款失败");}}
通用版
小程序文档 - 支付宝文档中心
通用版
导入依赖
<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-sdk-java</artifactId><version>4.34.0.ALL</version></dependency>
配置
@Component
@ConfigurationProperties(prefix = "alipay2")
@Data
public class Alipay2Config extends com.alipay.api.AlipayConfig {// 网关地址private String serverUrl;// 应用Idprivate String appId;// 应用私钥private String appPrivateKey;//请求格式private String format;//字符集编码private String charset;//签名类型private String signType;// 支付宝公钥private String publiceKey;// 回调接口路径private String notifyUrl;}
支付
@GetMapping("/pay2")public void pay2(String subject, String outTradeNo, String totalAmount, String returnUrl, HttpServletResponse httpResponse) throws Exception {AlipayClient alipayClient = new DefaultAlipayClient(alipay2Config.getServerUrl(), alipay2Config.getAppId(),alipay2Config.getAppPrivateKey(), alipay2Config.getFormat(), alipay2Config.getCharset(), alipay2Config.getAlipayPublicKey(), alipay2Config.getSignType());AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();request.setNotifyUrl(alipay2Config.getNotifyUrl());request.setReturnUrl(returnUrl);JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no", outTradeNo);bizContent.put("total_amount", totalAmount);bizContent.put("subject", subject);bizContent.put("product_code", "FAST_INSTANT_TRADE_PAY");request.setBizContent(bizContent.toString());String form = "";try {// 调用SDK生成表单form = alipayClient.pageExecute(request).getBody();} catch (AlipayApiException e) {e.printStackTrace();}httpResponse.setContentType("text/html;charset=UTF-8");// 直接将完整的表单html输出到页面httpResponse.getWriter().write(form);httpResponse.getWriter().flush();httpResponse.getWriter().close();}
退款
/*** 退款接口** @return*/@GetMapping("/refund2")public String refund2 (String outTradeNo, Float refundAmount){AlipayClient alipayClient = new DefaultAlipayClient("https://openapi-sandbox.dl.alipaydev.com/gateway.do",alipayConfig.getAppId(),alipayConfig.getAppPrivateKey(),"JSON","utf-8",alipayConfig.getPubliceKey(),"RSA2");AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();// 获取获取对应订单信息JSONObject bizContent = new JSONObject();bizContent.put("out_trade_no", outTradeNo);bizContent.put("refund_amount", refundAmount);bizContent.put("out_request_no", "HZ01RF002"); //退款标识,用于查询状态是操作request.setBizContent(bizContent.toString());// 使用支付宝支付页面接口进行支付try {AlipayTradeRefundResponse response = alipayClient.execute(request);System.out.println(response);if (response.isSuccess()) {System.out.println("退款成功");return "退款成功";} else {System.out.println("退款失败");throw new BizException(777, "退款失败");}} catch (Exception e) {e.printStackTrace();System.out.println("退款失败");throw new BizException(777, "退款失败");}}
相关文章:

支付宝沙箱环境 支付
一 什么是沙箱: 沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境 支付宝正式和沙箱环境的区别 : AI: 从沙箱到正式环境: 当应用程序开发完成后,需要将应用程序从沙箱环境迁移到正式环境。 这通常涉及…...
获取unity中prefab的中文文本内容以及和prefab有关的问题
背景1:经常会在开发中遇到策划需要改某个界面,但是我们不知道那是什么界面,只看到一些关键字比如圣诞活动,那这样我就可以轻易找到这个预设了。另外还可以扩展就是收集项目中的所有中文文本然后归集到多语言表中,然后接…...
Web自动化中常用XPath定位方式
在进行Web自动化测试时,元素定位是一个至关重要的环节。XPath(XML Path Language)是一种用于在XML文档中定位节点的语言。在Web自动化中,XPath广泛应用于定位HTML元素。本文将详细介绍几种常用的XPath定位方式,包括绝对…...

Unity3D播放GIF图片使用Animation来制作动画
系列文章目录 unity工具 文章目录 系列文章目录👉前言👉一、下载GIF动图,用PS制作导出帧动画图片👉二、使用Animation制作动画👉三、脚本控制动画播放👉壁纸分享👉总结👉前言 unity播放gif图片,本身是不支持的,但是可以使用其他方法来实现, 1.有一种使用System…...
redo log 和 bin log 的两阶段提交
两阶段提交的过程 当事务提交后,有一个两阶段提交策略。 在开启两阶段提交时,会开启一个 XA 事务(宏观上的事务), Prepare 阶段:将 redo log 的状态设置为 prepare,然后将 事务XID 写入 redo…...
Go基础学习07-map注意事项;多协程对map的资源竞争;sync.Mutex避免竟态条件
文章目录 Go中map使用以及注意事项map使用时的并发安全问题 Go中map使用以及注意事项 Go语言中map使用简单示例: func main() {var mp map[string]int// mp : map[string]int{}val, ok : mp["one"]if ok {fmt.Println(val)} else {fmt.Println(val)}mp[…...

远程服务器安装anaconda并创建虚拟环境
1、承接上文新用户zrcs,在服务器的zrcs文件夹下直接下载anaconda(很慢): wget https://repo.anaconda.com/archive/Anaconda3-2024.06-1-Linux-x86_64.sh 或者选择本地下载,清华大学开源软件镜像站:https:/…...
什么是IIC通信协议?
IIC(Inter-Integrated Circuit)通信协议,又称为I2C(Inter-Integrated Circuit 2)协议,是一种广泛使用的串行通信协议。它由飞利浦半导体公司(现NXP Semiconductors)开发,…...

P3131 [USACO16JAN] Subsequences Summing to Sevens S Python题解
[USACO16JAN] Subsequences Summing to Sevens S 题目描述 Farmer John’s N N N cows are standing in a row, as they have a tendency to do from time to time. Each cow is labeled with a distinct integer ID number so FJ can tell them apart. FJ would like to ta…...

鸿蒙NEXT开发-ArkUI(基于最新api12稳定版)
注意:博主有个鸿蒙专栏,里面从上到下有关于鸿蒙next的教学文档,大家感兴趣可以学习下 如果大家觉得博主文章写的好的话,可以点下关注,博主会一直更新鸿蒙next相关知识 专栏地址: https://blog.csdn.net/qq_56760790/…...

Matplotlib 使用 LaTeX 渲染图表中的文本、标题和数学公式
Matplotlib 使用 LaTeX 渲染图表中的文本、标题和数学公式 Matplotlib 是一个功能强大的 Python 库,用于绘制各种高质量的图表和图形。在许多科研和技术文档中,数学公式是不可或缺的一部分,LaTeX 提供了精美的数学公式渲染能力。Matplotlib …...

Android 安卓内存安全漏洞数量大幅下降的原因
谷歌决定使用内存安全的编程语言 Rust 向 Android 代码库中写入新代码,尽管旧代码(用 C/C 编写)没有被重写,但内存安全漏洞却大幅减少。 Android 代码库中每年发现的内存安全漏洞数量(来源:谷歌)…...

c++primier第十二章类和动态内存
本章内容包括: 对类成员使用动态内存分配隐式和显式地复制构造函数隐式和显式地重载赋值操作符在构造函数中使用new所必须完成的工作使用静态类成员 将布局new操作符用于对象使用指向对象的指针实现队列抽象数据类型(ADT) 动态内存和类 复习范例和静态类成员 首…...

Ansible学习之ansible-pull命令
想要知道ansible-pull是用来做什么的,就需要了解Ansible的工作模,Ansible的工作模式有两种: push模式 push推送,这是Ansible的默认模式,在主控机上编排好playbook文件,push到远程主机上来执行。pull模式 p…...

Linux:磁盘管理
一、静态分区管理 静态的分区方法不可以动态的增加或减少分区的容量。 1、磁盘分区-fdisk 该命令是用于查看磁盘分区情况,和分区管理的命令 命令格式:fdisk [选项] 设备文件名常用命令: -h:查看分区信息 fdisk系统常用命令&…...

FP7209: 用于紫外线消毒灯的 升压LED恒流驱动芯片
现在社会对于居家消毒也越发重视起来。而居家消毒除了75%浓度酒精及各类消毒液外,利用紫外线灯给衣物表面、房间消毒也是一种很好的选择。FP7209 定位于低压线性恒流驱动,精度高、外围电路简单、使用方便且可靠性高,更可广泛应用于商业照明系…...
【华为HCIP实战课程二】OSPF基础介绍和OSPF RID NBMA配置详解
一、OSPF多区域 自治系统(Autonomous System) 一个自治系统是指使用同一种路由协议交换路由信息的一组路由器 1、Area0为骨干区域 2、ABR--关乎3类LSA后续详解 ABR用来连接骨干区域Area0和非骨干区域,它与骨干区域之间既可以是物理连接,也可以是逻辑上的连接。 3、AS…...
网络编程(13)——单例模式
十三、day13 今天学习如何单例模式实现逻辑层的设计。内容包括服务器如何能捕获信号使其安全退出、单例模标类 1. 什么是单例模式? 单例模式(Singleton),保证一个类仅有一个实例,并提供一个访问它的全局访问点&…...

基于定制开发与2+1链动模式的商城小程序搭建策略
摘要:本文探讨商城小程序的搭建策略,对比自主组建团队和第三方开发两种方式,强调以第三方开发模式为主的优势。阐述在第三方开发模式下,结合定制开发和21链动模式,如何搭建一款有助于企业商业模式创新与智能商业升级的…...

银河麒麟,apt 安装软件报错640Unknown Status
今天把银行麒麟的机器恢复出厂了,然后apt install 安装极其不稳定,故障现象如下图所示: 错误提示里面有: 640 Unknown Status [IP: 106.116.184.122 80] E: 无法下载 http://archive.kylinos.cn/kylin/KYLIN-ALL/pool/universe/f…...

wordpress后台更新后 前端没变化的解决方法
使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…...
条件运算符
C中的三目运算符(也称条件运算符,英文:ternary operator)是一种简洁的条件选择语句,语法如下: 条件表达式 ? 表达式1 : 表达式2• 如果“条件表达式”为true,则整个表达式的结果为“表达式1”…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建
华为云FlexusDeepSeek征文|DeepSeek-V3/R1 商用服务开通全流程与本地部署搭建 前言 如今大模型其性能出色,华为云 ModelArts Studio_MaaS大模型即服务平台华为云内置了大模型,能助力我们轻松驾驭 DeepSeek-V3/R1,本文中将分享如何…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...

OPENCV形态学基础之二腐蚀
一.腐蚀的原理 (图1) 数学表达式:dst(x,y) erode(src(x,y)) min(x,y)src(xx,yy) 腐蚀也是图像形态学的基本功能之一,腐蚀跟膨胀属于反向操作,膨胀是把图像图像变大,而腐蚀就是把图像变小。腐蚀后的图像变小变暗淡。 腐蚀…...

C# 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...
C#学习第29天:表达式树(Expression Trees)
目录 什么是表达式树? 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持: 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...