Spring Boot 完善订单【五】集成接入支付宝沙箱支付

1.1.什么是沙箱支付

支付宝沙箱支付(Alipay Sandbox Payment)是支付宝提供的一个模拟支付环境,用于开发和测试支付宝支付功能的开发者工具。在真实的支付宝环境中进行支付开发和测试可能涉及真实资金和真实用户账户,而沙箱环境则提供了一个安全、隔离的环境,使开发者能够模拟支付过程,测试支付功能,而不会使用真实资金。

使用支付宝沙箱支付环境,开发者可以模拟各种支付场景,包括交易创建、支付请求、支付回调等,以验证支付功能的正确性和稳定性。沙箱环境中的所有交易和数据都是虚拟的,不会产生真实的交易或资金流动。

支付宝沙箱支付提供了开发者工具和接口,使开发者能够在模拟环境下进行支付流程的调试和测试。开发者可以在沙箱环境中创建测试账户、配置模拟的交易金额和状态,使用沙箱环境中的接口进行支付操作,并模拟支付回调接口接收支付结果。

通过使用支付宝沙箱支付,开发者可以更安全、更有效地进行支付功能的开发和测试,避免了对真实环境的影响和风险。一旦支付功能在沙箱环境中验证通过,开发者可以将其部署到真实的支付宝生产环境中,与真实用户进行交互和支付。

步骤:

1.2接入支付宝开放平台

登陆支付宝:支付宝开放平台

登录成功之后,点击控制台跳转到控制台主页面,将浏览器进度条滚动到最下面,选择沙箱,最后点击沙箱选项即可,如下:

下载密钥生成工具:

小程序文档 - 支付宝文档中心

前端代码:

$(".pay").click(function () {
    //地址,手机号,收货人,支付方式,快递方式
    let el = $(".addres").find(".on")
    let person = el.find(".tit .fl").text()
    let address = el.find(".addCon p:first-child").text()
    let telephone = el.find(".addCon p:last-child").text()
    let pay = $(".way .on").attr('value')
    let mail = $(".dis .on").text()
    let ids = $(this).attr('data-ids')
    let order={
        person,telephone,address,pay,mail,ids
    }
    $.post('/order/add',order,resp=>{
        if(resp.code===200){
    //         进入支付
        let f = confirm("是否去结算?")
        if (f){
            console.log(resp.data)
            location.href="/order/pay?oid="+resp.data
        }else {
            location.href="/"
        }
        }
    },"json")
})

后端代码:

package com.lya.lyaspshop.controller;

import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.yitter.idgen.YitIdHelper;
import com.lya.lyaspshop.config.AlipayConfig;
import com.lya.lyaspshop.pojo.Goods;
import com.lya.lyaspshop.pojo.Order;
import com.lya.lyaspshop.pojo.OrderItem;
import com.lya.lyaspshop.pojo.User;
import com.lya.lyaspshop.resp.JsonResponseBody;
import com.lya.lyaspshop.service.IOrderItemService;
import com.lya.lyaspshop.service.IOrderService;
import com.lya.lyaspshop.service.impl.GoodsServiceImpl;
import com.lya.lyaspshop.service.impl.RedisServiceImpl;
import com.lya.lyaspshop.vo.CartItemVo;
import com.lya.lyaspshop.vo.OrderVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;


@RestController
@RequestMapping("/order")
public class OrderController {

    @Autowired
    private RedisServiceImpl redisService;
    @Autowired
    private GoodsServiceImpl goodsService;
    @Autowired
    private IOrderItemService iOrderItemService;
    @Autowired
    private IOrderService iOrderService;

