业务下单系统网站源码分享?业务订单接单下单流程

其实业务下单系统网站源码分享的问题并不复杂,但是又很多的朋友都不太了解业务订单接单下单流程,因此呢,今天小编就来为大家分享业务下单系统网站源码分享的一些知识,希望可以帮助到大家,下面我们一起来看看这个问题的分析吧!

接上一篇Newbe.Claptrap框架入门,第三步——定义Claptrap,管理商品库存,我们继续要了解一下如何使用Newbe.Claptrap框架开发业务。通过本篇阅读,您便可以开始学会在Claptrap框架中使用Minion进行异步的业务处理。

Newbe.Claptrap是一个用于轻松应对并发问题的分布式开发框架。如果您是首次阅读本系列文章。建议可以先从本文末尾的入门文章开始了解。

开篇摘要

本篇,我通过实现“商品下单”的需求来了解一下如何在已有的项目样例中使用Minion来完成异步的业务处理。

首先,先了解一下本篇需要涉及的业务用例:

用户可以进行下单操作,下单时将使用当前购物车中的所有SKU形成一个订单。下单后将会扣除相关SKU的库存。如果某一SKU库存不足,则下单失败。下单操作仅到扣减库存成功为止,后续步骤不需要本样例讨论范围。因此,本样例在成功下单之后会在数据库中生成一条订单记录,表示订单创建结束。

本篇虽然重点在于Minion的使用,不过由于需要使用到一个新的OrderGrain对象,因此还是需要使用到前一篇“定义Claptrap”的相关知识。

Minion是一种特殊的Claptrap,它与其MasterClaptrap之间的关系如下图所示:

其主体开发流程和Claptrap类似,只是有所删减。对比如下:

步骤ClaptrapMinion定义ClaptrapTypeCode??定义State??定义Grain接口??实现Grain??注册Grain??定义EventCode?定义Event?实现EventHandler??注册EventHandler??实现IInitialStateDataFactory??

这个删减的原因是由于Minion是Claptrap的事件消费者,所以事件相关的定义不需要处理。但是其他的部分仍然是必须的。

本篇开始,我们将不再罗列相关代码所在的具体文件位置,希望读者能够自行在项目中进行查找,以便熟练的掌握。

实现OrderGrain

基于前一篇“定义Claptrap”相关的知识,我们此处实现一个OrderGrain用来表示订单下单操作。为节约篇幅,我们只罗列其中关键的部分。

OrderState

订单状态的定义如下:

usingSystem.Collections.Generic;\nusingNewbe.Claptrap;\n\nnamespaceHelloClaptrap.Models.Order\n{\npublicclassOrderState:IStateData\n{\npublicboolOrderCreated{get;set;}\npublicstringUserId{get;set;}\npublicDictionary<string,int>Skus{get;set;}\n}\n}

OrderCreated表示订单是否已经创建,避免重复创建订单UserId下单用户IdSkus订单包含的SkuId和订单量

OrderCreatedEvent

订单创建事件的定义如下:

usingSystem.Collections.Generic;\nusingNewbe.Claptrap;\n\nnamespaceHelloClaptrap.Models.Order.Events\n{\npublicclassOrderCreatedEvent:IEventData\n{\npublicstringUserId{get;set;}\npublicDictionary<string,int>Skus{get;set;}\n}\n}

OrderGrain

usingSystem.Threading.Tasks;\nusingHelloClaptrap.Actors.Order.Events;\nusingHelloClaptrap.IActor;\nusingHelloClaptrap.Models;\nusingHelloClaptrap.Models.Order;\nusingHelloClaptrap.Models.Order.Events;\nusingNewbe.Claptrap;\nusingNewbe.Claptrap.Orleans;\nusingOrleans;\n\nnamespaceHelloClaptrap.Actors.Order\n{\n[ClaptrapEventHandler(typeof(OrderCreatedEventHandler),ClaptrapCodes.OrderCreated)]\npublicclassOrderGrain:ClaptrapBoxGrain<OrderState>,IOrderGrain\n{\nprivatereadonlyIGrainFactory_grainFactory;\n\npublicOrderGrain(IClaptrapGrainCommonServiceclaptrapGrainCommonService,\nIGrainFactorygrainFactory)\n:base(claptrapGrainCommonService)\n{\n_grainFactory=grainFactory;\n}\n\npublicasyncTaskCreateOrderAsync(CreateOrderInputinput)\n{\nvarorderId=Claptrap.State.Identity.Id;\n//throwexceptioniforderalreadycreated\nif(StateData.OrderCreated)\n{\nthrownewBizException($&34;);\n}\n\n//getitemsfromcart\nvarcartGrain=_grainFactory.GetGrain<ICartGrain>(input.CartId);\nvaritems=awaitcartGrain.GetItemsAsync();\n\n//updateinventoryforeachsku\nforeach(var(skuId,count)initems)\n{\nvarskuGrain=_grainFactory.GetGrain<ISkuGrain>(skuId);\nawaitskuGrain.UpdateInventoryAsync(-count);\n}\n\n//removeallitemsfromcart\nawaitcartGrain.RemoveAllItemsAsync();\n\n//createaorder\nvarevt=this.CreateEvent(newOrderCreatedEvent\n{\nUserId=input.UserId,\nSkus=items\n});\nawaitClaptrap.HandleEventAsync(evt);\n}\n}\n}

OrderGrain实现订单的创建核心逻辑,其中的CreateOrderAsync方法完成购物车数据获取,库存扣减相关的动作。OrderCreatedEvent执行成功后将会更新State中相关的字段,此处就不再列出了。

通过Minion向数据库保存订单数据

从系列开头到此,我们从未提及数据库相关的操作。因为当您在使用Claptrap框架时,绝大多数的操作都已经被“事件的写入”和“状态的更新”代替了,故而完全不需要亲自编写数据库操作。

不过,由于Claptrap通常是对应单体对象(一个订单,一个SKU,一个购物车)而设计的,因而无法获取全体(所有订单,所有SKU,所有购物车)的数据情况。此时,就需要将状态数据持久化到另外的持久化结构中(数据库,文件,缓存等)以便完成全体情况的查询或其他操作。

在Claptrap框架中引入了Minion的概念来解决上述的需求。

接下来,我们就在样例中引入一个OrderDbGrain(一个Minion)来异步完成OrderGrain的订单入库操作。

定义ClaptrapTypeCode

namespaceHelloClaptrap.Models\n{\npublicstaticclassClaptrapCodes\n{\n34;cart_claptrap_newbe&34;_e_&34;addItem&34;removeItem&34;remoeAllItems&endregion\n\n34;sku_claptrap_newbe&34;_e_&34;inventoryUpdate&endregion\n\n34;order_claptrap_newbe&34;_e_&34;orderCreated&34;db_order_claptrap_newbe&endregion\n}\n}

Minion是一种特殊的Claptrap,换言之,它也是一种Claptrap。而ClaptrapTypeCode对于Claptrap来说是必需的,因而需要增加此定义。

定义State

由于本样例只需要向数据库写入一条订单记录就可以了,并不需要在State中任何数据,因此该步骤在本样例中其实并不需要。

定义Grain接口

+usingHelloClaptrap.Models;\n+usingNewbe.Claptrap;\n+usingNewbe.Claptrap.Orleans;\n+\n+namespaceHelloClaptrap.IActor\n+{\n+[ClaptrapMinion(ClaptrapCodes.OrderGrain)]\n+[ClaptrapState(typeof(NoneStateData),ClaptrapCodes.OrderDbGrain)]\n+publicinterfaceIOrderDbGrain:IClaptrapMinionGrain\n+{\n+}\n+}

ClaptrapMinion用来标记该Grain是一个Minion,其中的Code指向其对应的MasterClaptrap。ClaptrapState用来标记Claptrap的State数据类型。前一步,我们阐明该Minion并不需要StateData,因此使用NoneStateData这一框架内置类型来代替。IClaptrapMinionGrain是区别于IClaptrapGrain的Minion接口。如果一个Grain是Minion,则需要继承该接口。ClaptrapCodes.OrderGrain和ClaptrapCodes.OrderDbGrain是两个不同的字符串,希望读者不是星际宗师。

星际宗师:因为星际争霸比赛节奏快,信息量大,选手很容易忽视或误判部分信息,因此经常发生“选手看不到发生在眼皮底下的关键事件”的搞笑失误。玩家们由此调侃星际玩家都是瞎子(曾经真的有一场盲人和职业选手的对决),段位越高,瞎得越严重,职业星际选手清一色的盲人。

实现Grain

+usingSystem.Collections.Generic;\n+usingSystem.Threading.Tasks;\n+usingHelloClaptrap.Actors.DbGrains.Order.Events;\n+usingHelloClaptrap.IActor;\n+usingHelloClaptrap.Models;\n+usingNewbe.Claptrap;\n+usingNewbe.Claptrap.Orleans;\n+\n+namespaceHelloClaptrap.Actors.DbGrains.Order\n+{\n+[ClaptrapEventHandler(typeof(OrderCreatedEventHandler),ClaptrapCodes.OrderCreated)]\n+publicclassOrderDbGrain:ClaptrapBoxGrain<NoneStateData>,IOrderDbGrain\n+{\n+publicOrderDbGrain(IClaptrapGrainCommonServiceclaptrapGrainCommonService)\n+:base(claptrapGrainCommonService)\n+{\n+}\n+\n+publicasyncTaskMasterEventReceivedAsync(IEnumerable<IEvent>events)\n+{\n+foreach(var@eventinevents)\n+{\n+awaitClaptrap.HandleEventAsync(@event);\n+}\n+}\n+\n+publicTaskWakeAsync()\n+{\n+returnTask.CompletedTask;\n+}\n+}\n+}

MasterEventReceivedAsync是定义自IClaptrapMinionGrain的方法,表示实时接收来自MasterClaptrap的事件通知。此处暂不展开说明,按照上文模板实现即可。WakeAsync是定义自IClaptrapMinionGrain的方法,表示MasterClaptrap主动唤醒Minion的操作。此处暂不展开说明,按照上文模板实现即可。当读者查看源码时,会发现该类被单独定义在一个程序集当中。这只是一种分类办法,可以理解为将Minion和MasterClaptrap分别放置在两个不同的项目中进行分类。实际上放在一起也没有问题。

注册Grain

此处,由于我们将OrderDbGrain定义在单独的程序集,因此,需要额外的注册这个程序集。如下所示:

usingSystem;\nusingAutofac;\nusingHelloClaptrap.Actors.Cart;\nusingHelloClaptrap.Actors.DbGrains.Order;\nusingHelloClaptrap.IActor;\nusingHelloClaptrap.Repository;\nusingMicrosoft.AspNetCore.Hosting;\nusingMicrosoft.Extensions.Hosting;\nusingMicrosoft.Extensions.Logging;\nusingNewbe.Claptrap;\nusingNewbe.Claptrap.Bootstrapper;\nusingNLog.Web;\nusingOrleans;\n\nnamespaceHelloClaptrap.BackendServer\n{\npublicclassProgram\n{\npublicstaticvoidMain(string[]args)\n{\nvarlogger=NLogBuilder.ConfigureNLog(&34;).GetCurrentClassLogger();\ntry\n{\nlogger.Debug(&34;);\nCreateHostBuilder(args).Build().Run();\n}\ncatch(Exceptionexception)\n{\n//NLog:catchsetuperrors\nlogger.Error(exception,&34;);\nthrow;\n}\nfinally\n{\n//Ensuretoflushandstopinternaltimers/threadsbeforeapplication-exit(AvoidsegmentationfaultonLinux)\nNLog.LogManager.Shutdown();\n}\n}\n\npublicstaticIHostBuilderCreateHostBuilder(string[]args)=>\nHost.CreateDefaultBuilder(args)\n.ConfigureWebHostDefaults(webBuilder=>{webBuilder.UseStartup<Startup>();})\n.UseClaptrap(\nbuilder=>\n{\nbuilder\n.ScanClaptrapDesigns(new[]\n{\ntypeof(ICartGrain).Assembly,\ntypeof(CartGrain).Assembly,\n+typeof(OrderDbGrain).Assembly\n})\n.ConfigureClaptrapDesign(x=>\nx.ClaptrapOptions.EventCenterOptions.EventCenterType=EventCenterType.OrleansClient);\n},\nbuilder=>{builder.RegisterModule<RepositoryModule>();})\n.UseOrleansClaptrap()\n.UseOrleans(builder=>builder.UseDashboard(options=>options.Port=9000))\n.ConfigureLogging(logging=>\n{\nlogging.ClearProviders();\nlogging.SetMinimumLevel(LogLevel.Trace);\n})\n.UseNLog();\n}\n}

实现EventHandler

+usingSystem.Threading.Tasks;\n+usingHelloClaptrap.Models.Order.Events;\n+usingHelloClaptrap.Repository;\n+usingNewbe.Claptrap;\n+usingNewtonsoft.Json;\n+\n+namespaceHelloClaptrap.Actors.DbGrains.Order.Events\n+{\n+publicclassOrderCreatedEventHandler\n+:NormalEventHandler<NoneStateData,OrderCreatedEvent>\n+{\n+privatereadonlyIOrderRepository_orderRepository;\n+\n+publicOrderCreatedEventHandler(\n+IOrderRepositoryorderRepository)\n+{\n+_orderRepository=orderRepository;\n+}\n+\n+publicoverrideasyncValueTaskHandleEvent(NoneStateDatastateData,\n+OrderCreatedEventeventData,\n+IEventContexteventContext)\n+{\n+varorderId=eventContext.State.Identity.Id;\n+await_orderRepository.SaveAsync(eventData.UserId,orderId,JsonConvert.SerializeObject(eventData.Skus));\n+}\n+}\n+}

IOrderRepository是直接操作存储层的接口,用于订单的增删改查。此处调用该接口实现订单数据库的入库操作。

注册EventHandler

实际上为了节约篇幅,我们已经在“实现Grain”章节的代码中进行注册。

实现IInitialStateDataFactory

由于StateData没有特殊定义,因此也不需要实现IInitialStateDataFactory。

修改Controller

样例中,我们增加了OrderController用来下单和查询订单。读者可以在源码进行查看。

读者可以使用以下步骤进行实际的效果测试:

POST/api/cart/123{“skuId”:”yueluo-666”,”count”:30}向123号购物车加入30单位的yueluo-666号浓缩精华。POST/api/order{“userId”:”999”,”cartId”:”123”}以999userId的身份,从123号购物车进行下单。GET/api/order下单成功后可以,通过该API查看到下单完成的订单。GET/api/sku/yueluo-666可以通过SKUAPI查看下单后的库存余量。

小结

至此,我们就完成了“商品下单”这个需求的基础内容。通过该样例可以初步了解多个Claptrap可以如何合作,以及如何使用Minion完成异步任务。

不过,还有一些问题,我们将在后续展开讨论。

您可以从以下地址来获取本文章对应的源代码:

GithubGitee

最后但是最重要!

最近作者正在构建以反应式、Actor模式和事件溯源为理论基础的一套服务端开发框架。希望为开发者提供能够便于开发出“分布式”、“可水平扩展”、“可测试性高”的应用系统——Newbe.Claptrap

本篇文章是该框架的一篇技术选文,属于技术构成的一部分。如果读者对该内容感兴趣,欢迎转发、评论、收藏文章以及项目。您的支持是促进项目成功的关键。

联系方式:

GithubIssueGiteeIssue公开邮箱newbe-claptrap@googlegroups.com(发送到该邮箱的内容将被公开)GitterQQ群610394020

您还可以查阅本系列的其他选文:

理论入门篇

Newbe.Claptrap-一套以“事件溯源”和“Actor模式”作为基本理论的服务端开发框架

术语介绍篇

Actor模式事件溯源(EventSourcing)ClaptrapMinion事件(Event)状态(State)状态快照(StateSnapshot)Claptrap设计图(ClaptrapDesign)Claptrap工厂(ClaptrapFactory)ClaptrapIdentityClaptrapBoxClaptrap生命周期(ClaptrapLifetimeScope)序列化(Serialization)

实现入门篇

Newbe.Claptrap框架入门,第一步——创建项目,实现简易购物车Newbe.Claptrap框架入门,第二步——简单业务,清空购物车Newbe.Claptrap框架入门,第三步——定义Claptrap,管理商品库存

样例实践篇

构建一个简易的火车票售票系统,Newbe.Claptrap框架用例,第一步——业务分析在线体验火车票售票系统

其他番外篇

谈反应式编程在服务端中的应用,数据库操作优化,从20秒到0.5秒谈反应式编程在服务端中的应用,数据库操作优化,提速Upsert十万同时在线用户,需要多少内存?——Newbe.Claptrap框架水平扩展实验docker-mcr助您全速下载dotnet镜像十多位全球技术专家,为你献上近十个小时的.Net微服务介绍年轻的樵夫哟,你掉的是这个免费8核4G公网服务器,还是这个随时可用的Docker实验平台?

GitHub项目地址:https://github.com/newbe36524/Newbe.Claptrap

Gitee项目地址:https://gitee.com/yks/Newbe.Claptrap

您当前查看的是先行发布于www.newbe.pro上的博客文章,实际开发文档随版本而迭代。若要查看最新的开发文档,需要移步claptrap.newbe.pro。

本文作者:newbe36524本文链接:https://www.newbe.pro/Newbe.Claptrap/Get-Started-4/版权声明:本博客所有文章除特别声明外,均采用BY-NC-SA许可协议。转载请注明出处!

关于业务下单系统网站源码分享的内容到此结束,希望对大家有所帮助。

Published by

风君子

独自遨游何稽首 揭天掀地慰生平