前言
目前在开发abp电商模块,打算做一步,写一步,算是对自己的记录,主要是参考nopcommoner 并结合abp模块开发
知识都是连贯的,如果你熟悉asp.net core 3.x、abp(非vNext) 并且需要做电商功能,也许可以做个参考。即使不做电商,可能里面的其它功能也可以作为参考,如:如何开发abp模块、如何集成简单的微信功能(小程序登录、小程序支付)、通用字典模块、等等...
如果不熟悉asp.net core或abp,那建议还是补充基础知识后再说
如果你是专注电商的.neter,建议用nopcommerce,它是一个成熟完善的.net开源电商
本篇说说搭建电商模块开发环境
资源
- asp.net core 3框架揭秘【书】
- 大文件分片上传/秒传附件功能【视频】
- 通用数据字典【视频】
- 微信小程序登录【视频】
- 微信小程序支付【视频】
- >>>>>>>>>>>源码地址
建立电商模块项目
abp的模块就是个dll+一个特殊的类(其中包含生命周期方法),具体概念请参考官方文档
我这里说的电商模块是指的功能模块,按abp的分层方式分为:
- xxx.Core:实体、领域服务、领域事件和其它核心功能
- xxx.EFCore:基于efCore的仓储实现,由于abp的牛B,它基本为空
- xxx.Application:应用服务,动态webApi
木有提供UI部分,因为是前后单分离的(WebAdmin是基于JQuery的纯静态网站)
可以看到结构与abp默认项目模板保持一致
XXX.Core
与abp模型项目模板一致,它用来定义实体类、领域服务、领域事件、仓储接口 等。它是一个dll,也是一个独立的abp模块
Authorization:按abp的要求定义电商系统中涉及到的权限定义
Configuration:按abp要求定义的电商系统设计到“设置”功能,这个后期可能细化
Localization:商场模块有自己独立的本地化配置,
BXJGShopConsts:常量定义
BXJGShopDomainServiceBase:领域服务抽象类,将来定义的领域服务可能大多会继承这个类
BXJGShopCoreModule:这个还是按abp的标准模块定义方式,在模块的生命周期事件中做些初始化工作。
可以看到所有东东还是原来的配方,如果你熟悉abp 几乎不用思考。
本篇主要讲商城模块环境搭架,所以下面只是简单说说正在做的一些具体功能
Catalogue/ItemsEntity:是已经在做的“商品上架信息”的实体类,里面包含:商品基本信息、上架信息(是否热卖,是否新品、上架开始/结束时间等)、价格信息(原价、优惠价、等.),后续会陆续添加其它电商业务相关实体,订单、会员啥的...
Common/BXJGShopDictionaryEntity:电商模块单独的“通用字典”功能,比如支付方式、配送方式将来很多下拉框数据都使用这个,它是它是通过我们之前说的通用树模块来实现的。
Customer:顾客功能,它与abp的用户是做一对一关联,可以发现CustomerEntity<TUser>使用的泛型,这样将来你在引入商城模块时需要提供你自己的用户类型。整个商城功能可能会存在大量这种泛型的设计,目的是让模块与主程序分离。
Sale:中是跟销售相关的功能,核心的就是订单咯,后续会细讲
XXX.EFCore
这个是对应abp中的XXX.EntityFrameworkCore模块,是用来定义电商业务中数据操作的,也称为仓储实现层。但是由于abp已经提供了一个通用的泛型仓储实现,因此这个类库中基本上看不到啥东西,除非有特殊情况才需要专门定义。
另一个重要作用是用来定义EF映射配置,因为决定所有实体采用ef api的方式来定义映射。其中ModelBuilderExt用来定义扩展方法,方便将来调用方一次性配置商城系统中的EF映射。在你的主程序的DbContext做如下配置:
1 protected override void OnModelCreating(ModelBuilder modelBuilder) 2 { 3 base.OnModelCreating(modelBuilder); 4 //扫描并应用商城模块中的ef映射 5 modelBuilder.ApplyConfigurationBXJGShop<User>(); 6 }
XXX.Applicatiom
商城模块应用服务层,同时它也是一个abp模块。
BXJGShopApplicationModule:按abp模块套路定义的
BXJGShopAppServiceBase:商城功能应用服务基类
BXJGShopNavigationProvider:注意这是一个静态类,里面定义了商城功能的菜单,你需要在你主程序中的NavigationProvider中来调用这个静态方法,并传入上级菜单定义,这样做的目的是允许你将商城功能相关的菜单插入到你主菜单的指定节点位置。
以“商品上架信息ItemEntity”为例感受下
在XXX.Shop.Core中定义实体
商城里肯定包含很多商品咯,它的实体定义在这里:源码
在XXX.Shop.Core中定义商品管理相关权限
在xxx.Shop.EFCore中定义EF映射配置
目前源码里针对商品信息的映射没有定义,因为使用api映射是后来决定的,不过有“订单”的映射文件可以参考。然后修改ModelBuilderExt,添加映射类,参考Order的设计
在xxx.Shop.Application中定义应用服务
定义DTO、IAppService、AppService这个就是abp老套路,特别注意就是泛型的定义,目的之前说过,为了实现商城模块独立于主程序。参考源码。
然后定义商品管理对应的菜单
主程序如何引入?
1、主程序的EF中的DbContext配置
1 #region 注册商城模块中的实体 2 public virtual DbSet<BXJGShopDictionaryEntity> BXJGShopDictionaries { get; set; } 3 public virtual DbSet<ItemEntity> BXJGShopItems { get; set; } 4 public virtual DbSet<CustomerEntity<User>> BXJGShopCustomers { get; set; } 5 public virtual DbSet<OrderEntity<User>> BXJGShopOrders { get; set; } 6 #endregion 7 8 public ZLJDbContext(DbContextOptions<ZLJDbContext> options) 9 : base(options) 10 { } 11 12 protected override void OnModelCreating(ModelBuilder modelBuilder) 13 { 14 base.OnModelCreating(modelBuilder); 15 16 //扫描并应用商城模块中的ef映射 17 modelBuilder.ApplyConfigurationBXJGShop<User>(); 18 }
2、主程序的Core/AuthorizationProvider配置商品管理的权限
1 public class ZLJAuthorizationProvider : AuthorizationProvider 2 { 3 GeneralTreeModuleConfig cfg; 4 public ZLJAuthorizationProvider(GeneralTreeModuleConfig cfg) 5 { 6 this.cfg = cfg; 7 } 8 public override void SetPermissions(IPermissionDefinitionContext context) 9 { 10 var admin = context.CreatePermission(PermissionNames.Administrator, L("Administrator")); 11 //{codegenerator} 12 #region 商城 13 BXJGShopAuthorizationProvider.SetPermissions(admin); 14 #endregion 15 #region 资产管理
3、主程序的应用层中提供应用服务类,目的是指定商城管理服务需要的泛型
1 public class ItemAppService : ItemAppService<Tenant, User, Role, TenantManager, UserManager> 2 { 3 public ItemAppService(IRepository<ItemEntity, long> repository) : base(repository) 4 { 5 } 6 }
4、主程序的Web.Core注册商城模块的动态api功能
1 Configuration.Modules.AbpAspNetCore().CreateControllersForAppServices(typeof(BXJGShopApplicationModule).Assembly/*,"bxjgshop"*/);
最后
整个设计尽量做到模块分离,主要还是参考abp zero的思路,它让你去提供User类,使用UserManager时也需要提供TUser,最后达到模块独立的效果、方便扩展,你可以实现自己的User添加扩展字段。
如何做到模块可扩展性呢?有几种思路,刚才说的模块内部大量使用泛型和抽象类,让模块的调用方(比如我们的主程序)可以通过继承的方式来进行扩展。
也可以使用abp提供的EventBus功能,在模块内部触发各种事件,调用方(也就是我们这里的主程序)可以注册这些事件,达到参与到商城业务的目的。
后面再考虑吧,万里长征第一步才开始~希望不会烂尾....