    @RequestMapping("/add")
    public JsonResponseBody<?> toOrder(User user, OrderVo orderVo){
        String ids = orderVo.getIds();
        List<CartItemVo> cartItems = redisService.loadCart(user, ids);
        //所有的购物车中商品的id集合
        List<Long> gds = cartItems.stream().map(CartItemVo::getGid).collect(Collectors.toList());
        //根据集合查询所有对应的商品
        List<Goods> goods = goodsService.listByIds(gds);
        //遍历集合 赋值给对应的对象
        for (Goods g : goods) {
            //找到对应id相同的元素
            CartItemVo vo = cartItems.stream()
                    .filter(v -> Objects.equals(v.getGid(), g.getGid()))
                    .findFirst()
                    .get();
            //将商品g的属性赋值给vo
            BeanUtils.copyProperties(g,vo);
        }
        long oid = YitIdHelper.nextId();
        //增加订单项
        BigDecimal total=new BigDecimal(0);
        List<OrderItem> orderItems=new ArrayList<>();
        for (CartItemVo item : cartItems) {
            //生成订单项
            OrderItem orderItem = new OrderItem();
            //赋值属性
            BeanUtils.copyProperties(item,orderItem);
            orderItem.setQuantity(item.getNum());
            orderItem.setOoid(YitIdHelper.nextId());
            orderItem.setOid(oid);
            //放到一个集合中 批量增加 只会有一次数据库新增
            orderItems.add(orderItem);
            //计算总价 + 当前的小计
            total = total.add(item.cartprice());
        }
        iOrderItemService.saveBatch(orderItems,5);
        //增加订单
        Order order = new Order();
        BeanUtils.copyProperties(orderVo,order);
        order.setOid(oid);
        order.setTotal(total);
        order.setUserId(user.getId());
        order.setStatus(0);
        order.setCreateDate(new Date());
        //订单插入数据库
        iOrderService.save(order);
        //删除缓存元素
//        redisService.removeCart(user,orderVo.getIds());
        return JsonResponseBody.success(oid);
    }
    @RequestMapping("/pay")
    public String pay(User user, String oid){
//        得到结算的订单
        Order order = iOrderService.getById(oid);
//        调用支付页面
//        传来的是表单
        String body = new AlipayConfig().goAlipay(order);
        return body;
    }
//    这里传递来的数据:
    @RequestMapping("/payDone")
    public String payDone(Map<String,String> stringMap){
//        更具成功支付了id来修改状态:
        String oid = stringMap.get("out_trade_no");
        iOrderService.update(new UpdateWrapper<Order>()
                .eq("oid",oid)
                .set("status",1)
                .set("pay_date",new Date()));
//        html语句可以解析,json数据只能响应


        return "<script>\n" +
                "    alert(\"支付成功\")\n" +
                "    location.href=\"/\"\n" +
                "< /script>";
    }

}

这里我们要添加一条代码:(异步通知验签)

//      安全验证:
        Boolean b = Factory.Payment.Common().verifyNotify(stringMap);
        if (!b){
                throw   new BusinessException(JsonResponseStatus.UN_KNOWN);
        }

支付宝接口:(根据自己数据的来)

package com.lya.lyaspshop.config;

import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.lya.lyaspshop.pojo.Order;
import org.springframework.stereotype.Component;

@Component
public class AlipayConfig {

