需求分析与场景定义
- 明确代码生成器的目标:生成实体类、API控制器、DTO等常见场景
- 典型应用场景:快速开发CRUD功能、减少重复编码工作
- 核心需求:可配置性、模板灵活性、与项目结构无缝集成
具体实现可参考NetCoreKevin的kevin.CodeGenerator模块
基于.NET构建的企业级SaaS智能应用架构,采用前后端分离设计,具备以下核心特性:
前端技术:
- Vue3前端框架
- IDS4单点登录系统
- 一库多租户解决方案
- 多级缓存机制
- CAP事件集成
- SignalR实时通信
- 领域驱动设计
- AI智能体框架
- RabbitMQ消息队列
- 项目地址:github:https://github.com/junkai-li/NetCoreKevin
Gitee: https://gitee.com/netkevin-li/NetCoreKevin
第一步:配置模板
模板配置示例如下图所示:
创建kevin.CodeGenerator模块
ICodeGeneratorService接口定义- using kevin.CodeGenerator.Dto;
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace kevin.CodeGenerator
- {
- public interface ICodeGeneratorService
- {
- /// <summary>
- /// 获取区域名称列表
- /// </summary>
- /// <returns></returns>
- Task<List<string>> GetAreaNames();
- /// <summary>
- /// 获取区域名称下面的表列表
- /// </summary>
- /// <returns></returns>
- Task<List<EntityItemDto>> GetAreaNameEntityItems(string areaName);
- /// <summary>
- /// 生成代码
- /// </summary>
- /// <param name="entityItems"></param>
- /// <returns></returns>
- Task<bool> BulidCode(List<EntityItemDto> entityItems);
- }
- }
复制代码 CodeGeneratorService实现- using kevin.CodeGenerator.Dto;
- using Microsoft.CodeAnalysis;
- using Microsoft.CodeAnalysis.CSharp;
- using Microsoft.CodeAnalysis.CSharp.Syntax;
- using Microsoft.Extensions.Options;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Reflection.Metadata;
- using System.Text;
- using static Microsoft.CodeAnalysis.CSharp.SyntaxTokenParser;
- namespace kevin.CodeGenerator
- {
- public class CodeGeneratorService : ICodeGeneratorService
- {
- private CodeGeneratorSetting _config;
- public CodeGeneratorService(IOptionsMonitor config)
- {
- _config = config.CurrentValue;
- }
- public async Task<List<string>> GetAreaNames()
- {
- return _config.CodeGeneratorItems.Select(t => t.AreaName).ToList();
- }
- public async Task<List<EntityItemDto>> GetAreaNameEntityItems(string areaName)
- {
- var area = _config.CodeGeneratorItems.FirstOrDefault(t => t.AreaName == areaName);
- if (area != default)
- {
- var entityItems = new List<EntityItemDto>();
- var path = "..\\..\" + area.AreaPath.Trim().Replace(".", "\");
- // 遍历路径下的所有 .cs 文件
- if (!Directory.Exists(path))
- {
- throw new ArgumentException($"CodeGeneratorSetting配置:{areaName}{area.AreaPath}不存在");
- }
- else
- {
- var csFiles = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);
- foreach (var file in csFiles)
- {
- // 读取文件内容
- var code = File.ReadAllText(file);
- var tree = CSharpSyntaxTree.ParseText(code);
- var root = (CompilationUnitSyntax)tree.GetRoot();
- // 查找所有类声明
- var classDeclarations = root.DescendantNodes().OfType<ClassDeclarationSyntax>();
- foreach (var classDeclaration in classDeclarations)
- {
- // 检查类是否有 Table 特性
- if (classDeclaration.AttributeLists.Any(list =>
- list.Attributes.Any(attr =>
- attr.Name.ToString() == "Table")))
- {
- string description = "";
- // 检查类是否有 Description 特性
- var descriptionAttr = classDeclaration.AttributeLists
- .SelectMany(list => list.Attributes)
- .FirstOrDefault(attr => attr.Name.ToString() == "Description");
- if (descriptionAttr != null)
- {
- // 获取特性参数值
- var arg = descriptionAttr.ArgumentList?.Arguments.FirstOrDefault();
- if (arg?.Expression is LiteralExpressionSyntax literal)
- {
- description = literal.Token.ValueText;
- }
- }
- entityItems.Add(new EntityItemDto
- {
- AreaName = area.AreaName,
- EntityName = classDeclaration.Identifier.Text,
- Description = $"{file}: {description}"
- });
- }
- }
- }
- return entityItems;
- }
- }
- return new List<EntityItemDto>();
- }
- public async Task<bool> BulidCode(List<EntityItemDto> entityItems)
- {
- //获取对应的模板文件
- var iRpTemplate = GetBuildCodeTemplate("IRp");
- var rpTemplate = GetBuildCodeTemplate("Rp");
- var iServiceTemplate = GetBuildCodeTemplate("IService");
- var service = GetBuildCodeTemplate("Service");
- foreach (var item in entityItems)
- {
- var area = _config.CodeGeneratorItems.FirstOrDefault(t => t.AreaName == item.AreaName);
- if (area != default)
- {
- if (item.EntityName.StartsWith("T", StringComparison.OrdinalIgnoreCase))
- {
- item.EntityName = item.EntityName.Substring(1);
- }
- WriteCode(new Dictionary<string, string>
- {
- { "%entityName%",item.EntityName},
- { "%namespacePath%",area.IRpBulidPath}
- }, iRpTemplate, $"../../{area.IRpBulidPath.Trim().Replace(".", "\")}/I{item.EntityName}Rp.cs");
- WriteCode(new Dictionary<string, string>
- {
- { "%entityName%",item.EntityName},
- { "%namespacePath%",area.RpBulidPath}
- }, rpTemplate, $"../../{area.RpBulidPath.Trim().Replace(".", "\")}/{item.EntityName}Rp.cs");
- WriteCode(new Dictionary<string, string>
- {
- { "%entityName%",item.EntityName},
- { "%namespacePath%",area.IServiceBulidPath}
- }, iServiceTemplate, $"../../{area.IServiceBulidPath.Trim().Replace(".", "\")}/I{item.EntityName}Service.cs");
- WriteCode(new Dictionary<string, string>
- {
- { "%entityName%",item.EntityName},
- { "%namespacePath%",area.ServiceBulidPath}
- }, service, $"../../{area.ServiceBulidPath.Trim().Replace(".", "\")}/{item.EntityName}Service.cs");
- }
- }
- return true;
- }
- /// <summary>
- /// 获取对应模板文件
- /// </summary>
- /// <param name="name"></param>
- /// <returns></returns>
- private string GetBuildCodeTemplate(string name)
- {
- return File.ReadAllText("..\\..\" + "Kevin\\kevin.Module\\kevin.CodeGenerator\\BuildCodeTemplate\" + name + ".txt", encoding: Encoding.UTF8);
- }
- /// <summary>
- /// 生成文件和代码
- /// </summary>
- /// <param name="paramters"></param>
- /// <param name="content"></param>
- /// <param name="savePath"></param>
- private void WriteCode(Dictionary<string, string> paramters, string content, string savePath)
- {
- foreach (var item in paramters)
- {
- content = content.Replace(item.Key, item.Value);
- }
- var dir = Path.GetDirectoryName(savePath);
- if (!Directory.Exists(dir))
- {
- Directory.CreateDirectory(dir);
- }
- if (File.Exists(savePath))
- {
- Console.WriteLine($"文件{savePath}已存在,跳过生成!");
- }
- else
- {
- File.WriteAllText(savePath, content, Encoding.UTF8);
- }
- }
- }
- }
复制代码 CodeGeneratorSettingDto- namespace kevin.CodeGenerator.Dto
- {
- public class CodeGeneratorSetting
- {
- /// <summary>
- /// 配置文件相关信息
- /// </summary>
- public List CodeGeneratorItems { get; set; } = new();
- }
- public class CodeGeneratorItem
- {
- /// <summary>
- /// 区域
- /// </summary>
- public string AreaName { get; set; } = "";
- /// <summary>
- /// 数据库实体类路径
- /// </summary>
- public string AreaPath { get; set; } = "";
- /// <summary>
- /// 仓储接口生成路径
- /// </summary>
- public string IRpBulidPath { get; set; } = "";
- /// <summary>
- /// 仓储生成路径
- /// </summary>
- public string RpBulidPath { get; set; } = "";
- /// <summary>
- /// 服务接口生成路径
- /// </summary>
- public string IServiceBulidPath { get; set; } = "";
- /// <summary>
- /// 服务生成路径
- /// </summary>
- public string ServiceBulidPath { get; set; } = "";
- }
- }
复制代码 配置Json文件- ////代码生成器配置 .转换成/时要和路径一致 请配置好命名空间和路径对应关系
- "CodeGeneratorSetting": {
- "CodeGeneratorItems": [
- {
- "AreaName": "App.WebApi.v1", //项目命名
- "AreaPath": "App.Domain.Entities", //实体类路径
- "IRpBulidPath": "App.Domain.Interfaces.Repositorie.v1", //仓储接口命名空间和路径
- "RpBulidPath": "App.RepositorieRps.Repositories.v1", //仓储命名空间和路径
- "IServiceBulidPath": "App.Domain.Interfaces.Services.v1", //服务接口命名空间和路径
- "ServiceBulidPath": "App.Application.Services.v1" //服务命名空间和路径
- }
- ]
- }
复制代码 服务注入- services.AddKevinCodeGenerator(options =>
- {
- var settings = Configuration.GetRequiredSection("CodeGeneratorSetting").Get()!;
- options.CodeGeneratorItems = settings.CodeGeneratorItems;
-
- });
复制代码 使用
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |