支付宝沙箱环境 支付

一 什么是沙箱:

沙箱环境是支付宝开放平台为开发者提供的安全低门槛的测试环境

支付宝正式和沙箱环境的区别 :

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")
@Data
	public class AlipayConfig {
    // 应用Id
    private 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-8
         httpResponse.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;
    // 应用Id
    private 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, "退款失败");
            }
        }

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

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

相关文章

如何查看线程

1、首先找到我们的电脑安装jdk的位置&#xff0c;这里给大家展示一下博主本人的电脑jdk路径下的jconsole位置。 2、 ok&#xff0c;那么找到这个jconsole程序我们直接双击打开就可以查看我们电脑的本地进程&#xff1a; jconsole 这里能够罗列出你系统上的 java 进程&#xff0…

古代经典名方目录数据库-支持经典名方检索!

"古代经典名方目录"是指一系列历史上流传下来的&#xff0c;被认为具有一定疗效的中药方剂的汇总。这些方剂多来源于历代医学典籍&#xff0c;经过长期临床实践的检验&#xff0c;部分已被收录于官方的目录之中&#xff0c;以便于现代医疗实践中的参考和应用。 目前…

手机在网状态查询接口如何用C#进行调用?

一、什么是手机在网状态查询接口&#xff1f; 手机在网状态查询接口是利用实时数据来对手机号码在运营商网络中的状态进行查询的工具&#xff0c;包括正常使用状态、停机状态、不在网状态、预销户状态等。 二、手机在网状态查询适用哪些场景&#xff1f; 例如&#xff1a;商…

设计模式-结构型-11-代理模式

文章目录 1. 基本介绍2. 静态代理2.1 基本介绍UML 类图 2.2 应用实例定义接口目标对象代理对象调用代理 2.3 静态代理优缺点 3. 动态代理3.1 基本介绍3.2 JDK 中生成代理对象的 API参数说明UML类图 3.3 应用实例定义接口目标对象代理工厂调用代理 4. Cglib 代理4.1 基本介绍4.2…

求一个数的因子数(c语言)

1.计算并输出给定整数n的所有因子&#xff08;不包括1与n自身&#xff09;之和。规定n的值不大于1000。&#xff08;因子是能整除n的数 即n%i0&#xff09; // 例如&#xff0c;在主函数中从键盘给n输入的值为856&#xff0c;则输出为: sum763。 2.第一步我们先输入n的数&…

Koa (下一代web框架) 【Node.js进阶】

koa (中文网) 是基于 Node.js 平台的下一代 web 开发框架&#xff0c;致力于成为应用和 API 开发领域中的一个更小、更富有表现力、更健壮的基石&#xff1b; 利用 async 函数 丢弃回调函数&#xff0c;并增强错误处理&#xff0c;koa 没有任何预置的中间件&#xff0c;可快速…

mysql安装教程(新手版)

本教程不需要手动设置配置文件&#xff0c;比较简单&#xff0c;适合新手&#xff0c;过程需联网。 1.找到mysql官网 mysql官网 一.mysql的安装 1.界面如下图&#xff0c;点击箭头所指。 2.选择mysql版本&#xff0c;系统&#xff0c;安装。 3.下载完成后双击打开&#xff0…

golang操作mysql利器-gorm

1、傻瓜示例 GORM通过将数据库表中的数据映射到面向对象的模型中&#xff0c;简化了数据库操作&#xff0c;使得开发者可以很方便的使用代码来操作数据库&#xff0c;而无需编写SQL语句。 目前有个mysql表&#xff1a;miniprogram_orders&#xff0c;其存储了所有用户对应的订…

Android SystemUI组件(07)锁屏KeyguardViewMediator分析

该系列文章总纲链接&#xff1a;专题分纲目录 Android SystemUI组件 本章关键点总结 & 说明&#xff1a; 说明&#xff1a;本章节持续迭代之前章节的思维导图&#xff0c;主要关注左侧上方锁屏分析部分即可。 为了更好理解本文的内容&#xff0c;优先说明下SystemUI中与Ke…

CoreDNS实现跨集群service解析实践

