一、前言

上一篇大概说了下abp通用树形模块如何使用,本篇主要分析下设计思路。

日常开发中会用到很多树状结构的数据,比如:产品的多级分类、省市区县,大多数系统也会用到类似“通用字典/数据字典”的功能,为系统各个地方提下拉框选择的数据源。abp提供了一个模块化系统,只要按它的约定就可以实现一个通用的树形数据的模块,这样公司的多个系统都可以使用,也可以用类似nuget的方式提供给别人使用。

先列举下它的功能

  1. 通过nuget方便安装和升级
  2. 配置简单
  3. 默认已经提供“通用字典”功能
  4. 实体、管理器、应用服务都是抽象类,结合泛型 狠容易扩展实现自己的树形结构

二、必备知识

这不是abp入门级的文章,是探讨系统模块化开发的一种思路。所以要求对abp有经验,完整看过abp文档,对涉及到的模块、依赖注入、启动配置、权限、菜单、本地化等等概念有清晰的认识

三、包和源码

源码地址:https://github.com/bxjg1987/abpGeneralModulesnuget:Install-Package BXJG.GeneralTree -Version 1.0.2
在线地址:  http://test.cqsifang.com/    账号密码:admin  zlj.com    (别胡来,拜托...)
源码仓库中还有通用的文件模块、附件模块,后期会讲讲;nuget搜索bxjg可以找到这几个相关的包

四、总体设计

为了便于说明,我们以常见的产品无限级分类来说明,所有树形结构数据有这么几个特点:

  • 有个ParentId属性指向父级节点,
  • 有个code,数据格式类似:00001.00001,一个是能简单体现产品分类节点的层级结构,二个是方便将来查询某个分类及其后代分类下的所有产品 where categoryCode like '00001%
  • 当然还有Name属性

上面说了定义实体类的关键点,然后我们需要提供一个对应的Manager(这个是abp定义领域服务的套路),来主负责CRUD和节点间的移动操作,其实最麻烦的就是自动处理code,新增和修改时要根据所属父节点的code自动生成子节点的code,移动时就更复杂了,要重新计算当前节点及其兄弟节点及其所有后代节点的code,这还涉及到目标节点和源节点。为了便于扩展,上面的领域服务还得将被处理的实体泛型话,文章后续会具体说明

最后按abp套路我们还需要提一个应用服务,它核心操作就是调用上面提供的Manager做节点的crud操作,在此基础上按abp的套路应该提供权限验证、处理实体与dto之间的转换。同理为了便于将来模块的使用方进行扩展,我们应该应用抽象类和泛型的威力,文章后续会具体说明

最后我们如何提供Repository呢?参考abp zero的思路,我们将这个遗留到调用方来定义。在我们的领域服务Manager和应用服务AppService中都是通过依赖注入注入的IRepository<TEntity,TKey>

核心的3个东东定义好后,我们分别实现一个默认类,实现一个“通用字典”,将来调用方可以继承我们的类并提供泛型参数来实现他们自己的树形结构。
另外我们将所有的代码放在一个项目中,因为模块足够小,功能少  这样调用方用起来更方便

注意一点,上面以产品分类来说明只是便于理解,既然要提供扩展能力,设计时只能从抽象的角度来看待树形数据,否则设计出来的东西很容易最后发现不够抽象,此废话只可意会不可言传

最后是abp相关的:本地化定义、模块定义及依赖关系、权限提供器、菜单提供器、动态webapi的处理

五、实体类

实体类我这里只是说明,具体源码请访问顶部的github

GeneralTreeEntity<TEntity>

它定义了树形结构数据的通用树形,Id、Code、Name、Parent等
泛型TEntity是子节点的类型,由于是树,实际上也是父节点的类型,这种设计是方便将来模块使用方在实现自定义的树形结构时拿到的Parent树形和Children树形,是他们自己定义的类型
主键Id属性,我定死了long类型,其实也可以使用泛型的TKey,思来想去简单起见直接定死吧

public class GeneralTreeEntity : GeneralTreeEntity<GeneralTreeEntity>

