当前位置: 首页 > news >正文

【SpringBoot开发】之商城项目案例(沙箱支付)

 🎉🎉欢迎来到我的CSDN主页!🎉🎉

🏅我是君易--鑨,一个在CSDN分享笔记的博主。📚📚

🌟推荐给大家我的博客专栏《SpringBoot开发之商城项目系列》。🎯🎯

🎁如果感觉还不错的话请给我关注加三连吧!🎁🎁


前言

        在上一期的商城项目分享中我们实现了订单项及订单的生成,首先在购物车中选择我们所需要结算的商品,点击结算。然后我们就会获取相关的参数传递都后端进行一系列处理,接着我们调用方法进行新增,其次就是将选中的商品从缓存中去除掉指定的商品数据即可。本期博客基于上期的博客文章,本次实现的是购买支付,请仔细阅读,干货满满。

一、什么是沙箱支付

1. 概述

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

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

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

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

2. 沙箱支付的应用场景

        沙箱支付是一个用于模拟真实支付环境的测试工具,其主要作用是在开发和测试阶段模拟支付流程,以便开发者能够验证其支付系统的正确性、稳定性和安全性。以下是沙箱支付的主要作用和一些应用场景:

沙箱支付的应用场景
应用场景说明
测试支付集成开发者可以使用沙箱支付来测试其应用与支付网关、第三方支付服务商等支付系统的集成。这有助于确保支付流程的正确性和顺畅性。
模拟不同支付状态沙箱支付通常允许开发者模拟不同的支付状态,如支付成功、支付失败、支付取消等,以确保系统能够正确地处理各种支付结果。
调试和错误排查在沙箱环境中,开发者可以更容易地调试和排查支付相关的问题,而不必担心真实支付交易对用户产生影响。
安全性测试沙箱支付环境还可以用于测试支付系统的安全性,包括对支付数据的加密、身份验证和防止欺诈的功能。
开发人员培训沙箱支付是培训新的开发人员、商户或支付系统操作员的理想环境,因为它提供了一个模拟支付流程的平台,而无需使用真实的支付账户和资金。
API 接口测试对于开发使用支付API的应用,沙箱支付提供了一个测试接口的环境,开发者可以验证其API调用的正确性。
新功能测试当支付系统添加新功能时,沙箱环境可以用于测试这些新功能,确保其与现有系统的兼容性。
合规性测试对于需要遵循一定支付行业标准和法规的应用,沙箱支付可以用于测试支付系统的合规性,确保符合相关的法规和标准。

二、配置沙箱支付

1.接入支付宝开放平台

        首先我们进入到支付宝开放平台官网进行登陆,网址:支付宝开放平台 ,

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

         在进入之前我们还需要进行一个操作,补全信息

         将浏览器进度条滚动到最下面,选择沙箱,最后点击沙箱选项即可

 2. 下载

        我们使用沙箱支付需要下载安装支付宝开放平台开发助手。

网址::小程序文档 - 支付宝文档中心

注意事项 :请不要安装在含有空格的目录路径下,否则会导致公私钥乱码的问题

        我们下载的版本如下所示 

         我们下载好安装包点击进行安装,根据指示进行安装,安装之后我们的桌面会生成一个图标,打开之后的页面如下

3. 配置秘钥

        打开支付宝开放平台开发助手,选择密钥方式,选择`RSA2`方式,最后点击生成密钥即可生成得到私钥和公钥。

         我们会生成对应的应用私钥和应用公钥。

4.  生成支付宝公钥

         根据支付宝开放平台开发助手生成的应用公钥,生成支付宝公钥。找到支付宝开放平台的沙箱应用一栏,选择“开发信息”接口加签方式中的自定义密钥方式,点击设置并查看按钮:

 

        将我们之前生成的应用公钥的内容复制在所选的框内 

 5. 配置沙箱账号(买家)

        我们使用沙箱支付前还需配置沙箱账号进行相应的付款支付。

网址:登录 - 支付宝

 6. 下载沙箱支付宝(手机下载)

        下载沙箱支付宝(只支持安卓),利用实现功能

网址:登录 - 支付宝

        下载安装之后,进行相应的注册或者登陆 

 

三、SpringBoot项目中集成使用

1. 导入pom依赖

        导入我们沙箱支付所需要的pom依赖,版本不同可能会影响到我们的使用

<dependency><groupId>com.alipay.sdk</groupId><artifactId>alipay-easysdk</artifactId><version>2.0.1</version>
</dependency>

2. 配置沙箱支付配置类

        我们可以参考我们的开发文档中根据自己的需要及信息进行修改

        下面是我自己修改后的配置类,配置类中需要修改以下信息

 

 AlipayConfig.java

package com.yx.yxshop.config;import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import com.yx.yxshop.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";//协议httpsconfig.protocol = "https";//应用ID,您的APPID,收款账号既是您的APPID对应支付宝账号config.appId = "9021000133666836";//支付宝公钥config.alipayPublicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr5pP6Hf4txMzWmDIjkUUK5wju2gaZwV3MdNa/zvBOImeHTNcSdXTrtNtweZ8/gXxoJJV9nJR1h9SDyBZqDx54wd2Mu3XeHuQRZuqW1Sr4uCpcbsFGgULzv4Y8AgmJZpIJUkFFUIFY3m3NdK7bHHjBqVw9T+AkiHSAvzKgAOmoLX/WHEFIEKTEGrkILvs6HtDsVSn7MWJ6WM5ndk9tZBJZDRhb2p2H0EgeVPrZ8OrqJxzWs/Tl08WYrd0yblPuLg3c7IUM6G7gXx0Y2cPc0XyjpXVhXcryASH5Pl5u7nChI9ra6xvwNshdZpXlZ9iygFsTrHW7tAgHpKwjlIxe4pM2QIDAQAB";//签名方式config.signType = "RSA2";//商户私钥(应用私钥),您的PKCS8格式RSA2私钥config.merchantPrivateKey = "MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCKk86IjtT1YR6Q00PY4OcPyd4p2L6PpYkphY2vBXoH8Umy2IJbpaERH5y+NeD06SLrCkAbSuEZ8neGR27HKX6VRlMhyFSbiSufLn4FjGrfuiLhFQ2EjtJOXN2f/aw4hpigjBEbPppt+wXTEel3ggwY8t3xqYmyuTnKLbd1R7wKTJz3iBrt02eGmcBgnkhL10oImvivbcoacCYZjbv4TvbPHYQPpyFNRGHGHFH8p4EZzmoRyZHyHCCfiUnYKvP1VESRSWWihDS1be05OIVRwFl6RORLhouDrqukRnvFnu9euE8mXsZSc1sL2fF/9uRtVY7q+s00gFYFZTseDSltcVbRAgMBAAECggEAfkEN8XKYaXtzeqVQcj7tpX/Yzi1v6LX7kn3gSS5nMOdPqwcBNXhgl5ZCmzXBX8EslBHBuFvvXFGBPjDEp+WRM3Vf9i5rj01ZFe0o2etFz9HpR0KED1qEFusa7FIU32cZlWQnjbfqwPrsIpJ2L/CnDu/u7+bz0oZZNW+TbuHNW19tPAkpS+kkSZRYOdMjqXJ8faDUUVm0ywFepOYjRgsUZhBhELC7W9Snd3ZKJt0QdtgN/OD9t3xqsrOcIoCe5V+EgYz69ntFly2xZssf9wUDr5jJz4L+ZsOolfKfiP+S9aEfq55kJxYkTseD4XmoGk6uUQMYwShi/RwBIbeFt0PJ5QKBgQD9n+ahZPXuWP4EAPiVDpG6A4HfJBTkfQ3EPIPd8/43kXuRto9VkB4XrKA90qF2+Ubg+iZTbfOZ5r9dQvODbgWA7CP8pMUV1hagIx+MrgYSkt4rZAFAZzPmDZEoPz8BrpSeGUysmii2OM6Oi/E5TOEsY9QR12AD5YdSHtt6DxaEcwKBgQCL4BCMbvZzhRh2k8tJRsoMt0d9hvK+R1AVu++dSLQEWqAYDCAVU5EGRpTMMbXH+wMNvyUCnk17vtQXJfdxdpbOlQXwHfukX5p94Tw05jI8sndbGzcmiBuB2lD+SrONIRebtqXpYqKrAvQNJN3r1VJ0nR9tU5ydGODYlNP0eqQqqwKBgHFmqKFrWgcbZWB26q8DF6d7X/tcz7amL5yZjkCUkwtXkk/Bt+8DBGGDfxaFckqXBNkdIDvXgr9CjDfv8p/GdtGBREn3hmPQGMe7TKUDPpXZc1slWOXp/yuSz1+Wf96Jp8vU9hKKzz9CwSC9c7syI9BMRos/qJ+1Zj8SqwG1c1T/AoGAXzX7zbvSYjvctQpRO+XFrvYq4ZU0MrVUHBc7OXK9pqERjIzkYd/qPb1Zl8zWkfOY1oif5rJex7bTo5YiYsd4S9JAonumSPMStFDWrKNs2sgYWpmh5saLAs7aht3ObmhyK3oeYUjUtVdjTHcl4FvqrpotRDu/xWej1Yko5ad9i9UCgYB1XGJcnclrlMlVjJvwdK/JXoBgLu+N4OLIaJQ3E5G/CSYRSFQzy1m312ogd1CeCJFL9gZzkCZE5HL5/ARpAP/5CbvcEyxN6KN+1nV9bqv9d5IqYH/CDnzVeInx3zReWSMAmpUIUX6jj+4YIfJ2Gkm4++Dei7lHJv98Gwf1xyDx5w==";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);}}}

3. 修改订单生成代码

 OrderController.java
package com.yx.yxshop.controller;import com.alipay.easysdk.factory.Factory;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.github.yitter.idgen.YitIdHelper;
import com.yx.yxshop.config.AlipayConfig;
import com.yx.yxshop.exp.BusinessException;
import com.yx.yxshop.pojo.Goods;
import com.yx.yxshop.pojo.Order;
import com.yx.yxshop.pojo.OrderItem;
import com.yx.yxshop.pojo.User;
import com.yx.yxshop.resp.JsonResponseBody;
import com.yx.yxshop.resp.JsonResponseStatus;
import com.yx.yxshop.service.IGoodsService;
import com.yx.yxshop.service.IOrderItemService;
import com.yx.yxshop.service.IOrderService;
import com.yx.yxshop.service.IRedisService;
import com.yx.yxshop.vo.CartVo;
import com.yx.yxshop.vo.OrderVo;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;/*** <p>* 订单信息表 前端控制器* </p>** @author yangxin* @since 2023-12-27*/
@RestController
@RequestMapping("/order")
public class OrderController {//    引入对应接口@Autowiredprivate IRedisService redisService;@Autowiredprivate IGoodsService goodsService;@Autowiredprivate IOrderItemService orderItemService;@Autowiredprivate IOrderService orderService;/*** 跳转订单的请求方法* @return*/@RequestMapping("/add")public JsonResponseBody<?> toOrder(User user, OrderVo orderVo){
//        获取购物车商品id字符串String ids = orderVo.getIds();
//        从缓存中获取购物车商品信息   此时只有id和数量List<CartVo> cartitems = redisService.loadCart(user, ids);//        从数据库中获取商品信息//        获取到所选中商品的Id集合List<Long> gds = cartitems.stream().map(CartVo::getGid).collect(Collectors.toList());
//      根据集合查询对应的商品信息List<Goods> goods = goodsService.listByIds(gds);
//      遍历结合赋值给对应的选项for (Goods g : goods) {
//            根据商品Id查询对应的购物车选项CartVo cartVo = cartitems.stream().filter(v -> Objects.equals(v.getGid(), g.getGid())).findFirst().get();
//            商品g的属性赋值给voBeanUtils.copyProperties(g,cartVo);}
//          使用雪花id生成订单idlong oid = YitIdHelper.nextId();//订单id
//        定义一个变量计算总价BigDecimal total = new BigDecimal("0");
//        增加订单项
//        实例化一个集合List<OrderItem> orderItems = new ArrayList<>();//用户后续插入数据
//        遍历商品信息集合for (CartVo item : cartitems) {
//            生成订单项
//            实例化一个订单项OrderItem orderItem = new OrderItem();
//              赋值属性BeanUtils.copyProperties(item,orderItem);
//            订单项的订单商品数量orderItem.setQuantity(item.getNum());orderItem.setOoid(YitIdHelper.nextId());//订单项idorderItem.setOid(oid);//订单id
//            订单对象存放到订单集合中
//              减少请求生成orderItems.add(orderItem);
//            计算总价total = total.add(item.sumprice());}
//        向数据库中批量插入数据orderItemService.saveBatch(orderItems,5);//分批插入防止数据量过多
//        增加订单
//        实例化订单对象Order order = new Order();
//        设置订单属性BeanUtils.copyProperties(orderVo,order);
//        设置订单idorder.setOid(oid);
//      设置总价order.setTotal(total);
//        设置用户idorder.setUserId(user.getId());
//        设置订单状态  默认0order.setStatus(0);
//      设置创建时间order.setCreateDate(new Date());
//      将订单插入数据库orderService.save(order);
//        删除缓存中购物车对应的商品redisService.removeCart(user,orderVo.getIds());return JsonResponseBody.success(oid);}/*** 跳转支付的请求方法* @return*/@RequestMapping("/pay")public String toOrder(User user, String oid){
//        根据订单ID查询订单Order order = orderService.getById(oid);
//        调用支付宝的支付功能String body = new AlipayConfig().goAlipay(order);//返回的是表单return body;}/*** 支付成功之后的请求方法,修改其订单状态* @return*/@RequestMapping("/payDone")public String toOrder(@RequestParam Map<String,String> ms) throws Exception {
//        验签  检验是否支付Boolean b = Factory.Payment.Common().verifyNotify(ms);if (!b){//没有支付throw new BusinessException(JsonResponseStatus.UN_KNOWN);//抛出未知异常}
//       获取订单idString oid = ms.get("out_trade_no");
//        修改订单状态orderService.update(new UpdateWrapper<Order>().set("status",1).set("pay_date",new Date()).eq("oid",oid));return "<script>\n" +"\talert(\"支付成功\");\n" +"\tlocation.href=\"/\";//跳转首页\n" +"</script>";}}

