日均千万订单的交易平台设计稿

news2024/11/24 18:50:33

业务背景

平台主要售卖电子商品和少量特定的实物商品。

经营模式,主要分为平台商家和自营店,自营店的流量占整个平台业务的50%以上,我负责自营店交易履约相关业务。

以前的架构,平台交易和履约中心是所有流量共享,在发品的时候,可以针对产品的归属(平台商家/自营店)进行打标,后续可以针对产品的归属进行流量染色和路由。

下图以正向交易为例

PS:下图简化了整个交易的核心链路,其他域还有产品域、商品域、资源域、购物车域、出行人域、凭证域、商家域等很多强依赖以及弱依赖的相关域,后文所提到的商品和产品在本文的语义可以理解为一样的(实际上,在平台业务定义上,商品为C端所属,商品有自己的特别属性,比如:零售价,商品详情等;产品为B端所属,产品也有自己的特别属性,比如供应商、结算价、成本价等)

在这里插入图片描述

这个“采购平台”历史悠久,领域边界模糊,代码和技术腐化严重,对后续的业务支撑非常不友好。

考虑到疫情结束,业务前景向好,于是,在慎重决定下,要在原有的平台架构上,构建一套涵盖交易、履约、产品、资源、合约、直连、风控、计费结算等多个领域的全新供应链体系,期望能在短暂时间内,能够将原有的业务流量平滑迁移到新架构上,并且新架构在未来能够友好的扩展新的业务模式,显著提高平台收益。

因为平台主要售卖电子商品,几乎所有的商品走的都是线上履约方式,所以,交易和履约以及逆向业务都收敛到了我这里。

关键词:电商、供应链、交易履约、采购中心、订单中心、系统设计、技术方案、高并发、分布式

工程难点

时间

Question:这个新架构是倒排需求,第一版迭代周期只有三个月。在保证工程质量的情况下,需要在三个月之内完成:需求评审 - 技术方案评审 - 研发 - 自测 - 联调 - QA - 上线 - 切流,并且能够完全承接旧系统的业务流量。

Answer:敏捷开发、做好规划、风险把控、人力协调、视死如归、我是牛马。

业务

Question:旧系统的业务架构单一,新架构的业务复杂多变,未来预期很高,所以在系统设计之初,就需要具备一定的扩展性,在领域设计时,也要处理好领域边界和领域模型的建设。

Answer:深学平台全链路业务;广学行业内相关业务和解决方案;向前辈求学问道,无论如何先把东西学到手。

技术

Question:系统的流量和未来预期的流量很高,每天增量的订单就有千万级别。

  1. 新系统上线之后,如何将旧系统的数据和流量平滑迁移至新系统?
  2. 面对复杂业务架构,如何保证系统具备良好的业务扩展性?
  3. 面对复杂技术架构,如何保证订单数据的一致性?产品数据的一致性?
  4. 流量会集中在某一天或一天的某段时间,如何保证系统的可用性和稳定性?

Answer:具备领域驱动知识、分布式解决方案、行业解决方案、高并发场景解决方案;深入理解集团中间件。

组织

Question:平台侧的团队变动频繁,一套平台工程经历了十几个团队,业务逻辑不透明,平台侧的研发同学新人居多,接入很漫长,心理压力大,再加上组织架构的隔离性比较高,平台侧的问题很难推动。

Answer:提供足够的情绪价值、夸她、爱她、包容她;交付进度阻塞必须风险上升,一切以解决问题为主。

业务演进

之前的“采购平台”仅支持平台自营店,新的架构希望能够扩展业务模式,所以在原有的业务模式上,给新架构设定了三个目标。

目标核心

  1. 打通供应链交易履约逆向链路,完成流量的平滑迁移
  2. 在原有的业务基础上,具备横向纵向业务领域的扩展
    a. 在原有类目的基础上,能够自由扩展更多的业务类目
    b. 在原有销售模式的基础上,能够扩展更多的销售模式(直销、分销、代理等)
    c. 在原有业务模式的基础上,能够扩展更多的业务模式(秒杀、二次预约、囤货、预售等)
    d. 在原有支付体系的基础上,打造域内的资金池等体系(预付款、授信等)
  3. 能够支持线上计费结算,完全替代线下手工对账体系

