电商中的订单支付(内网穿透)
支付页面

接口文档


@Operation(summary="获取订单信息")
@GetMapping("auth/{orderId}")
public Reuslt<OrderInfo> getOrderInfo(@Parameter(name="orderId",description="订单id",required=true) @PathVaariable Long orderId){OrderInfo orderInfo = orderInfoService.getOrderInfo(orderId);return Reuslt.build(orderInfo,ResultCode.SUCCESS);
}
@Override
public OrderInfo getOrderInfo(Long orderId){return orderInfoMapper.getById(orderId);
}
//mapper
OrderInfo getById(Long orderId);
<select id="getById"resultType="com.xxx.OrderInfo" >select *from order_infowhere id=#{orderId}</select>
不经过购物车,直接购买
@Operation(summary="立即购买")
@GetMapping("auth/buy/{skuId}")
public Result buy(@PathVariable Long skuId){TradeVo tradeVo = orderInfoService.buy(skuId);return Result.build(tredeVo,ResultCodeEnum.SUCCESS);
}
@Override
public TradeVo buy(Long skuId){List<OrderItem> orderItemList = new ArrayList<>();ProductSku productSku = productFeignClient.getBySkuId(skuId);OrderIntem orderItem = new OrderItem();orderItem.setSkuId(skuId);orderItem.setSkuName(productSku.getSkuName());orderItem.setSkuNum(1);orderItem.setSkuPrice(productSku.getSalePrice());orderItem.setThumbImg(productSku.getThumbImg());orderItemList.add(orderItem);TradeVo tradeVo = new TradeVo();trade.setOrderItemList(orderItemList);trade.setTotalAmount(productSku.getSalePrice());return tradeVo;
}
查询订单

@Operation(summary="获取订单分页列表")
@GetMapping("auth/{page}/{limit}")
public Result<PageInfo<OrderInfo>> list(@Parameter(name="page",description="当前页码",required=true)@PathVariable Integer page,@Parameter(name="limit",description="每页记录数",required=true)@PathVariable Integer limit,@Parameter(name="orderStatus",description="订单状态",required=false)@RequestParam(required=false,defaultValue="") Integer orderStatus){PageInfo<OrderInfo> pageInfo = orderInfoService.findUserPage(page,limit,orderStatus);return Result.build(pageInfo,ResultCodeEnum.SUCCESS);
}
@Override
public PageInfo<OrderInfo> findOrderPage(Integer page,Integer limit,Integer orderStatus){PageHelper.startPage(page,limit);//查询订单信息Long userId = AuthContextUtil.getUserInfo().getId();List<OrderItem> orderInfoList = orderInfoMapper.findUserPage(userId,orderStatus);//查询订单里所有的订单项orderInfoList.forEach(orderInfo -> {//订单id查询订单里面的订单项List<OrderItem> orderItemList = orderItemMapper.findByOrderId(orderInfo.getId());orderInfo.setOrderItemList(orderItemList);});return new PageInfo<>(orderInfoList);
}


===================================================================================
支付宝支付


通过营业执照进行开通
获取的参数