    private Config aliconfig() {
        Config config = new Config();
        //沙箱支付宝地址
        config.gatewayHost = "openapi-sandbox.dl.alipaydev.com";
        //协议https
        config.protocol = "https";
        //应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号
        config.appId = "9021000132623583";
        //支付宝公钥
        config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmexyLYPEgC4GHxHtCYEhThPEIOjOoMpr8w+bmOtAPpmLg3wrYt4xMFbTP4Wg8wBSWiLHgXtBl32BekY5PD0pOPRZ5VW8rL84uDt+wnCdS9PjXscFmDdzGvp4c1o4vgjQovylrfEf1AlLINYUsXaTp1Nk5IZGRxERLOoTKVI/COY/qyIvhSueS+gIadpgSXNn1R0K73zorJaKVhJS4WKtHfr1246sslQRptinaFiU5PAvQXzt5iaBLdqc3C0UGz1jTHgemaJOIW/SlhsR3CkKif0MX25IoCrwgpzYbv0JDoGG74pzAIOf2LuNaZbQRwQldYokTLVXIlWis1H0UqiYzQIDAQAB";
        //签名方式
        config.signType = "RSA2";
        //商户私钥(应用私钥),您的PKCS8格式RSA2私钥
        config.merchantPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC+y08ssgZZsO0y1Xr4dTTD3/Vh9rfpCJ79B5YLJlWhWDZ/+yfGBdyoMtMnPjvuqZNvyloNrxJFAlOc17A6JLEypnJw7G1W7BYIRur0cQx7bVjqqN/lCO9V1dsyOOKhFd+10lbkIgr1DY0FwY4z9bZuniPCRERvKu6M/485Iq68C8vQnBzlXPYSP9STmzLoNtkSDhC/4t5EQus5FEcpNkmXuDM9fGw1J2d4e3SKMZIj4h2+1qByhktEsc5HhKF4RCZK+MR0fhBStF8rRVd2hvDhjcgg3TVoYjvn0fLN2wMX03/lLsIA7+G4ORVxO9RS5PmhCLQab5lqa9YPFpqyoCB7AgMBAAECggEAAUE3CRU2o3pdZPswbtfee/dKFtXXicnLueBF5VbgM0pwOVE+hrfdJqIG73giTsSAurh69SIUna2RPTPR7d/15l5f3ExBv9OXpYBJ5UelDF7AufJYXpo7cLYSVfc3zlVlfj2e4qsypT/skIAgXkkcZQfXNlzaklyW6wh3Oan3ujbau1IQVE/jQBvTdUbAWapFcGJ5RH07MvuBJhz4rG2eAMANxT6JIp8+3rU1Pi//enhb5qTWa5xg+HFtqeNs5T+E0JPzR8ezWYkbCDiXL5iYE1jvoTeyaBfz7iKxRuN1bpgClg/DNB5j3JXo3Ke4SRtLf80WnCQFwV5paeWXUbdsuQKBgQDs7DiGoa1YD3yhXdkXJQONDp2EZb2679d3rC5m5qJsAZi+W+qWe4V7vqqmfJrFjAUe+eNWSaoaUXO9Z5Ps3dcNpFXBnOW0ODpBGcYnT8bu5qqWjRbYFMOAAznh895v/2uNtljWvYTHUrnYEP2ZNkiEzCg9IYgH1L5GWJ8hoPC+jQKBgQDOKDkHfSwELOOIFidOAJqV3qpeo4AzPW5X3GsNKg1fcnN9nRTgUqZhW+woGetXTbbCxuM24uQpVZqpVhZA+TcCBc+kj7yDwkyjhFtO7UQQRSBiyQm0w6qZY+1aKIwf1Z578Nsbcf07FEJjpfxV8YAuF6Vq9PcS1lI4N1rVi5m9JwKBgE6zYUuHpVddPZ8014pSp01SD40NZusUBNUiAv/3mPibxytkyRZXzc1/VpybQ6ZfjsvtYlElgzXe3L2MDJ1gS7GiZ0I7ZippiyBY+XPRklmFkiEUmQQKUa7SY4XlRnyZshaO/g/HQLYditJ1QmiEma5TSwKTguZnCxW/Fo1LMu15AoGBALEc/WHhuB8eMZyI69unySdY1SXZchqTfGkfhRkaN8L4oSAaBAV0/FxIjOsm2Xl32rwcArj01PBuCyHQQ+4uLYQfWfUXR+4qz4zr+UYlsYQI33n/HcefEsIVh6UdkMUI0c/JbXR2yggnr6HMyK1NfcIbrpHlQx974cdKR0+PT9WhAoGBANC3h8Y4FBaKOLcxwHCVDSUrCszCyE+NGvDJI2I5Q7Pjxb5hfHkYR0/cVG5aUJPElWWizaf+7wNCL9XtVCfoUYWZ3DffNs526DL3btN9zby2Tcq7q3NhvRc3ZezSd/XZkGpr7LhWK0wppi5TuvNlhl1VyoGtbMiNUPOrSNWepror";
        return config;
    }

