支付宝沙箱支付

news2024/9/23 23:24:09

支付宝沙箱支付

支付宝沙箱(Alipay Sandbox)是支付宝提供的一个模拟环境,用于开发者在不影响真实交易的情况下进行支付宝相关功能的测试和调试。在软件开发中,沙箱环境通常指的是一个隔离的测试环境,可以模拟真实环境的行为,但不会对真实数据产生影响。

支付宝沙箱为开发者提供了一套模拟的支付流程和接口,使开发者能够在沙箱环境中进行支付测试,验证其支付功能是否正常工作,而无需使用真实的资金进行交易。这有助于开发者在应用上线之前进行充分的测试,确保支付流程的稳定性和安全性。

使用支付宝沙箱,开发者可以模拟各种支付场景,包括扫码支付、APP支付、H5支付等。此外,支付宝沙箱还提供了一些调试工具和接口文档,帮助开发者更方便地进行测试和开发。

使用支付宝沙箱环境可以帮助开发者在开发和测试阶段及时发现和解决问题,确保支付功能的稳定和安全。一旦开发者在支付宝沙箱环境中完成了测试和调试,就可以将代码和配置切换到真实的支付宝环境中进行生产部署。

支付宝开放平台 (alipay.com)

准备工作

引入依赖

        <!--支付宝-->
        <dependency>
            <groupId>com.alipay.sdk</groupId>
            <artifactId>alipay-sdk-java</artifactId>
            <version>4.38.133.ALL</version>
        </dependency>
        <!--其他-->
       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.33</version>
        </dependency>

配置文件

alipay:
    appId: # 应用id
    appPrivateKey: # 应用私钥
    alipayPublicKey: # 支付宝公钥
    notifyUrl: # 异步通知地址 
    gateway: # 支付宝网关
server:
    port: 8088

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

代码编写

配置类

AliPayConfig 支付宝支付配置类 方便我们获取配置参数

@Data
@Component
@ConfigurationProperties(prefix = "alipay")
public class AliPayConfig {
    private String appId;
    private String appPrivateKey;
    private String alipayPublicKey;
    private String notifyUrl;
    private String gateway;
}

AlipayClientConfig 支付宝客户端配置类

@Configuration
public class AlipayClientConfig {
    @Autowired
    private AliPayConfig aliPayConfig;

    @Bean
    public AlipayClient getAlipayClient(){
        AlipayClient alipayClient = new DefaultAlipayClient(
                aliPayConfig.getGateway(),
                aliPayConfig.getAppId(),
                aliPayConfig.getAppPrivateKey(),
                AlipayConstants.FORMAT_JSON,
                AlipayConstants.CHARSET_UTF8,
                aliPayConfig.getAlipayPublicKey(),
                AlipayConstants.SIGN_TYPE_RSA2);
        return alipayClient;
    }
}

controller

AlipayController

@RestController
@RequestMapping("/alipay")
public class AlipayController {
    @Autowired
    private AlipayService alipayService;

    /**
     *  支付接口
     * @param order 订单
     * @return
     */
    @PostMapping("/pay")
    public R pay(@RequestBody Order order){
        // 使用时间当订单号
        order.setOrderId(String.valueOf(System.currentTimeMillis()));
        return alipayService.pay(order);
    }

    /**
     *  订单状态通知 异步通知
     * @param request
     * @return
     * @throws AlipayApiException
     */
    @GetMapping("/notify")
    public R payNotify(HttpServletRequest request) throws AlipayApiException {
        return alipayService.payNotify(request);
    }
}

Service

AlipayService

public interface AlipayService {
    /**
     *  支付接口
     * @param order
     * @return
     */
    R pay(Order order);

    /**
     *  异步通知
     * @param request
     * @return
     */
    R payNotify(HttpServletRequest request);
}

AlipayServiceImpl

@Service
public class AlipayServiceImpl implements AlipayService {
    @Value("${alipay.alipayPublicKey}")
    private String publicKey;
    @Value("${alipay.notifyUrl}")
    private String notifyUrl;