①、创建模块service-pay
配置文件、启动类……
spring:profiles:active: devserver:port:
spring:application:name:cloud:nacos:discovery:server-addr: localhost:8848datasource:type: com.zaxxer.hikari.HikariDataSourcedriver-class-name: com.mysql.cj.jdbc.Driverurl:username:password:data:redis:host: localhostport: 6379
mybatis:config-localtion: classpath:mybatis-config.xmlmapper-location: classpath:mapper/*/*.xml
②、保存支付记录
public interface PaymetInfoService{PaymentInfo savePaymentInfo(String orderNo);
}
@Service
public class PaymentInfoService implements PaymentInfoService{@Autowiredprivate PaymentInfoMapper paymentInfoMapper; @Overridepublic PaymentInfo savePaymentInfo(String orderNo){PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(orderNo);if(paymentInfo==null){//如果支付记录不存在,则远程调用订单信息OrderInfo orderInfo = orderFeignClient.getOrderInfoByOrderNo(orderNo).getData();paymentInfo = new PaymentInfo();paymentInfo.setUserId(orderInfo.getUserId());paymentInfo.setPayType(orderInfo.getPayType());String content = "";for(OrderItem item:orderInfo.getOrderItemList()){content += item.getSkuName() + "";}paymentInfo.setContent(content);paymentInfo.setAmount(orderInfo.getTotalAmount());paymentInfo.setOrderNo(orderNo);paymentInfoMapper.save(paymentInfo);}return paymentInfo;}
}
@Mapper
public interface PaymentInfoMapper{PaymentInfo getByOrderNo(String orderNo);void save(PaymentInfo paymentInfo);
}
<sql id="columns">id,user_id,order_no,pay_type,out_trade_no,amount,content,payment_status,callback_time,callback_content
</sql><select id="getByOrderNo" resultMap="paymentInfoMap">select <include refid="colums"></include>from payment_infowhere order_no = #{orderNo}
</select><insert id="save" useGeneratedKeys="true" keyProperty="id">insert into payment_info(id,user_id,order_no,pay_type,out_tread_no,amount,coutent,payment_status,)
</insert>


③、支付接口
Ⅰ、service-pay模块中添加alipay-sdk依赖
Ⅱ、application-alipay.yml文件,添加配置

Ⅲ、application-dev.yml配置文件需要引入application-alipay.yml
spring:config:import: application-alipay.yml
Ⅳ、读取配置文件
@Data
@Configuration(prefix="spzx.alipay")
public class AlipayProperties{//属性名必需和配置文件中的保持一致private String alipayUrl;private String appPrivateKey;public String alipayPublicKey;private String appId;public String returnPaymetUrl;public String notifyPaymentUrl;public final static String format="json";public final static String charset="utf-8";public final static String sign_type="RAS2";
}
Ⅴ、启动类添加注解@EnableConfigurationProperties(value={AlipayProperties.class})
④、配置发送请求的核心对象AlipayClient
@Configuration
public class AlipayConfiguration{@Autowiredprivate AlipayProperties alipayProperties;@Beanpublic AlipayClient alipayClient(){AlipayClient alipayClient = new DefaultAlipayClient(alipayProperties.getAlipayUrl(),alipayProperties.getAppPrivateKey(),alipayProperties.format,alipayProperties.charset,alipayProperties.getAlipayPublicKey(),alipayProperties.sign_type);return alipayClient;}
}
⑤、返回支付宝支付页面
@Controller
@RequestMapping()
public class AlipayController{@Autowiredprivate AlipayService alipayService;@Operation(summary="支付宝下单")@GetMapping("submitAlipay/{orderNo}")public Result<String> submitAliPay(@Parameter(name="orderNo",description="订单号",required=true),@PathVariable(value="orderNo") String orderNo){String form = aliapyService.submitAlipay(orderNo);//返回表单页面return Result.build(form,ResultCodeEnum.SUCCESS);}
}
@Override
public String submitAlipay(String orderNo){//保存支付记录PaymentInfo payementInfo = paymentInfoService.savePaymentInfo(orderNo);//调用支付宝服务接口封装参数AlipayTradeWapPayRequest alipayRequest = new AlipayTradeWapPayRequest();//同步回调alipayRequest.setReturnUrl(alipayProperties.getReturnPaymentUrl());//异步回调alipayRequest.setNotifyUrl(alipayProperties.getNotifyPaymentUrl());//准备请求参数HashMap<String,Object> map = new HashMap<>();map.put("out_trade_no",paymentInfo.getOrderNo());map.put("product_code","QUICK_WAP_WAY");map.put("total_amount",paymentInfo.getAmount());//map.put("total_amount",new BigDecimal("0.01")); 为了便于测试map.put("subject",paymentInfo.getContent());alipayRequest.setBizContent(JSON.toJSONString(map));try{//发送请求AlipayTradeWapPayResponse response = alipayClient.pageExecute(alipayRequest);if(response.isSuccess()){log.info("调用成功");String form = response.getBody();//返回支付页面return form;}else{log.info("调用失败");throw new GuiguException(ResultCodeEnum.DATA_ERROR);}}catch(AlipayApiException e){throw new RuntimeException(e);}}

⑥、完成支付
- 内网穿透,方便用来开发测试

- 支付成功之后到达的页面:修改自定义的页面
- 本地的接口路径:修改为内网穿透绑定到后端网关接口赠送的域名地址


@Operation(summary="支付宝异步回调")
@ReqeustMapping("callback/notify")//该路径和配置文件中的notify_payment_url
@ResponseBody
public String alipayNotify(@RequestParam Map<String,String> paramMap,HttpServletRequest request){log.info("AlipayController...alipayNotify方法执行了");boolean signVerified = false;//调用SDK验证签名(验证是否是支付宝传递过来)try{signVerified = AlipaySignature.rsaCheckVl(paramMap,alipayProperties.getAlipayPublicKey(),AlipayProperties.charset,AlipayProperties.sign_type);}catch(AlipayApiException e){e.printStackTrace();}//交易状态String trade_status = paramMap.get("trade_status");if(signVerified){//进行二次校验if("TRADE_SUCCESS".equals(trade_status)||"TRADE_FINISHED".equals(trade_status)){//正常的支付成功,更新交易记录状态paymentInfoService.updatePaymentStatus(paraMap,2);return "success";}}else{//验签失败,记录异常日志return "failture";}
}
//支付状态的更新
@Override
public void updatePaymentStatus(Map<String,String> map){//根据订单编号查询支付记录信息PaymentInfo paymentInfo = paymentInfoMapper.getByOrderNo(map.get("out_trade_no"));//如果支付记录已经完成,不需要更新if(paymentInfo.getPaymentStatus()==1){return;}//没有完成才更新paymentInfo.setPaymentStatus(1);paymentInfo.setOutTradeNo(map.get("trade_no"));paymentInfo.setCallbackTime(new Date());paymentInfo.set.CallbackContent(JSON.toJSONString(map));paymentInfoMapper.updatePaymentInfo(paymentInfo);//远程调用,更新订单模块(根据订单编号修改)orderFeignClient.updateOorderStatus(paymentInfo.getOrderNo());//更新sku商品销售
}



配置内网穿透
- 本质上就是因为无法直接调用本地服务,所以通过内网穿透便于第三方服务通过域名来调用本地服务
- ngrok工具:https://ngrok.cc/login/register 注册用户
- 完成实名认证
- 开通隧道管理
- 绑定本地服务开发者的service-gateway网关模块,获取赠送的域名
- 复制隧道id,下载客户端工具windows_amd64zip







相关文章:
电商中的订单支付(内网穿透)
支付页面 接口文档 Operation(summary"获取订单信息") GetMapping("auth/{orderId}") public Reuslt<OrderInfo> getOrderInfo(Parameter(name"orderId",description"订单id",requiredtrue) PathVaariable Long orderId){OrderI…...
ESP32开发之ubuntu环境搭建
1. 在Ubuntu官网下载Ubuntu server 20.04版本https://releases.ubuntu.com/20.04.6/ 2. 在vmware下安装Ubuntu 3. 改Ubuntu静态IP $ sudo vi /etc/netplan/00-installer-config.yaml# This is the network config written by ‘subiquity’ network: renderer: networkd eth…...
2025年,HarmonyOS认证学习及考试
HarmonyOS应用开发者认证考试 基础认证 通过系统化的课程学习,熟练掌握 DevEco Studio,ArkTS,ArkUI,预览器,模拟器,SDK 等 HarmonyOS 应用开发的关键概念,具备基础的应用开发能力。 高级认证…...
空间信息可视化——WebGIS前端实例(一)
技术栈:原生HTML 源代码:CUGLin/WebGIS: This is a project of Spatial information visualization 4 全国贫困县可视化系统 4.1 系统设计思想 党的十九大报告明确指出,要“确保到2020年我国现行标准下农村贫困人口实现脱贫,贫困县全部摘帽,解决区域…...
10.第二阶段x64游戏实战-添加计时器
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:9.第二阶段x64游戏实战-创建项目代码获取人物属性 效果图: 当前游戏…...
搭载DeepSeek|暴雨AI教育一体机加速AI教育普及
近日,在全国智算大会上,暴雨公司展示了新一代 AI 教育一体机,通过全栈国产化技术与 DeepSeek 模型的深度适配,打造低成本、高性能的人工智能教育解决方案,助力 AI 教育普及与教育数字化转型。 暴雨AI教育一体机&#…...
【论文阅读】MOE奠基论文《Adaptive Mixtures of Local Experts》
《Adaptive Mixtures of Local Experts》 前言一、让协同学习竞争1.1 方案1.2 方案演变的由来 二、让竞争学习协同2.1 竞争学习2.2 竞争学习协同 三、案例验证3.1 任务背景3.2 实验结果3.3 后续工作 (Future Work) 前言 论文提出了一个基于多个分离网络的有监督学习方案,该方案…...
Python(14)Python内置函数完全指南:从基础使用到高阶技巧
目录 背景介绍一、内置函数全景分类1. 数据类型转换(15个)2. 数学运算(12个)3. 迭代处理(9个)4. 对象操作(11个)5. 输入输出(4个) 二、高阶函数应用场景1. en…...
VM虚拟机安装及Ubuntu安装配置
VM虚拟机安装及Ubuntu安装配置 1、VM虚拟机安装2、创建虚拟机3、Ubuntu系统安装4、编译环境配置4.1 、Ubuntu和 Windows文件互传 文件互传4.1.1、 开启Ubunt下的FTP服务 4.2、 Ubuntu下NFS和SSH服务开启4.2.1、 NFS服务开启4.2.2、 SSH服务开启 4.3、 交叉编译器安装4.3.1 安装…...
基于大模型的轻症急性胰腺炎全流程预测与诊疗方案研究报告
目录 一、引言 1.1 研究背景与意义 1.2 研究目的与创新点 二、轻症急性胰腺炎概述 2.1 定义与诊断标准 2.2 发病机制与病因 2.3 流行病学现状 三、大模型技术原理及应用于医疗领域的可行性 3.1 大模型的基本原理 3.2 在医疗领域的应用进展 3.3 应用于轻症急性胰腺炎…...
【C++ 进阶】泛型算法:概述
目录 一、泛型算法基础概念 1.1 什么是泛型算法? 1.2 核心设计原则 1.3 算法分类体系 1.4 与 STL 容器的关系 二、迭代器:泛型算法的 “钥匙” 2.1 迭代器类型 2.2 迭代器适配器 三、常用泛型算法分类与实战 3.1 非修改型算法(只读…...
系统与网络安全------Windows系统安全(10)
资料整理于网络资料、书本资料、AI,仅供个人学习参考。 域与活动目录 域相关概念 域和域控制器 域(Domain) 集中管理网络中多台计算机的一种逻辑模式 有别于工作组的对等式管理 是组织与存储资源的核心管理单元 域控制器(D…...
Linux vagrant 导入ubuntu到virtualbox
前言 vagrant 导入ubuntu虚拟机前提要求 安装 virtualbox 和vagrant<vagrant-disksize> (Linux 方式 Windows 方式)创建一键部署ubuntu虚拟机 /opt/vagrant 安装目录/opt/VirtualBox 安装目录/opt/ubuntu22/Vagrantfile (可配置网络IP,内存,cpu,磁盘及分区,启动项,…...
eSTK.me Cloud Enhance Server 笔记
eSTK.me Cloud Enhance Server 笔记 一、 概述 eSTK.me Cloud Enhance Server 是一个用 Go 语言编写的开源服务器,旨在处理 eSTK.me 远程 eUICC(嵌入式通用集成电路卡)的请求,例如配置文件下载和通知处理。该服务器主要针对 EST…...
C++ 用红黑树封装map/set
前言 一、源码结构分析 二、模拟实现map/set 2.1 套上KeyOfT 2.2 普通迭代器实现 2.3 const迭代器实现 2.4 解决key不能修改的问题 2.5 map的[]实现 2.6 map/set以及红黑树源码 2.6.1 RBTree.h 2.6.2 set.h 2.6.3 map.h 总结 前言 之前的文章讲解了红黑树的具体实…...
【资料分享】瑞芯微RK3506(3核ARM+Cortex-A7 + ARM Cortex-M0)工业核心板选型资料
核心板简介 创龙科技SOM-TL3506是一款基于瑞芯微RK3506J/RK3506B处理器设计的3核ARM Cortex-A7 + ARM Cortex-M0全国产工业核心板,主频高达1.5GHz。核心板CPU、ROM、RAM、电源、晶振等所有元器件均采用国产工业级方案,国产化率100%。 核心板通过邮票孔连接方式引出2x DSMC、…...
3.7 字符串基础
字符串 (str):和列表用法基本一致 1.字符串的创建 -str转换(字符串,可用于将其他字符类型转换为字符串) -单引号 双引号 三引号 2.索引 3.字符串的切片 4.字符串的遍历 5.字符串的格式化 6.字符串的运算符 7.字符串的函数 #…...
量子计算未来的潜力和挑战
据麦肯锡预测,到 2035 年或 2040 年,量子计算市场规模可能增长至约 800 亿美元。目前,许多量子比特技术正竞相成为首台通用、无差错量子计算机的基础,但仍面临诸多挑战。 我们将探讨量子计算的未来前景、潜力,以及它对…...
机器学习项目二:帕金森病检测
目录 下载数据 一、导入相关包 二、数据加载 三、特征工程 四、构建模型 五、评估与可视化 六、程序流程 七、完整代码 一、导入相关包 # 导入库部分 import numpy as np # 数值计算基础库 import pandas as pd # 数据处理库 from sklearn.preprocessing import MinMaxS…...
LDAP渗透测试
LDAP渗透测试 1.LDAP协议概述2.LDAP写公钥3.暴力破解LDAP4.LDAP信息收集ldapdomaindumpwindapsearch工具ldapsearch 1.LDAP协议概述 LDAP(Lightweight Directory Access Protocol,轻量目录访问协议)是一种访问和管理目录服务的应用层协议&am…...
五笔输入法学习的抉择:86版 or 98版?(一场关于效率与传承的思辨)
新开直接98,纯粹高开;老版过渡艰辛自知😋。 笔记模板由python脚本于2025-04-14 19:22:22创建,本篇笔记适合喜好汉字衷情母语的coder翻阅。 【学习的细节是欢悦的历程】 博客的核心价值:在于输出思考与经验,…...
为您的 Web 应用选择最佳文档阅读器
为显示选择合适的文档查看器是开发 Web 应用过程中至关重要的一步。文档查看器应能在提供功能性的同时,确保用户体验的流畅性。 开发人员必须评估多种因素,以确保效率、性能和兼容性。本文将帮助您了解影响用户文档浏览体验成功与否的关键指标。 渲染质…...
微服务之protobuf:下载、语法和使用一站式教程
基本介绍 Protobuf全称 Protocol Buffer,是 Google 公司于2008年开源的一种语言无关、平台无关、可扩展的用于序列化结构化数据——类似于XML,但比XML更小、更快、更简单,它可用于(数据)通信协议、数据存储等。你只需…...
国产海光 DCU 资源监控脚本 + Promethues+grafana 深度解析
在当今数字化时代,对于服务器资源的高效监控与管理愈发重要。特别是在使用国产海光 DCU 的场景下,如何精准掌握其资源使用情况,成为了众多技术人员关注的焦点。本文将详细介绍一款国产海光 DCU 资源监控脚本,以及它与 Prometheus 和 Grafana 的结合使用,助力大家实现对 DC…...
Ollama调用多GPU实现负载均衡
文章目录 📊 背景说明🛠️ 修改 systemd 服务配置1. 配置文件路径2. 编辑服务文件2. 重新加载配置并重启服务3. 验证配置是否成功 📈 应用效果示例1. 调用单个70b模型2. 调用多个模型(70b和32b模型) 总结📌…...
WebRTC实时通话EasyRTC嵌入式音视频通信SDK,构建智慧医疗远程会诊高效方案
一、方案背景 当前医疗领域,医疗资源分布不均问题尤为突出,大城市和发达地区优质医疗资源集中,偏远地区医疗设施陈旧、人才稀缺,患者难以获得高质量的医疗服务,制约医疗事业均衡发展。 EasyRTC技术基于WebRTC等先进技…...
深入理解计算机系统记录
在 C 语言中,struct(结构体)和 union(联合体)都是用来存储多个不同类型的数据成员,但它们在内存分配和数据存储方式上有显著区别。下面详细说明它们的主要区别: 1. 内存分配 结构体(…...
【笔记】对抗训练-GAN
对抗训练-GAN 深度学习中 GAN 的对抗目标函数详解与最优解推导一、GAN 的基本对抗目标函数二、判别器与生成器的博弈目标三、判别器的最优解推导四、最优判别器的含义五、总结六、WGAN 的动机(为后续铺垫) 深度学习中 GAN 的对抗目标函数详解与最优解推导…...
(二十三)安卓开发中数据存储之Room详解
在安卓开发中,Room 是一个强大的本地数据库解决方案,它是 Android Jetpack 的一部分,基于 SQLite 构建,提供了更高层次的抽象。Room 简化了数据库操作,减少了样板代码,同时支持与 LiveData 和 ViewModel 的…...
AIoT 智变浪潮演讲实录 | 刘浩然:让硬件会思考:边缘大模型网关助力硬件智能革新
4 月 2 日,由火山引擎与英特尔联合主办的 AIoT “智变浪潮”技术沙龙在深圳成功举行,活动聚焦 AI 硬件产业的技术落地与生态协同,吸引了芯片厂商、技术方案商、品牌方及投资机构代表等 700 多位嘉宾参会。 会上,火山引擎边缘智能高…...