    public String goAlipay(Order order) {
        try {
            // 1. 设置参数(全局只需设置一次)
            Factory.setOptions(aliconfig());
            // 2. 发起API调用(subject商品标题、outTradeNo订单编号、totalAmount总金额、returnUrl异步通知地址)
            AlipayTradePagePayResponse response = Factory.Payment.Page()
                    .pay("商城项目收款",
                            order.getOid().toString(),
                            order.getTotal().toString(),
                            //支付成功之后的异步通知(跳出到自己系统的哪个位置)
                            "http://localhost:8080/order/payDone");
//            支付宝支付页面
            return response.body;
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

}

注意:

这里的支付宝公钥,应用私钥要填好:失败了多生成几次:

接入成功:

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

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

相关文章

网络对讲终端 网络音频终端 网络广播终端SV-7011V使用说明

高速路sip广播对讲求助 隧道sip对讲调度SIP-7011 网络广播终端SV-7011 壁挂式对讲终端网络监听终端SIP广播终端 sip语音对讲终端SIP-7011 SV-7011网络对讲终端网络对讲、网络厂播、监听 SV-7101网络解码终端提供一路线路输出接功放或有源音箱。 SV-7102网络解码广播终端两…

OpenGL如何基于glfw库 进行 点线面 已解决

GLFW是现在较流行、使用广泛的OpenGL的界面库&#xff0c;而glut库已经比较老了。GLEW是和管理OpenGL函数指针有关的库&#xff0c;因为OpenGL只是一个标准/规范&#xff0c;具体的实现是由驱动开发商针对特定显卡实现的。由于OpenGL驱动版本众多&#xff0c;它大多数函数的位置…

一加 Buds 3正式发布:普及旗舰音质 一加用户首选

1月4日&#xff0c;一加新品发布会正式推出旗下新款耳机一加 Buds 3。延续一加经典美学&#xff0c;秉承音质完美主义追求&#xff0c;一加 Buds 3全面普及一加旗舰耳机体验&#xff0c;其搭载旗舰同款“超清晰同轴双单元”&#xff0c;配备49dB 4000Hz超宽频主动降噪&#xff…

企语iFair 协同管理系统 任意文件读取漏洞复现(CVE-2023-47473)

0x01 产品简介 企语iFair协同管理系统是一款专业的协同办公软件,该管理系统兼容性强,适合多种企业类型。该软件永久免费,绿色安全,无需收取费用即可使用所有功能。企语iFair协同管理系统同时兼容了Linux、Windows两种操作系统 0x02 漏洞概述 企语iFair协同管理系统getup…

LangChain与昇腾

LangChain这个词今年已经听烂了&#xff0c;今天基于昇腾的角度总结一下&#xff1a; Why LangChain &#xff1f; 场景&#xff1a;构建一个LLM应用 在构建一个新项目时&#xff0c;可能会遇到许多API接口、数据格式和工具。要去研究每一个工具、接口很麻烦。 假设要构建一…

Flume基础知识(三):Flume 实战监控端口数据官方案例

1. 监控端口数据官方案例 1&#xff09;案例需求&#xff1a; 使用 Flume 监听一个端口&#xff0c;收集该端口数据&#xff0c;并打印到控制台。 2&#xff09;需求分析&#xff1a; 3&#xff09;实现步骤&#xff1a; &#xff08;1&#xff09;安装 netcat 工具 sudo yum …

java数据结构与算法刷题-----LeetCode70. 爬楼梯

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 很多人觉得动态规划很难&#xff0c;但它就是固定套路而已。其实动态规划只…

探索3D软件的奥秘:Maxon Cinema 4D与Autodesk Maya的比较

在3D软件的广阔天地中&#xff0c;Maxon Cinema 4D和Autodesk Maya无疑是两颗璀璨的明星。它们各自拥有独特的功能和特点&#xff0c;使它们在影视、广告、游戏等领域中广受欢迎。在这篇文章中&#xff0c;我们将深入探讨这两款软件的差异&#xff0c;以帮助您更好地了解它们。…

Python编程基础:顺序结构、循环结构、程序跳转语句、pass空语句

Python是一种简单而强大的编程语言&#xff0c;它提供了多种结构和语句&#xff0c;使得程序编写变得更加灵活和高效。在本文中&#xff0c;将介绍Python中的顺序结构、循环结构、程序跳转语句以及pass空语句&#xff0c;并解释如何正确使用它们。 目录 程序的描述方式自然语言…

真双端口ram相关知识点

WEA&#xff1a; RAM 端口 A 写使能信号&#xff0c;高电平表示向 RAM 中写入数据&#xff0c;低电平表示从 RAM 中读出数据。 ENA&#xff1a;端口 A 的使能信号&#xff0c;高电平表示使能端口 A &#xff0c;低电平表示端口 A 被禁止&#xff0c;禁止后端口 A 上的读写操作…

论文解读Language-based Action Concept Spaces Improve Video Self-Supervised Learning

Language-based Action Concept Spaces Improve Video Self-Supervised Learning 基于语言的动作概念空间改善视频自我监督学习 备注: 最近研究需要&#xff0c;先将翻译概括内容放这里 论文地址&#xff1a;论文 https://arxiv.org/pdf/2307.10922v3.pdf 摘要 最近的对比…

【AI】使用LoFTR进行图像匹配测试Demo

LoFTR图像匹配的源码解析我们在上篇文章中已经写了&#xff0c;对于怎么试用一下&#xff0c;我这边再啰嗦一下。 0.环境搭建 详细的搭建教程请点击链接查看&#xff0c;这里只对需要特殊注意的地方做阐述 1.创建的Python环境采用python3.8的环境&#xff0c;因为文章发布较早…

2023 年最先进认证方式上线,Authing 推出 Passkey 无密码认证

密码并非是当前数字世界才有的安全手段。古今中外诸如故事中的《阿里巴巴与四十大盗》的“芝麻开门”口诀&#xff0c;或是江湖中“天王盖地虎&#xff0c;宝塔镇河妖”等传统的口令形式&#xff0c;都是以密码作为基本形态进行身份认证。然而&#xff0c;随着密码在越来越多敏…

第十四章 14.2案例:使用KVM命令集管理虚拟机

查看命令帮助 [rootLinux01 ~]# virsh -h—————————————————————————————————————————— 查看KVM的配置文件存放目录〈test01 , xml是虚拟机系统实例的配置文件) [rootLinux01 ~]# ls /etc/libvirt/qemu —————————————…

这个方法可以让你把图片无损放大

随着数字技术的不断发展&#xff0c;照片无损放大已经成为了摄影领域中的一项重要技术。照片无损放大能够让摄影师在不损失细节和画质的情况下&#xff0c;将照片放大到更大的尺寸&#xff0c;从而让观众能够更加清晰地欣赏到照片中的每一个细节。 今天推荐的这款软件主要是通…

redis服务迁移数据工具--RDM

一、背景&#xff1a; 在日常的运维工作经常遇见各种数据迁移工作&#xff0c;例如mysql数据库迁移、redis数据库迁移、minio数据迁移等等工作。这里介绍一下redis数据库的迁移过程。 二、迁移思路&#xff1a; redis服务/集群的数据迁移思路是需要新建一个配置、密码一样的re…

T527 camera: AHD摄像头转MIPI

一、AHD 常见的摄像头接口一般有MIPI、USB、DVP等等&#xff0c;但是MIPI摄像头受限于高速信号的传输距离问题&#xff0c;导致走线不能太长&#xff0c;这样在安防监控领域、车载等领域&#xff0c;使用就很受限&#xff0c;因此会引入AHD&#xff0c;目的就是提高了传…

Python 自学(三) 之序列的应用

目录 1. 序列的含义 2. 序列的索引 P80 3. 序列相加 P81 4. 序列乘法 P82 5. in 关键字 P83 6. 计算序列的最大值max()&#xff0c;最小值min()和长度len() P83 7. 列表的初始化 list() P85 8. 列表元素的添加&#xff0c;…

python的课后练习总结4(while循环)

for循环用于针对序列中的每个元素的一个代码块。 while循环是不断的运行&#xff0c;直到指定的条件不满足为止。 while 条件&#xff1a; 条件成立重复执行的代码1 条件成立重复执行的代码2 …….. i 1while i < 5:print(i)i i 11、使用wh…

多线程基础入门【Linux之旅】——下篇【死锁,条件变量,生产消费者模型,信号量】

目录 一&#xff0c;死锁 1. 死锁的必要条件 2&#xff0c;避免死锁 二&#xff0c;条件变量 同步概念与竞态条件 条件变量——初始化 静态初始化 动态初始化 pthread_cond_destroy (销毁) pthread_cond_wait (等待条件满足) pthread_cond_signal (唤醒线程) ph…