CoreDNS实现跨集群service解析实践 背景介绍使用条件实现方案 CoreDNS是一款使用Go语言实现的专为云原生应用而生的DNS服务器。本文介绍CoreDNS在特定实际场景下的一种进阶使用实践&#xff0c;也许能为其他也在使用CoreDNS做服务发现的同学提供一些启发和思考。 背景介绍 在…

luceda ipkiss教程 76:设计光栅耦合器

案例分享&#xff1a;设计光栅耦合器 全部代码如下&#xff1a; from si_fab import all as pdk from ipkiss3 import all as i3 import numpy as npclass grating_coupler(i3.PCell):"""SOI grating coupler."""_name_prefix "grating_c…

mysql 05 InnoDB数据页结构

01.数据页结构的快速浏览 02.记录在页中的存储 在页的7个组成部分中&#xff0c;我们自己存储的记录会按照我们指定的 行格式 存储到 User Records 部分。但是在一开始生成页的时候&#xff0c;其实并没有 User Records 这个部分&#xff0c;每当我们插入一条记录&#xff0c…

单词记忆的化境:用思想的流水去淹没坚硬的石块

其实&#xff0c;鹅卵石通常都是很硬的。但是河底的石子&#xff0c;几乎大多都成了鹅卵石&#xff0c;它们被流水淹没&#xff0c;日复一日、夜以继日的冲刷着&#xff0c;没有了棱角。 在单词的记忆过程中&#xff0c;我们有太多的人&#xff0c;都有着不堪回首的往事&#x…

面试系列-携程暑期实习一面

Java 基础 1、Java 中有哪些常见的数据结构&#xff1f; 图片来源于&#xff1a;JavaGuide Java集合框架图 Java 中常见的数据结构包含了 List、Set、Map、Queue&#xff0c;在回答的时候&#xff0c;只要把经常使用的数据结构给说出来即可&#xff0c;不需要全部记住 如下&…

爬虫逆向学习(九):记录一个集cookie、请求参数、请求体、响应文本加密的站点反爬

此分享只用于学习用途&#xff0c;不作商业用途&#xff0c;若有冒犯&#xff0c;请联系处理 反爬前置信息 站点&#xff1a;aHR0cHM6Ly96d2Z3LmNxLmdvdi5jbi9pY2l0eS9pY2l0eS9lbmdpbmVlcmluZy9uYXZpZ2F0aW9u 接口&#xff1a;/icity/api-v2/cq.app.icity.engineering.Engine…

江科大51单片机

文章目录 led灯led点亮led闪烁流水灯 独立按键按键点灯按键消抖按键实现二进制流水灯按键实现流水灯 数码管静态数码管显示动态数码管显示 矩阵键盘定时器/中断串口通信led点阵屏DS1302实时时钟蜂鸣器AT24C02DS18B20LCD1602直流电机驱动AD/DA红外遥控 led灯 创建项目&#xff…

打印沙漏(最蠢的办法)

直接给代码&#xff0c;很好理解的 #include<bits/stdc.h> using namespace std; int s(int b){if(b<1)return 0;if(b2)return 1;for(int i3;i<sqrt(b);i){if(b%i0)return 0;}return 1; } int main(){int n;cin>>n;char c;cin>>c;vector<int>s;…

网络原理之IP协议(网络层)

目录 前言 什么是IP协议&#xff1f; IP协议的协议头格式 16位总长度&#xff08;字节数&#xff09; 16位标识、3位标志位和13位片偏移 8位生存时间 IP地址管理 1.动态分配IP 2.NAT机制&#xff08;网络地址转换&#xff09; NAT机制是如何工作的 NAT机制的优缺点…

解决启动docker desktop报The network name cannot be found的问题

现象 deploying WSL2 distributions ensuring main distro is deployed: checking if main distro is up to date: checking main distro bootstrap version: getting main distro bootstrap version: open \wsl$\docker-desktop\etc\wsl_bootstrap_version: The network name…

Windows驱动调试方法

单步调试驱动 驱动的调试不能直接在本机上进行&#xff0c;而是要放在虚拟机&#xff08;或其它设备&#xff09;中。这是因为在内核模式下&#xff0c;一个断点的触发将会停下整个系统而不只是单个进程。 在前面的文章里&#xff0c;使用了DbgPrint函数来进行日志的输出&…