演进阶段

在初步设定好新架构的目标之后,规划了一下业务演进的方向,大致分为了 3 个阶段。

  • 第一个阶段:构建高可用、高扩展的技术架构,并支持单业务类目单销售单支付模式,完成上线切流。
  • 第二个阶段:持续建设系统的稳定性,并支持单业务类目多销售模式单支付模式。
  • 第三个阶段:针对核心业务进行极致优化,并推动系统平台化发展,支持多业务类目多销售模式多支付模式。

收益体现

新架构的收益总结

经济收益:

  1. 针对自营店,2023年的GMV大概为 n 亿元,经过业务战略的调整和完善,2024年的GMV保守估计已达 2n+ 亿元,完成了自营店收益跨越式增长。
  2. 基于业务资源背景,打通分销销售渠道,一年入驻 分销商/代理商 x 家,接入 核销商/系统商/供应商 y 家,资源数量级涌进国内行业前列。
  3. 分销和代理渠道的GMV在一年内已远超自营店2023年的GMV,2024年保守估计已达 1.3n+ 亿元,成为平台经济收益新来源。

技术收益:

  1. 解决了高并发下的系统可用、数据一致等问题,解锁集团域内中间件新玩法。
  2. 沉淀出一套完整的交易履约技术方案、系统治理方案以及业务领域架构方案,实现域内相关业务可复用能力。

团队收益:

  1. 项目初期,周末加班双倍工资,项目稳定上线之后,每个人获得1~3个月工资的项目奖金,提升了团队人员流动的稳定性。
  2. 团队在前3个月一直保持007高强度的工作节奏,无一人缺席,倡导的狼性文化得到验证,提升了团队的凝聚力。
  3. 业务相关数据成指数级增长,带来了当下和未来及其可观的收益,供应链侧研发团队由 n 人,已经扩展到目前的 2n+ 人。

业务设计

交易角色

  1. 对于整个平台的交易角色,可以划分为:C - B - P - S
  2. 对于整个供应链领域,可以划分为:B - P - S
    C:用户|B:自营店/分销商/代理商|P:采购平台主体|S:供应商

交易属性

  1. 对于自营店,在 B - P 阶段的交易,本质上是虚拟交易。
  2. 对于分销商和代理商,是真实支付的线上交易。

交易阶段

在供应链交易这个领域,是两阶段交易:BP & PS。流量从 B 端过来,可能会涉及到拆单的操作,映射到系统设计上,BP 阶段产生的订单定义为主单(BP 单),主单拆成的订单,也就是 PS 阶段产生的订单,定义为子单(PS 单)。

领域设计

在设计之初,需要将各个领域边界划分清晰,方便后续的系统迭代和架构升级。

领域架构

整个新团队,职责划分非常明确和清晰,在经过数次的“脑暴”后,领域框架选型成了最大的问题。以前研究过Axon几年,并且有过Axon在大型区块链交易系统,从0到1的实战经验,所以在领域架构选型上,首推Axon作为整个团队的领域基础框架。

但是,在 “技术落地讨论会” 中,发现团队内的同学们,技术分散严重,只有一半是做过Java相关业务的,业务分散也很严重,只有一半是做过/了解过电商相关业务的。因此,大家对行业的业务领域和这些领域驱动框架,了解的不是特别多。

为了让项目尽快落地,在领域框架设计上,并没有严格采用DDD的思想,但是在系统设计上参考了Cola这类框架的整洁结构和Axon这类框架的事件驱动设计,结合平台的业务,将“脑暴”后的领域模型,不断推演,最后将传统的领域驱动框架进行抽象和精简,就有了现在的基础领域架构。

scc-starter是在大学开源的一套适配器组件的域内升级版,方便灵活,一键启动。

在这里插入图片描述

领域划分

最开始绿色的领域,都是打散到红色领域中,第一版上线以后,发现各个领域随着业务迭代愈发臃肿,于是及时做了调整。
核心域:订单域,支付域,资金域,履约域,退款域

支撑域:产品域,合约域,超时域,消息域

领域能力

订单域:预下单、收单

支付域:正向付款、逆向扣款等

资金域:资金流

履约域:预定资源、确定资源、服务完成

