java自学教程|www.konglongmei.com

作者: David902
查看: 94|回复: 0

more +社区更新Forums

more +随机图赏Gallery

[技术知识] ABPHelper.CLI及其依赖项简单介绍

[技术知识] ABPHelper.CLI及其依赖项简单介绍

[复制链接]
David902 | 显示全部楼层 发表于: 2020-7-30 20:49:24
David902 发表于: 2020-7-30 20:49:24 | 显示全部楼层 |阅读模式
查看: 94|回复: 0
目录

ABPHelper.CLI

命令行CLI实现ABP VNEXT中CRUD代码的生成,用户只需要创建一个实体类,即可生成该表的CRUD,并添加到项目中。
使用前请确保备份您的源文件!
入门


  • 安装 AbpHelper CLI 工具
    dotnet tool install EasyAbp.AbpHelper -g
如果您更喜欢GUI,那么还有一个UI工具: AbpHelper.GUI

  • 如果以前安装过,请使用以下命令更新它:
    dotnet tool update EasyAbp.AbpHelper -g
  • 使用 ABP CLI 创建一个ABP 应用
    abp new MyToDo
  • 创建实体
  1. public class Todo : FullAuditedEntity{    public string Content { get; set; }    public bool Done { get; set; }}
复制代码

  • 运行 AbpHelper
abphelper generate crud Todo -d C:\MyTodo

  • generate crud 是生成CRUD文件的子命令
  • Todo 指定了我们先前创建的实体名
  • -d 指定了由ABP CLI创建的ABP项目的根目录
AbpHelper 将生成所有的CRUD , 甚至包括添加迁移和数据库更新!

  • 运行这个 DbMigrator 项目去迁移数据库
  • 启动你的应用
  • 用默认的管理员帐户登录,看到神奇的事发生了!

如果看不到 TODO 菜单,请检查您的权限并确保授予了TODO相关的权限
使用指南


  • 运行abphelper -h 查看帮助
  • 类似地,您可以使用 -h或--help 选项查看以下每个命令的详细用法
命令行


  • generate
    为ABP项目生成文件. 使用 'abphelper generate --help' 获取详情

    • crud
      根据指定实体生成一组与CRUD相关的文件
      1. abphelper generate crud Todo
      复制代码

    • service
    根据指定的名称生成服务接口和类文件
    1. abphelper generate service Project -f Projects
    复制代码


    • methods
      Generate service method(s) according to the specified name(s)
      根据指定名称,给service 增加方法
      1. abphelper generate methods Login Logout -s Project
      复制代码

    • localization
      Generate localization item(s) according to the specified name(s)
      根据指定名称生成localization 本地化项
      1. abphelper generate localization MyItem1 MyItem2 MyItem3
      复制代码

    • controller
      1. abphelper generate controller Todo
      复制代码
      Generate controller class and methods according to the specified service


技术点如下


  • Scriban
  • Microsoft.Extensions.FileProviders.Embedded
  • Microsoft.CodeAnalysis.CSharp
  • System.CommandLine
  • Elsa
  • Humanizer.Core
如果我们想实现代码生成器,我们需要解决什么问题呢。

  • 提供.NET接口的模板引擎,比如Razor,Sciban等
  • 模板一般放在文件中,我们需要知道如何读取这些资源文件,文本文件。
  • 如果我们使用code first,通常需要创建一个实体类,当创建好一个类后,怎么解析出这个类名,属性,命名空间呢,而不是另外去输入这些参数。(只需要代码的路径)

    • 实体名Name,比如BaseItem
    • 命名空间NameSpace LinCms.Base.BaseItems或Volo.Abp.BaseItems
    • 主键类型PrimaryKey,比如是Guid,还是int,还是long

  • 明确有哪些变量,如何控制输入。

    • 模板的位置TemplatePath : ./Templates
    • 根据模板生成的代码的输出目录OutputDirectory : 相对路径 或 绝对路径 ./output  或 D:/code/github/code-scaffolding

Scriban

Scriban是一种快速、强大、安全和轻量级的文本模板语言和.NET引擎,具有解析liquid模板的兼容模式
创建一个xunit测试项目,引入包Sciban
  1. [/code]做一个小测试
  2. [code][Fact]public void Test1(){    var template = Template.Parse("Hello {{name}}!");    var result = template.Render(new { Name = "World" });    Assert.Equal("Hello World!", result);}