为了提供我们默认实现的“通用字典”功能,我们定义一个默认的子类GeneralTreeEntity,将来系统中那些简单的数据可以直接使用它
IsSysDefine表示此节点是否是系统预定义的,将来不允许删除
IsTree是否是树形,将来可能会用到,因为某些下拉框数据可能不需要多层次的,比如:民族,学历

六、领域服务

按套路我们提供一个抽象的领域服务Manager类,和一个为了实现“通用字典”功能的默认实现

public abstract class GeneralTreeManager<TEntity> : DomainService  where TEntity : GeneralTreeEntity<TEntity>

它的主要职责总体设计也说了一嘴,完成crud和move移动操作,难点是处理code的自动生成,尤其是移动节点时,节点原来位置之后的其它节点及其后代节点、目标节点之后的其它节点及其后代节点的code的生成
内部对数据的操作直接注入IRepository<TEntity, long>,因此按abp的套路,默认情况下使用EF时,调用方只需要在他的DBContext中顶一个DBSet就可以了

public class GeneralTreeManager : GeneralTreeManager<GeneralTreeEntity>

实现“通用数据字典”的默认领域服类,因为核心功能父类基本都完成了。所以几乎没代码

七、应用服务

按套路一个抽象类,一个默认实现类,内部核心操作是上面提供的Manager来完成的,应用服务主要是出去权限和dto之间的转换

public  class GeneralTreeAppServiceBase< TEntity,  TDto, TEditDto> : ApplicationService,     IGeneralTreeAppServiceBase<TDto, TEditDto>
        where TEntity : GeneralTreeEntity<TEntity>
        where TDto : GeneralTreeGetTreeNodeBaseDto<TDto>, new()
        where TEditDto : GeneralTreeNodeEditBaseDto

另外它提供了一些通用方法,一个树形数据通常在3个地方呗使用,以产品分类为例,在产品分类的管理页面、在产品的搜索栏应该提供产品类别的选择、在产品编辑页面应该有个下拉框选择当前产品所属类别,其它树形数据都有类似的场景,因此抽象的应用服务处理了这部分功能

public class GeneralTreeAppService : GeneralTreeAppServiceBase< GeneralTreeEntity, GeneralTreeDto, GeneralTreeEditDt, GeneralTreeManager>,IGeneralTreeAppService

按套路我们为“通用字典”提供了一个默认的实现类

应用服务中的DTO定义、应用服务接口我这里省略了,这是abp的常规套路,请看源码

八、abp相关套路:模块、本地化、权限、菜单

模块和本地化就不说了,abp的常规套路
由于我们提供了“通用字典”,默认情况下是可以直接用作你项目的,调用方完全可以按abp的套路在自己的模块中来配置权限和菜单,但是默认我们的模块也提供了,调用方完全可以在主机的PermissionProvicer和NavigationProvider的合适的位置配置权限和菜单。参考GeneralTreeModuleConfig源码

九、总结

abp本身提供了模块化方式,如果运用得当我们的系统可以由很多小模块组成,将来更容易维护、升级和复用
就好比我们目前提供的通用树,如果你使用的是abp,那么完全可以拿去就用,类似的“通用附件”模块,因为我们的多个系统或者同一个系统都可能会用到附件的功能,到处复制代码是下下策。