    @Autowired
    private AlipayClient alipayClient;
    @Override
    public R pay(Order order){
        AlipayTradePagePayRequest request = new AlipayTradePagePayRequest();
        // 异步通知的地址
        request.setNotifyUrl(notifyUrl);
        Map<String,String> map = new HashMap<>();
        map.put("out_trade_no",order.getOrderId());
        map.put("total_amount",order.getPrice());
        map.put("subject",order.getSubject());
        map.put("body",order.getBody());
        map.put("product_code","FAST_INSTANT_TRADE_PAY");

        // 设置业务参数
        request.setBizContent(JSONObject.toJSONString(map));

        // 发起支付请求
        // 发起支付请求
        AlipayTradePagePayResponse response = null;
        try {
            response = alipayClient.pageExecute(request);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }
        // 获取响应结果
        if (response.isSuccess()) {
            System.out.println("调用成功");
            System.out.println("支付宝支付链接:" + response.getBody());
            return R.ok(response.getBody());
        } else {
            System.out.println("调用失败");
            System.out.println("错误信息:" + response.getMsg());
            return R.fail("调用失败",40010);
        }
    }

    @Override
    public R payNotify(HttpServletRequest request) {
        Map<String, String[]> paramMap = request.getParameterMap();
        Map<String, String> params = new HashMap<>();
        for (Map.Entry<String, String[]> entry : paramMap.entrySet()) {
            String name = entry.getKey();
            String[] values = entry.getValue();
            StringBuilder valueStr = new StringBuilder();
            for (int i = 0; i < values.length; i++) {
                valueStr.append((i == values.length - 1) ? values[i] : values[i] + ",");
            }
            params.put(name, valueStr.toString());
        }

        // 调用SDK验证签名
        boolean verifyResult = false;
        try {
            verifyResult = AlipaySignature.rsaCheckV1(params, publicKey, AlipayConstants.CHARSET_UTF8, AlipayConstants.SIGN_TYPE_RSA2);
        } catch (AlipayApiException e) {
            throw new RuntimeException(e);
        }

        if (verifyResult) {
            // 验证成功,处理业务逻辑,更新订单状态等
            // 注意:请防止重复处理,可以通过记录支付状态或者订单号来判断是否已经处理过
            System.out.println("支付宝异步通知验证成功");
            // 返回给支付宝成功处理的响应
            return R.ok();
        } else {
            // 验证失败,不处理业务逻辑
            System.out.println("支付宝异步通知验证失败");
            // 返回给支付宝失败处理的响应
            return R.fail("支付失败",40010);
        }
    }
}

工具类

Order 订单类

@Data
public class Order {
    // 订单id
    private String orderId;
    // 价格
    private String price;
    // 商品名称
    private String subject;
    // 商品描述
    private String body;
    // 支付场景
    /**
     * FAST_INSTANT_TRADE_PAY(即时到账):适用于即时交易场景,买家付款后,卖家立即收到款项。
     * QUICK_MSECURITY_PAY(手机网页支付):适用于手机网页支付场景。
     * FACE_TO_FACE_PAYMENT(当面付):适用于线下面对面付款场景,比如扫码支付。
     * APP支付(APP支付场景):适用于在APP内的支付场景。
     * WAP支付(手机网站支付场景):适用于手机网站支付场景。
     * PRE_AUTH(预授权):适用于预先授权场景,买家授权预先冻结资金,商家在完成业务后调用支付宝解冻资金
     */
    private String code;
}

R 响应类

@Data
public class R {
    private String data;
    private String msg;
    private int code;

    public R() {
    }

    public R (String msg, int code) {
        this.msg = msg;
        this.code = code;
    }

    public R( String msg, int code,String data) {
        this.data = data;
        this.msg = msg;
        this.code = code;
    }

    public static R ok(){
        return new R("成功",200);
    }
    public static R ok(String data){
        return new R("成功",200,data);
    }
    public static R fail(String message, int code) {
        return new R( message,code);
    }
}

测试页面

<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title>商城</title>
    <script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<div id="box">
    <div>
        <h1>订单列表</h1>
        <ul>
            <li v-for="order in orders" :key="order.orderId">
                <h3>{{ order.subject }}</h3>
                <p>价格: ¥{{ order.price }}</p>
                <p>{{ order.body }}</p>
                <button v-on:click="pay(order)">购买</button>
                <hr>
            </li>
        </ul>
    </div>
    <div v-html="paymentFormHtml"></div>