复制代码
ctrl+r  ctrl+t 运行测试,正常。
写一个我们仓储接口。
  1.      [Fact]        public void Test9()        {            var template = Template.Parse(@"using LinCms.Core.Entities;namespace LinCms.Core.IRepositories{    public interface I{{ entity_name }}Repository : IAuditBaseRepository    {    }}");            var result = template.Render(new { EntityName = "Doc" });            Assert.Equal(@"using LinCms.Core.Entities;namespace LinCms.Core.IRepositories    {        public interface IDocRepository : IAuditBaseRepository        {        }    }".Replace("\r\n", "").Replace(" ", ""), result.Replace("\r\n", "").Replace(" ", ""));        }
复制代码
最终生成的效果是
  1. using LinCms.Core.Entities;namespace LinCms.Core.IRepositories{    public interface IDocRepository : IAuditBaseRepository    {    }}
复制代码
通过Microsoft.Extensions.FileProviders.Embedded获取嵌入资源

这是一个嵌入资源Provider,提供嵌入资源的获取,比如我们写的Sciban的模板文件。
xunit测试项目引入包
  1. [/code]创建一个测试类FileTest
  2. [code][Fact]public void FileProviderTest(){    IFileProvider fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(FileTest)));}
复制代码
出现这个错
System.InvalidOperationException:“Could not load the embedded file manifest 'Microsoft.Extensions.FileProviders.Embedded.Manifest.xml' for assembly 'OvOv.Test'.”
打开OvOv.Test.csproject
PropertyGroup增加如下一行
true
新建目录Templates,新建文本文件 IRepository.txt,右键属性,生成操作(嵌入的资源),可不选复制到输出目录
  1. using LinCms.Core.Entities;namespace LinCms.Core.IRepositories{    public interface I{{ entity_ame }}Repository : IAuditBaseRepository    {    }}
复制代码
可修改csproject文件设置Templates目录下都是嵌入式资源
  1.        
复制代码
在测试方法中,通过GetFileInfo,得到IFileInfo.通过stream进行读取文本,并输出。
  1. private readonly ITestOutputHelper output;public FileTest(ITestOutputHelper output){    this.output = output;}[Fact]public void GetTextTest(){    IFileProvider fileProvider = new ManifestEmbeddedFileProvider(Assembly.GetAssembly(typeof(FileTest)));    IFileInfo fileInfo = fileProvider.GetFileInfo("./Templates/IRepository.txt");    string text;    using (var stream = fileInfo.CreateReadStream())    {        using (var streamReader = new StreamReader(stream, Encoding.UTF8, true))        {            text = streamReader.ReadToEnd();        }    }    output.WriteLine(text);}
复制代码
通过静态方法获取文件内容

不用嵌入式资源,需要右键文件 属性(复制到输出目录:如果较新则复制),可不选生成操作
  1. [Fact]public void ReadAllText(){    string text = File.ReadAllText("./Templates/IRepository.txt");    output.WriteLine(text);}
复制代码
使用Microsoft.Extensions.FileProviders.Physical获取文件内容

引用包
  1. [/code][code][Theory][InlineData("./Templates/IRepository.txt")]public void PhysicalFileProviderReadText(string path){    var current = Environment.CurrentDirectory;    var fileProvider = new PhysicalFileProvider(current);    IFileInfo fileInfo = fileProvider.GetFileInfo(path);    string text;    using (var stream = fileInfo.CreateReadStream())    {        using (var streamReader = new StreamReader(stream, Encoding.UTF8, true))        {            text = streamReader.ReadToEnd();        }    }    output.WriteLine(text);}
复制代码
var current = Environment.CurrentDirectory;  这行代码,能得到当前的目录,因为设置为输出 ,所以当前目录下有templates文件夹,并有IRepository.txt
  1. "D:\\code\\gitee\\Code\\OvOv.Test\\bin\\Debug\\netcoreapp3.1"
复制代码
Microsoft.CodeAnalysis.CSharp

代码生成还需要什么呢,创建一个实体类,根据此实体类生成表的CRUD代码。
修改OvOv.Test,引入包
复制代码
这个包是https://github.com/dotnet/roslyn的一部分.Roslyn 是.NET编译器为C#和Visual Basic 提供了丰富的代码分析API。
再搞个CodeAnalysisTest测试类。这里我们有一个字符串,他是一个实体类,这个类有一些特点。比如

  • 命名空间namespace
  • 类名 class
  • 继承的父类泛型类型 guid
  • 有二个属性,author,title