asp.net abp模块化开发之通用树2:设计思路及源码解析的更多相关文章

  1. abp模块化开发之通用树1:基本使用

    一.概述 有些功能在单个项目或多个项目被重复使用,比如:附件,同一个系统中的多个模块都可能使用到,不同项目也有需要.再比如:有无限级分类的树形功能,区域.产品分类.数据字典等.最简单粗暴的办法是直接复 ...

  2. Asp.net Mvc模块化开发之分区扩展框架

    对于一个企业级项目开发,模块化是非常重要的. 默认Mvc框架的AreaRegistration对模块化开发真的支持很好吗?真的有很多复杂系统在使用默认的分区开发的吗?我相信大部分asp.net的技术团 ...

  3. 初识ABP vNext(9):ABP模块化开发-文件管理

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 创建模块 模块开发 应用服务 运行模块 单元测试 模块使用 最后 前言 在之前的章节中介绍过ABP扩展实体,当时在用户 ...

  4. Asp.net Mvc模块化开发系列(目录)

    模块化开发是非常重要的,模块化开发是个系统性问题,为此我觉得有必须要写一个系列的文章才能基本说的清楚 那又为什么要写一个目录呢? 其一.是对我昨天承诺写一个系列新的文章的回应 其二.是先写出一个大纲, ...

  5. C#/ASP.NET MVC微信公众号接口开发之从零开发(四) 微信自定义菜单(附源码)

    C#/ASP.NET MVC微信接口开发文章目录: 1.C#/ASP.NET MVC微信公众号接口开发之从零开发(一) 接入微信公众平台 2.C#/ASP.NET MVC微信公众号接口开发之从零开发( ...

  6. 【源码解析】凭什么?spring boot 一个 jar 就能开发 web 项目

    问题 为什么开发web项目,spring-boot-starter-web 一个jar就搞定了?这个jar做了什么? 通过 spring-boot 工程可以看到所有开箱即用的的引导模块 spring- ...

  7. abp vnext2.0核心组件之领域实体组件源码解析

    接着abp vnext2.0核心组件之模块加载组件源码解析和abp vnext2.0核心组件之.Net Core默认DI组件切换到AutoFac源码解析集合.Net Core3.1,基本环境已经完备, ...

  8. asp微信支付代码证书文件post_url.aspx和post_url.aspx.cs源码下载

    很多朋友在网上找的asp支付代码中都没有这两个证书文件,只能是用别人的,但是如果别人把他的网站这个文件删了,你的支付也就不能用了,今天我就把大家需要的这两个asp微信支付代码证书文件post_url. ...

  9. c++实现游戏开发中常用的对象池(含源码)

    c++实现游戏开发中常用的对象池(含源码) little_stupid_child2017-01-06上传   对象池的五要素: 1.对象集合 2.未使用对象索引集合 3.已使用对象索引集合 4.当前 ...

随机推荐

  1. [校内训练20_01_20]ABC

    1.问有多少个大小为N的无标号无根树,直径恰好为L.$N,L \leq 200$ 2.问一个竞赛图中有多少个长度为3.4.5的环.$N \leq 2000$ 3.给出一些直线和单个点A,问这些直线的交 ...

  2. CentOS7主机名的查看和修改

    CentOS7主机名的查看和修改 在CentOS7中,有三种定义的主机名: 静态的(Static hostname) "静态"主机名也称为内核主机名,是系统在启动时从/etc/ho ...

  3. CGI fastCgi php-fpm PHP-CGI 辨析

    CGI fastCgi php-fpm PHP-CGI 辨析 LNMP环境中的nginx是不支持php的,需要通过fastcgi插件来处理有关php的请求.而php需要php-fpm这个组件提供该功能 ...

  4. Jconsole或者VisualVM监控远程主机(阿里云,jdk11或者8)

    准备: 1 一个war包或者jar包,这里我用springboot的 2 linux环境,安装tomcat,jdk,我用的jdk11和tomcat9,jdk11和8的拷贝权限文件路径有点不一样,这个需 ...

  5. Linux(Centos)安装Java JDK及卸载

    步骤一.下载安装包 a.   因为Java JDK区分32位和64位,所以安装之前需先判断一下我们操作系统为多少位·,命令如下: uname -a 解释:如果有x86_64就是64位的,没有就是32位 ...

  6. RPC简单设计方案

    服务端: 启动后,等待客户端发来信息,收到信息后进行处理,返回结果. 客户端: 主线程中发起一次RPC,那么就将信息封装成一个任务,提交到线程池,阻塞等待结果. 线程池中工作线程执行任务,发送信息,等 ...

  7. SDL多线程显示更新窗口

    //初始化SDL2和创建一个窗口,并且将屏幕绘制成大红色 #include <iostream> extern "C" { #include <SDL.h> ...

  8. pandas使用的25个技巧

      本文翻译自https://nbviewer.jupyter.org/github/justmarkham/pandas-videos/blob/master/top_25_pandas_trick ...

  9. HDU 1004 Let the Balloon Rise(STL初体验之map)

    Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...

  10. Java压缩包(zip)【学习笔记】

    前言 Java实现Zip压缩解压可以使用JDK的原生类java.util.zip,但是JDK 7 之前存在中文文件名乱码问题. 使用 ant.jar 的org.apache.tools.zip包,可以 ...