</div>
<script type="text/javascript">
    var vm = new Vue({
        el: '#box',
        data: {
            orders: [
                {
                    "price": "12148.00",
                    "subject": "iPhone 15 Pro Max 512GB 原色钛金属",
                    "body": "iPhone 15 Pro Max 512GB 原色钛金属"
                },
                {
                    "price": "4999",
                    "subject": "xiaomi 14 钛金属",
                    "body": "xiaomi 14 钛金属 256gb"
                }
            ],


            paymentFormHtml: "" // 新增 paymentFormHtml 属性
        },
        methods: {
            pay: function (order) {

                axios.post('http://127.0.0.1:8088/alipay/pay', order)

                    .then(res => {
                        // 处理支付成功的逻辑
                        console.log('支付成功', res.data);
                        this.paymentFormHtml = res.data.data;
                        // 手动提交表单

                        // 在延时后提交表单
                        setTimeout(function () {
                            document.forms['punchout_form'].submit();
                        }, 1000); // 1000毫秒,即1秒

                    })
                    .catch(error => {
                        // 处理支付失败或其他错误的逻辑
                        console.error('支付失败', error);
                    });
            }
        }
    });
</script>


</body>

</html>

测试

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

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

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

相关文章

【论文阅读】MAG:一种用于航天器遥测数据中有效异常检测的新方法

文章目录 摘要1 引言2 问题描述3 拟议框架4 所提出方法的细节A.数据预处理B.变量相关分析C.MAG模型D.异常分数 5 实验A.数据集和性能指标B.实验设置与平台C.结果和比较 6 结论 摘要 异常检测是保证航天器稳定性的关键。在航天器运行过程中&#xff0c;传感器和控制器产生大量周…

Python 自动化(十八)admin后台管理

admin后台管理 什么是admin后台管理 django提供了比较完善的后台数据库的接口&#xff0c;可供开发过程中调用和测试使用 django会搜集所有已注册的模型类&#xff0c;为这些模型类提供数据管理界面&#xff0c;供开发使用 admin配置步骤 创建后台管理账号 该账号为管理后…

2023年中职“网络安全“—Web 渗透测试①

2023年中职"网络安全"—Web 渗透测试① Web 渗透测试任务环境说明&#xff1a;1.访问地址http://靶机IP/task1&#xff0c;分析页面内容&#xff0c;获取flag值&#xff0c;Flag格式为flag{xxx}&#xff1b;2.访问地址http://靶机IP/task2&#xff0c;访问登录页面。…

【每日一题】三个无重叠子数组的最大和

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;滑动窗口 写在最后 Tag 【滑动窗口】【数组】【2023-11-19】 题目来源 689. 三个无重叠子数组的最大和 题目解读 解题思路 方法一&#xff1a;滑动窗口 单个子数组的最大和 我们先来考虑一个长度为 k 的子数组的最…

【开源】基于Vue.js的创意工坊双创管理系统

项目编号&#xff1a; S 049 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S049&#xff0c;文末获取源码。} 项目编号&#xff1a;S049&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 管理员端2.2 Web 端2.3 移动端 三、…

leetcode算法之分治-快排