        前端代码修改主要是js的代码

 

四、演示


 

 🎉🎉本期的博客分享到此结束🎉🎉

📚📚各位老铁慢慢消化📚📚

🎯🎯下期博客博主会带来新货🎯🎯

🎁三连加关注,阅读不迷路 !🎁

相关文章:

  • IDEA 每次新建工程都要重新配置 Maven的解决方案
  • Java中如何使用SQLite数据库
  • 【Python小游戏】消消乐丨喜羊羊与灰太狼(完整代码)
  • 2397. 被列覆盖的最多行数
  • bullet3 三种碰撞检测及实现
  • 不要盲目自学网络安全!学习顺序特别重要!
  • WPF调节图片的对比度
  • 抖音小店怎么做好前期运营?这三个步骤做好就行了!
  • 【开题报告】基于SpringBoot的洗衣店管理系统的设计与实现
  • ios环境搭建_xcode安装及运行源码
  • 【干货】Windows中定时删除system32目录下的.dmp文件教程
  • springboot连接oracle报错ORA-12505解决方案
  • JOSEF约瑟 定时限过流继电器 JSL-21/5 柜内安装,板前接线 实物图
  • RTSP/Onvif安防平台EasyNVR接入EasyNVS显示服务不存在的原因及解决办法
  • 海康威视摄像头+服务器+录像机配置校园围墙安全侦测区域入侵侦测+越界侦测.docx
  • 【个人向】《HTTP图解》阅后小结
  • 【跃迁之路】【699天】程序员高效学习方法论探索系列(实验阶段456-2019.1.19)...
  • Babel配置的不完全指南
  • CentOS从零开始部署Nodejs项目
  • Django 博客开发教程 8 - 博客文章详情页
  • docker python 配置
  • Java 最常见的 200+ 面试题:面试必备
  • JavaScript 事件——“事件类型”中“HTML5事件”的注意要点
  • Js实现点击查看全文(类似今日头条、知乎日报效果)
  • js中forEach回调同异步问题
  • mongodb--安装和初步使用教程
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • STAR法则
  • vuex 笔记整理
  • 阿里云Kubernetes容器服务上体验Knative
  • 从PHP迁移至Golang - 基础篇
  • 面试遇到的一些题
  • 前端代码风格自动化系列(二)之Commitlint
  • 让你成为前端,后端或全栈开发程序员的进阶指南,一门学到老的技术
  • 如何利用MongoDB打造TOP榜小程序
  • 我从编程教室毕业
  • 追踪解析 FutureTask 源码
  • 2017年360最后一道编程题
  • ​【已解决】npm install​卡主不动的情况
  • (C)一些题4
  • (C语言)fgets与fputs函数详解
  • (function(){})()的分步解析
  • (分享)一个图片添加水印的小demo的页面,可自定义样式
  • (附源码)spring boot公选课在线选课系统 毕业设计 142011
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (南京观海微电子)——COF介绍
  • (转)LINQ之路
  • (转)一些感悟
  • .bashrc在哪里,alias妙用
  • .CSS-hover 的解释
  • .NET Framework 4.6.2改进了WPF和安全性
  • .NET I/O 学习笔记:对文件和目录进行解压缩操作
  • .NET 将混合了多个不同平台(Windows Mac Linux)的文件 目录的路径格式化成同一个平台下的路径
  • .NET使用存储过程实现对数据库的增删改查