退款域:申请退款、快速退、强制退、退款回调

产品域:产品查询、库存扣减、库存回补、拆单、合单、Hold 单

合约域:合约信息查询、合约合法性校验

超时域:集团内部通用的技术解决方案,旨在解决分布式事务(tcc)、消息丢失、任务补偿等

消息域:领域事件驱动

领域事件

[思维导图]

领域模型

实体对象:采购单、资金单、履约单、退款单、预付款信息、预付款详情、调度任务

值对象:联系人信息、账户信息、合作关系、分销商与供应商信息、操作日志、退款规则、POI、凭证信息、出行人信息以及渠道信息

数据模型设计是整个系统最核心的环节,设计之初要保证数据结构具备足够的扩展性和容忍性。比如订单是否需要聚合、订单模型是否能够支撑未来的业务模式等。

订单状态

订单态:订单初始化 - 订单交易中 - 订单交易完成 - 订单交易关闭

履约态:履约单初始化 - 履约单已创建 - 供应商创单成功/失败 - 待核销 - 部分核销 - 全部核销 - 履约完成

支付态:未支付 - 已支付

退款态:未退款 - 退款单初始化 - 已申请退款 - 同意/拒绝退款 - 退款关闭 - 退款成功

资金态:未付款 - 已付款 - 付款成功/失败 - 分账完成/失败 - 结算完成/失败 - 交易完成/失败

系统设计

平台全链路交易履约时序图

新架构的预期流程,如下面的时序图所示(这是相对复杂的一种情况)
这个全链路时序图,屏蔽了很多交易系统弱依赖应用,希望能让读者轻松看懂整体的交易履约流程。
在这里插入图片描述
在这里插入图片描述

整体设计图

整体是两阶段交易,正向交易主单驱动子单,逆向履约子单推动主单,从下图来看:

第一阶段:收单 - 支付,归属于BP交易范畴,因为平台和分销商合作的性质不同,支付能力基于第三方支付平台和域内资金池等方式,但是整体而言都算是实时支付。

第二阶段:预订资源阶段本质上就是系统商创单的阶段,如果创单成功,会记录资金流水,同时也会给计费结算平台发送计费事件。这里其实也是基于平台和系统商合作的性质,因为平台和所有的系统商资金都是T+1月结。

在这里插入图片描述

解决方案

收单服务治理

收单服务接口,是整个交易平台的流量口子,在收单过程中,会和域内域外多个服务进行交互,涉及到各种复杂的业务逻辑。比如合约服务、产品中心和直连网关等,这些服务都是交易平台强依赖的,这些服务不可用,也会导致交易平台不可用,本地基本上是没有什么降级方案的。

除了本地服务基本的代码优化(减少调用链路,优化代码逻辑执行顺序,将阻断校验流程前置,优化数据结构和算法,优化查询逻辑,减少IO次数,利用本地缓存等),合约服务接口性能、产品中心服务接口性能以及第三方支付平台的接口性能,成为了影响收单服务接口性能的重要因素。

  1. 合约服务:查询合约信息等
  2. 产品中心:查询产品信息、扣减库存、回补库存等
  3. 支付能力:支付宝代扣(查、付、退、取消、校验等)

在这里插入图片描述

第一阶段开发周期短,核心是如期交付上线,接住旧系统的线上流量,为后续的业务扩展带来可能。根据已有大KA的要求,收单RT在6秒之内,收单服务即为可用,上线之后,收单服务的RT常态化Max为5秒。

治理前后各项指标概要:

  1. 总响应时间(RT)显著提升:
    治理前:4700ms
    治理后:250ms
    治理效果:提升了18倍
  2. 本地计算响应时间(RT)显著缩短:
    治理前:200ms
    治理后:30ms
    治理效果:缩短了6倍
  3. 查询产品信息响应时间(RT)大幅减少:
    治理前:800ms
    治理后:70ms
    治理效果:提升了11倍
  4. 查询合约信息响应时间(RT)大幅降低:
    治理前:1200ms
    治理后:60ms
    治理效果:提升了20倍
  5. 校验支付能力响应时间(RT)极大缩短:
    治理前:500ms
    治理后:10ms
    治理效果:提升了50倍
  6. 预占库存响应时间(RT)显著减少:
    治理前:2000ms
    治理后:80ms
    治理效果:提升了25倍
  7. 单机QPS(每秒查询次数)大幅提高:
    治理前:40qps
    治理后:800qps
    治理效果:提升了20倍
  8. 集群Max QPS显著提升:
    治理前:1100
    治理后:4000
    治理效果:提升了4倍
  9. 收单Max QPS显著提升:
    治理前:300
    治理后:1200
    治理效果:提升了4倍
  10. 服务器数量优化:
    治理前:40台(4C8G)
    治理后:21台(4C12G),包括10台、8台和3台不同配置
    治理效果:服务器数量减少,配置提升。