如下代码,通过语法树,解析出这个字符串中的命名空间,输出 LinCms.Books。
说明: FullAduitEntity是一个包含CRUD的审计实体类,通常包含七个字段(创建人,创建时间,修改人,修改时间,是否删除,删除人,删除时间),另外还有一个主键。默认是long,具体可查看此文件https://github.com/luoyunchong/lin-cms-dotnetcore/blob/master/src/LinCms.Core/Entities/FullAduitEntity.cs
你也可以使用诸如Entity,即一个泛型的实体类即可。
  1. public class Entity{    public T Id { get; set; }}
复制代码
  1. [Fact]public void GetNamespace(){    string text = @"namespace LinCms.Books{    public class Book : FullAduitEntity    {        public string Author { get; set; }        public string Title { get; set; }     }}";    SyntaxTree tree = CSharpSyntaxTree.ParseText(text);    CompilationUnitSyntax root = tree.GetCompilationUnitRoot();    var @namespace = root.DescendantNodes().OfType().Single().Name.ToString();    output.WriteLine(@namespace);    }
复制代码
获取类名.className为Book
  1. ClassDeclarationSyntax classDeclarationSyntax = root.DescendantNodes().OfType().Single();string className = classDeclarationSyntax.Identifier.ToString();
复制代码
获取父类baseType为FullAduitEntity
主键类型primaryKey值为Guid
  1.     BaseListSyntax baseList = classDeclarationSyntax.BaseList!;var genericNameSyntax = baseList.DescendantNodes().OfType()    .First(node => !node.ToFullString().StartsWith("I")) // Not interface    .DescendantNodes().OfType()    .FirstOrDefault();string baseType;string? primaryKey;if (genericNameSyntax == null){    // No generic parameter -> Entity with Composite Keys    baseType = baseList.DescendantNodes().OfType().Single().Type.ToString();    primaryKey = "long";}else{    // Normal entity    baseType = genericNameSyntax.Identifier.ToString();    primaryKey = genericNameSyntax.DescendantNodes().OfType().Single().Arguments[0].ToString();}
复制代码
获取该类的属性集合。
  1. var properties = root.DescendantNodes().OfType()                  .Select(prop => new PropertyInfo(prop.Type.ToString(), prop.Identifier.ToString()))                  .ToList();
复制代码
其中PropertyInfo是用来存储属性集合的实体类
  1. public class PropertyInfo{    public string Type { get; }    public string Name { get; }    public PropertyInfo(string type, string name)    {        Type = type;        Name = name;    }}
复制代码
我们通过debugger查看局部变量。

Humanizer.Core

Humanizer可以用来处理strings, enums, dates, times, timespans, numbers and quantities所有的需求。
当我们写代码时,总避免不了写复数形式的代码,一些特殊的后缀不是直接加s就行的。
所以可以用Humanizer来处理这些特殊的变量

  • 转下划线  Underscore
  • 复数形式(比如取集合数据时,变量名) Pluralize
  • 转小驼峰写法(比如变量)  Camelize
  • 更多直接看README
通过扩展方法生成这些字符串。
  1. public class EntityInfo{    public EntityInfo(string name)    {        Name = name;    }    public string Name { get; }    ///     /// 复数    ///     public string NamePluralized => Name.Pluralize();    ///     /// 首字母小写    ///     public string NameCamelize => Name.Camelize();    ///     /// 小写+复数    ///     public string NameCamelizePluralized => Name.Camelize().Pluralize();}
复制代码
System.CommandLine

System.CommandLine是一组用于构建命令行应用程序的库,包括解析,调用和渲染。
他能简化命令行参数的处理,帮助我们构建自己的CLI。
对于代码生成器,不要是必须的。
Elsa

Elsa Core是一个工作流库,可在任何 .NET Core应用程序中执行工作流。工作流可以不仅使用代码来定义,也可作为JSON,YAML或XML。
代码生成器,流程多,可使用此程序工作流来处理。不是必须的。
AbpHelper.GUI

ABP VNEXT的代码生成的可视化界面,使用方式看README就好,不多介绍。
帮助ABP VNext的开发者快速构建单表的CRUD的。
如果你自己研究一下这些类库的使用方法,特别是Sciban。我们也能实现代码生成器,帮助改善公司及自己已有项目的开发流程。

鲁班 Java架构师VIP课程一期共89G视频教程 luban it教程下载:http://www.77cxw.com/download/78
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|网站地图|java自学教程|www.konglongmei.com

GMT+8, 2020-9-24 20:32 , Processed in 0.263482 second(s), 47 queries .

快速回复 返回顶部 返回列表