目录 1.颜色分类2.排序数组3.数组中的第k个最大元素4.最小的k个数 1.颜色分类 颜色分类 class Solution { public:void sortColors(vector<int>& nums) {int n nums.size();int left -1,rightn,i0;while(i<right){if(nums[i] 0) swap(nums[left],nums[i]);e…

力扣 字母异位词分组 哈表 集合

&#x1f468;‍&#x1f3eb; 力扣 字母异位词分组 ⭐ 思路 由于互为字母异位词的两个字符串包含的字母相同&#xff0c;因此对两个字符串分别进行排序之后得到的字符串一定是相同的&#xff0c;故可以将排序之后的字符串作为哈希表的键。 &#x1f351; AC code class Solut…

设计模式-行为型模式-策略模式

一、什么是策略模式 策略模式是一种行为设计模式&#xff0c;它允许在运行时选择算法或行为&#xff0c;并将其封装成独立的对象&#xff0c;使得这些算法或行为可以相互替换&#xff0c;而不影响使用它们的客户端。&#xff08;ChatGPT生成&#xff09; 主要组成部分&#xff…

一款实用的.NET Core加密解密工具类库

前言 在我们日常开发工作中&#xff0c;为了数据安全问题对数据加密、解密是必不可少的。加密方式有很多种如常见的AES&#xff0c;RSA&#xff0c;MD5&#xff0c;SAH1&#xff0c;SAH256&#xff0c;DES等&#xff0c;这时候假如我们有一个封装的对应加密解密工具类可以直接…

【STL】:反向迭代器

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关反向迭代器的模拟实现&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门到精通…

【kafka】使用docker启动kafka

1.环境准备 docker拉取zookeeper镜像 docker pull zookeeper:3.4.14 创建zookeeper容器&#xff0c;默认端口号为2181 docker run -d --name zookeeper -p 2181:2181 zookeeper:3.4.14 拉取kafka镜像 docker pull wurstmeister/kafka:2.12-2.3.1 创键kafka容器&#xff…

c语言-输入输出详解

文章目录 格式化输入输出占位符printfscanf 字符串输入输出puts&#xff08;&#xff09;gets&#xff08;&#xff09; 字符输入输出putchar&#xff08;&#xff09;getchar&#xff08;&#xff09; 区别 格式化输入输出 输入输出的库函数的头文件&#xff1a; #include<…

2023/11/19总结

项目进度&#xff1a; 地址管理&#xff1a; 显示菜品 购物车相关功能 然后最近在看 支付宝沙盒支付的相关功能&#xff0c;打算把支付给做了 。界面做的不是很好看 &#xff0c;但是后续会改成 手机端的。

WSL 2 更改默认安装的 Linux 发行版

目录 什么是 WSL 2&#xff1f;更改默认安装的 Linux 发行版更改发行版的 WSL 版本 什么是 WSL 2&#xff1f; WSL 2 是适用于 Linux 的 Windows 子系统体系结构的一个新版本&#xff0c;它支持适用于 Linux 的 Windows 子系统在 Windows 上运行 ELF64 Linux 二进制文件。 它的…

基于SSM的北海旅游网站设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;采用JSP技术开发 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#x…

ICCV2023 Tracking paper汇总(二)(多目标跟随、单目标跟随等)

十六、Integrating Boxes and Masks: A Multi-Object Framework for Unified Visual Tracking and Segmentation paper&#xff1a; https://openaccess.thecvf.com/content/ICCV2023/papers/Xu_Integrating_Boxes_and_Masks_A_Multi-Object_Framework_for_Unified_Visual_ICC…

Android 13 - Media框架(14)- OpenMax(二)

这一节我们将来解析 media.codec 这个 HIDL service 究竟提供了什么服务&#xff0c;服务是如何启动的。 1、main 函数 我们先来看 frameworks/av/services/mediacodec/main_codecservice.cpp&#xff1a; int main(int argc __unused, char** argv) {strcpy(argv[0], "…

搭建网关服务器实现DHCP自动分配、HTTP服务和免密登录

目录 一. 实验要求 二. 实验准备 三. 实验过程 1. 网关服务器新建网卡并改为仅主机模式 2. 修改新建网卡IP配置文件并重启服务 3. 搭建网关服务器的dhcp服务 4. 修改server2网卡配置文件重启服务并效验 5. 设置主机1的网络连接为仅主机模式 6. 给server2和网关服务器之…

【Django-DRF用法】多年积累md笔记,第(4)篇:Django-DRF反序列化详解

本文从分析现在流行的前后端分离Web应用模式说起&#xff0c;然后介绍如何设计REST API&#xff0c;通过使用Django来实现一个REST API为例&#xff0c;明确后端开发REST API要做的最核心工作&#xff0c;然后介绍Django REST framework能帮助我们简化开发REST API的工作。 全…

性能测试学习——项目环境搭建和Jmete学习二

项目环境搭建、Jmeter学习二 环境的部署虚拟机的安装虚拟机中添加项目操作步骤 使用环境的注意事项Jmeter的安装和简单使用Jemter的使用的进阶Jemter元件 Jmeter属性执行顺序和作用域作用域以自定义用户变量和用户参数(前置处理器)为例如何解决用户变量和线程组同级时&#xff…