库存扣减

https://blog.csdn.net/CSDN_SAVIOR/article/details/142887066

产品查询

https://issavior.blog.csdn.net/article/details/140734888

支付能力

正式创单之前,会进行支付校验,域外的支付服务,非常不稳定,因此,增加了重试、补偿等容错手段。为了彻底解决这种问题,提高成单率,平台在域内打造资金池,分销商可在平台预付款,每次支付从资金池扣减。

流量平滑迁移

https://issavior.blog.csdn.net/article/details/141201666

业务扩展能力

https://issavior.blog.csdn.net/article/details/140891892
https://issavior.blog.csdn.net/article/details/140903785

系统数据治理

订单数据一致性

https://issavior.blog.csdn.net/article/details/141275722

订单全局唯一ID

https://issavior.blog.csdn.net/article/details/141279168

存量数据

针对旧采购系统的订单数据,新交易系统不必感知。

旧系统的存量数据和新系统的增量数据由买家域和卖家域自行处理这些数据即可。处理数据需要注意数据的一致性,在平滑切流的过程中,新系统可能会存在旧系统的数据,域外在同步数据的时候可以做一层清洗和过滤。

数据的分片

随着分销商和供应商资源的不断涌入,流量在一段时间内成指数增长,庞大的订单数据该如何存储?这里的方案是采用分库分表(未分区)和读写分离架构,将数据和流量打散。

将采购单表、资金单表、履约单表、任务表进行水平拆分,设计到相关的技术是TDDL,核心原理和Sharding-JDBC差不多。

拆分规则

因为采购单数据不涉及到实时查询,所以根据订单ID直接取模即可。

分片规则

根据以前业务的数据规模以及业务方针对未来的流量期望,每天的增量订单会有千万级别。

根据集团的数据库和存储引擎性能,最终采取的分库分表方案如下:
8库 - 32张表/库 - 256张表

数据清理

供应链交易履约平台的订单的生命周期比较短,目前已知订单最长的生命周期是一个月,所以可以将数月之前的数据同步到冷库中。

读写分离

准确的说,读写分离在交易系统上的实践是有风险的,交易系统大多为实时查询,如果因为大事务、网络抖动等原因,导致从库的数据同步有延时,那对于交易系统的稳定性是非常致命的。

这里读写分离主要是用在一些域内非核心应用(小二系统),给这些非核心且关键的业务透出一个口子,做一些必要操作,但是也要注意这些接口的稳定性,比如限流措施等。交易等核心业务,对于数据的实时性要求比较高,读写都需要在master节点上。

但是这样的设计显然不合理,应该要将这些依赖交易系统的非核心应用全部干掉,让他们通过其他渠道去获取数据,以此来提升交易系统的稳定性。

系统治理

流量分组

  1. 交易平台将自营店流量和分销/代理流量进行分组,避免销售渠道相互影响。
  2. 全链路服务将交易的流量单独隔离开,避免非核心业务影响到交易链路。
    异常监控
    针对系统和业务级别的异常,划分严重等级,做聚合告警(整合行业AI大模型,做智能监控),通知运营和研发同学,及时处理。

发布流程

上线之前,严格按着发布流程来,研发 - 自测 - QA - CR - 安全环境回归 - 观察 - 灰度发布 - 观察 - 分批上线 - 观察,而且CR务必经过Owner,血的教训。

埋点日志

针对各个交易节点,做全链路trace埋点,除了排查问题之外,还可以溯源,很多次,系统商服务的问题,无法追溯,导致结算出问题。

风控巡检

上线之后,发现系统商这服务说挂就挂,很不稳定,用风控巡检来对所有的系统商服务接口做探针探活,有问题就熔断掉异常系统商服务,服务存活后,再恢复系统商服务能力。

熔断限流

对外的接口,上线之前要进行服务接口进行压测,并根据压测结果,设置合理的限流阈值,防止服务挂掉。

日常工具

常见的不可抗拒的问题,需要制定相应的工具,遇到问题时可以提供给运营或者研发同学。

紧急预案

如果出现线上的问题,需要有止血措施,比如在上线之前,可以针对改动点增加动态配置开关,如果出现问题,可以秒级止血,即在1秒内关闭上线功能,然后在进行回滚以及问题排查等措施。

问题复盘

出现问题不要怕,要及时复盘、总结,不能秉持“少做少错,不做不错”的态度。

节前准备

针对于预知的流量(节假日、营销活动等)要做好扩容,值班人员必须保证问题响应效率和解决质量。

风险排查

成单率、消息堆积、磁盘内存、ES容量、数据同步延迟、慢SQL等。

提效秘籍

自己这几年用的还不错的复盘计划,分享一下,希望能对大家有所帮助。
在这里插入图片描述

结束语

本文对“交易履约平台”做了简单叙述,主要从宏观视角概述了繁杂业务中仅一条相对复杂的“交易”业务线的相关要点,当然,履约和逆向业务也是非常的好玩并且具备难点和技术挑战,若有机会,我将分享这些领域的心得。

期望本文能为初涉电商交易领域的小伙伴们提供一些有价值的启发。同时,希望各位老师不吝批评指正,指出文中的瑕疵与待改进之处。更期盼大家在评论区踊跃留言,共同交流心得、探讨问题,携手促进我们的成长与进步。

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

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

相关文章

day01-Qt5入门

day01-Qt5入门 1.下载Qtcreate 官网地址:http://qt-project.org/downloads 2.配置环境变量 将类似于 D:\Qt\Qt5.1.1\5.1.1\mingw48_32\bin 的目录添加到环境变量中 3.创建一个新项目 输入自己的项目名称,后面默认下一部 4.运行第一个项目 在窗口…

计算机网络:数据链路层 —— PPP 点对点协议

文章目录 PPP 帧PPP帧的格式PPP帧的透明传输面向字节的异步链路面向比特的同步链路 PPP帧的差错检测 PPP 的工作状态 点对点协议(Point-to-Point Protocol,PPP)是目前使用最广泛的点对点数据链路层协议,用于在两个节点之间进行数据…

10.12面试题

代理模式 为什么需要代理模式? 1.中介隔离 客户类不想或者不能直接引用委托对象,需要使用代理类作为中介,需要代理类和委托对象都实现同一接口 2.满足开闭原则 若客户类需要委托对象新增某些功能,就需要代理类在调用委托对象…

【ProtoBuf】基础使用与编译

文章目录 ProtoBuf的使用基本使用指定proto3语法package声明符定义消息(message)定义消息字段字段唯一编号 编译序列化与反序列化序列化与反序列化使用 ProtoBuf的使用 流程如下: 编写 .proto文件,定义结构对象(message)及属性内容使用 protoc 编译器编…

常用类(二)--String类的简单总结

文章目录 1.基本介绍1.1创建对象1.2找到对应下标的字符1.3找到对应字符的下标1.4指定位置开始遍历1.5反向进行遍历1.6大小写之间的转换1.7字符串转换为数组1.8元素的替换1.9字符串的分割1.10字符串的截取 2.StringBuilder和StringBuffer2.1 StringBuilder的引入2.2面试题目 1.基…

拆解学习【无线充,EMMC,锂电池电量计,OTA】(二)

主要学习到了:无线充,EMMC,手表CPU方案,锂电池电量计,OTA。 无线充电功能是产品的核心卖点之一,充电头网通过拆解发现,手表内部使用恒玄BES2500BP智能手表单芯片解决方案,内置四核C…

BetterZip怎么导入文件进行压缩?苹果解压软件怎么用?

BetterZip作为苹果系统常用的压缩文件软件之一,具有使用方便、压缩导出格式多、兼容性强等特点。我们要使用BetterZip进行文件压缩时,首先需要将文件导入到BetterZip才可以。 关于BetterZip的文件导入方式,主要有几种,今天我来给…

垂直AI大模型行业全景分析及发展趋势研究报告

2024-10-12调研咨询机构环洋市场咨询出版的【全球垂直AI大模型行业总体规模、主要厂商及IPO上市调研报告,2024-2030】只要调研全球垂直AI大模型总体规模,主要地区规模,主要企业规模和份额,主要产品分类规模,下游主要应…

每日一题|3158. 求出出现两次数字的 XOR 值|哈希

题目给的范围很小,50以内,所以什么数据结构都可以。 这里采用set来维护访问过的数字,利用哈希来提升时间效率。 class Solution:def duplicateNumbersXOR(self, nums: List[int]) -> int:visited set()l []res 0for i in nums:if i i…

游戏如何应对薅羊毛问题

在大众眼里,“薅羊毛”是指在电商领域,“羊毛党”利用平台、商家的促销规则,低价获取商品和服务的行为。如前不久“小天鹅被一夜薅走7000万”的案例震惊全网。 然而实际上,“薅羊毛”现象不仅存在于电商场景,在游戏中…

【Unity】TextMeshPro 3.0.9无法显示emoji表情问题

需要下载TextMeshPro 3.2.x-pre.xxx版本,重新生成Sprite Asset文件解决 注意:若Package Manager没有搜到pre版本,那么可以去github下载到本地,再解压后,将文件夹移动到工程Packages文件夹下,然后打开Packa…

基于SpringBoot的体育商城购物系统

作者:计算机学姐 开发技术:SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等,“文末源码”。 专栏推荐:前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏:…

React复习

文章目录 常用的HooksuseStateuseReduceruseRefuseContextuseMemouseCallbackuseEffect 组件通信Props(属性)Ref(引用)Context(上下文)State(状态)回调函数Event Bus(事件…

Python WebSocket 的原理及其应用

Python WebSocket 的原理及其应用 在现代 Web 开发中,实时通信成为了越来越多应用的重要组成部分。尤其是像聊天应用、实时数据更新、在线游戏等场景,服务器与客户端之间的即时数据传输需求非常迫切。在传统的 HTTP 协议中,通信往往是基于请…

在docker的容器内如何查看Ubuntu系统版本

文章目录 写在前面一、问题描述二、解决方法参考链接 写在前面 自己的测试环境: docker 一、问题描述 由于 lsb_release -a 只能查看自己电脑(宿主机)的系统版本,如果在docker的容器内又应该如何查看Ubuntu系统版本呢&#xff…

GoPro 解决方案:恢复 GoPro 数据、GoPro 重置为出厂设置

在本文中,我们将向您展示如何轻松将 GoPro 相机重置为出厂设置以及如何从已重置为出厂设置的 GoPro 中恢复丢失的数据。 第 1 部分:将 GoPro 重置为出厂设置后恢复丢失的数据。 ​在将 GoPro 重置为出厂设置之前,最好对视频进行完整备份。但…

URDF统一机器人建模语言

统一机器人建模语言 URDF(Unified Robot Description Format)统一机器人描述格式,URDF使用XML格式描述机器人文件。 我们从下面四个方面介绍URDF: URDF的组成介绍 URDF-Link介绍 URDF-Joint介绍 创建一个简单的URDF…

大数据新视界 --大数据大厂之差分隐私技术在大数据隐私保护中的实践

💖💖💖亲爱的朋友们,热烈欢迎你们来到 青云交的博客!能与你们在此邂逅,我满心欢喜,深感无比荣幸。在这个瞬息万变的时代,我们每个人都在苦苦追寻一处能让心灵安然栖息的港湾。而 我的…

ribbon和nginx负载均衡图解

通俗来说 nginx: 规定一个地址v(比如v代理了地址a,b,c,d且他们都实现了同一个服务e),然后当我们的请求想要实现e服务而去请求v的时候,v实际上就会从a,b,c,d中选一个来让他们给请求者提供服务。 ribbon: …

[Halcon矩阵] 通过手眼标定矩阵计算相机旋转角度

📢博客主页:https://loewen.blog.csdn.net📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!📢本文由 丶布布原创,首发于 CSDN,转载注明出处🙉📢现…