egg代码生成器

今天给大家分享一下egg的代码生成器,这个其实原理很简单,说白了就是用到了nodejs的一个文件io的操作,通过一系列配置参数解析然后生成一个很长的字符串,写入到文件中,最后导出到我们指定的文件夹。

前提概要

为什么我要写这个代码生成器呢?原因主要还是为了提高自己平时开发的效率和时间,比如说什么呢,其实现在单表单业务的管理系统页面完全是可以使用代码生成来做的,可以极大程度的去简化我们开发的一个效率,也是我们一个摸鱼神器。话不多说,讲讲我的大致的一个思路把

大致思路

这里我希望每次生成代码都是根据配置进行生成,我希望我每次在egg-sequelize设计好一个实体之后,然后自动关联到数据表,自动获取数据表中的字段,这个字段我可以进行配置也可以不进行配置,然后这些字段最终都是要加入到我后端的crud接口中的。

我这里使用的是egg-swagger-doc框架,还需要根据它那边的规则去生成对应的swagger文档,所以我写了一个大致的配置

在这里插入图片描述

这样的话我就可以根据具体的配置去生成对应的controller,对应的service,对应的router以及vue文件,生成完成之后的str,我就根据工具类的创建文件夹,创建对应的controller,service,router,vue等文件夹,再把文件内容写入到文件,放入到对应文件夹里面,这就是我分享的代码生成器的大致的一个实现思路

工具类

// 移除文件夹,移除output目录
function clearOutputFolder() {fs.readdirSync(outputPath).forEach((file) => {if (file !== 'index.js') {const filePath = path.join(outputPath, file);if (fs.lstatSync(filePath).isDirectory()) {deleteFolderRecursive(filePath);} else {fs.unlinkSync(filePath);}}});
}// 创建文件夹
function createFolder(folderName) {return new Promise((resolve, reject) => {fs.mkdir(folderName, (err) => {if (err) {reject(err);} else {resolve();}});});
}// 删除文件夹
function deleteFolderRecursive(folderPath) {// 文件夹存在if (fs.existsSync(folderPath)) {// 读取文件夹里面所有文件fs.readdirSync(folderPath).forEach((file) => {const currentFilePath = path.join(folderPath, file);// 如果是文件夹,递归删除if (fs.lstatSync(currentFilePath).isDirectory()) {deleteFolderRecursive(currentFilePath); // 递归删除子文件夹} else {// 如果是文件删除文件fs.unlinkSync(currentFilePath); // 删除文件}});fs.rmdirSync(folderPath); // 删除空文件夹}
}//生成controller代码
function generateController(){//...
}//生成service代码
function generateService(){//...
}//生成swagger的contract代码,用于放dto和vo的对象
function generateContract(){//...
}//生成路由代码
function generateRouter(){//...
}//生成swagger api字符串
function generateSwaggerApiStr(){}

入口

  const str = `请选择要使用的功能1.代码生成器2.根据表格生成所有字段基本信息请输入对应的数字序号`;let number = await getInput(str);if (Number(number) === 1) {const config = require('./config');let isUseFileConfig = await getInput('你是否使用文件配置(yes/no)','select');let author,parentMenu,moduleEName,moduleName,moduleDescription,isGenerateAnnotaion;// 是否使用文件配置if (!isUseFileConfig) {author = await getInput('请输入作者');parentMenu = await getInput('请输入模块所在上层目录');moduleName = await getInput('请输入模块中文名称');moduleEName = await getInput('请输入模块英文名称');moduleDescription = await getInput('请输入模块描述信息');isGenerateAnnotaion = await getInput('你是否想要生成注释信息(yes/no)','select');} else {author = config.author;parentMenu = config.parentMenu;moduleName = config.moduleName;moduleEName = config.moduleEName;moduleDescription = config.moduleDescription;isGenerateAnnotaion = config.isGenerateAnnotaion;}clearOutputFolder();const date = timeFormat(new Date());const upperCaseModuleEName = capitalizeFirstLetter(moduleEName);const upperCaseParentMenu = capitalizeFirstLetter(parentMenu);let generateConfig = {author,parentMenu,moduleName,moduleEName,moduleDescription,isGenerateAnnotaion,date,upperCaseModuleEName,upperCaseParentMenu};if (isUseFileConfig) {generateConfig = {...generateConfig,...config};}// 生产控制器代码generateController(generateConfig);// 生产路由代码generateRouter(generateConfig);// 生产服务端代码generateService(generateConfig);// 生成swagger的contractgenerateContract(generateConfig);// 生成前端的文件generateVueFolder(generateConfig);console.log('代码生成完成,生成的文件在codeGenerator/output文件夹下');rl.close();} else if (Number(number) === 2) {let table = await getInput('请输入表名称');const str = await getVoByTb(table);const folderPath = path.join(__dirname, 'output');// console.log(folderPath);// await createFolder(folderPath);const filePath = path.join(folderPath, 'dto.js');fs.writeFileSync(filePath, str);console.log('vo生成完成,生成的文件在codeGenerator/output文件夹下,名字为dto.js');rl.close();} else {console.log('输入的值出错!!');rl.close();}// 控制台输入
async function getInput(question, type) {return new Promise((resolve) => {rl.question(question, (input) => {input = input.trim();if (!input) {console.log('输入不能为空,请再次输入');resolve(getInput(question));} else {if (type === 'select') {if (input.toLocaleLowerCase() === 'yes') {resolve(true);} else if (input.toLocaleLowerCase() === 'no') {resolve(false);} else {console.log('请输入yes或者no');resolve(getInput(question));}}resolve(input);}});});
}

我这里还使用了一个控制台输入的,做了两种配置,可以通过配置指定,也可以通过控制台输入,这里控制台输入的有一些还没有完善好,后面觉得配置形式的好用一点,就是每次需要重新改。

生成controller

我这里随机用一个来展示,代码有点多,主要就是来展示一下,大概的一个实现,本质上其实就是模版 + 配置的动态数据

const {author,moduleName,moduleEName,moduleDescription,date,groupName,parentMenu} = opts;const listAnnotationStr = generateSwaggerApiStr({ ...opts, type: 'list' });const detailAnnotationStr = generateSwaggerApiStr({...opts,type: 'detail'});const pageAnnotationStr = generateSwaggerApiStr({ ...opts, type: 'page' });const addAnnotationStr = generateSwaggerApiStr({ ...opts, type: 'add' });const editAnnotationStr = generateSwaggerApiStr({ ...opts, type: 'edit' });const deleteAnnotationStr = generateSwaggerApiStr({...opts,type: 'delete'});const exportAnnotationStr = generateSwaggerApiStr({...opts,type: 'export'});const controllerStr = `/**
* @description ${moduleDescription}
* @controller ${moduleName}管理 ${moduleName}管理 ${groupName ? groupName : ''}
* @author ${author}
* @date : ${date}
*/`;const upperCaseModuleEname = capitalizeFirstLetter(moduleEName);const parentModuleGroupStr = parentMenu ? `${parentMenu}.${moduleEName}` : moduleEName;const content = `
const Controller = ${parentMenu ? "require('../../core/baseController')" : "require('../core/baseController')"};${controllerStr}
class ${moduleEName}Controller extends Controller {${listAnnotationStr}async list() {const { ctx, service } = this;ctx.body = await service.${parentModuleGroupStr}.find${upperCaseModuleEname}List();}${detailAnnotationStr}async detail() {const { ctx, service } = this;const {id} = ctx.params;ctx.body = await service.${parentModuleGroupStr}.find${upperCaseModuleEname}Detail(id);}${pageAnnotationStr}async page(){const { ctx, service } = this;const opts = ctx.params;ctx.body = await service.${parentModuleGroupStr}.find${upperCaseModuleEname}Page(opts);}${addAnnotationStr}async create() {const { ctx, service } = this;await service.${parentModuleGroupStr}.add${upperCaseModuleEname}(ctx.request.body);}${editAnnotationStr}async update() {const { ctx, service } = this;await service.${parentModuleGroupStr}.edit${upperCaseModuleEname}(ctx.request.body);}${deleteAnnotationStr}async destroy() {const { ctx, service } = this;ctx.validate({ ids: 'string' }, ctx.request.query);await service.${parentModuleGroupStr}.delete${upperCaseModuleEname}(ctx.request.query.ids);}${exportAnnotationStr}async export() {await this.exportExcel('${parentModuleGroupStr}', 'export${upperCaseModuleEname}', '${moduleName}');}
}
module.exports = ${moduleEName}Controller;

最终效果

运行这个index,在控制台可以进行输入,输入完成回车

在这里插入图片描述

最后根据配置生成的一个结果

在这里插入图片描述

可以直接进入引入,引入到自己项目中,重新编译就可以看到一个效果

可拓展

我目前这个代码生成器还有可拓展的空间

  • 比如关于一些字段的配置,我这里最好可以传递一个数组,然后在后台进行接收,数组里面包含每一个属性对象,属性对象里面有各种属性来区分这些字段是否要展示,是否要加入查询,是否要加入添加,是否要加入编辑,等等
  • 我这个代码生成器可以做成可视化的形式,把配置文件通过在前端界面进行配置,配置完成之后生成文件出来,通过浏览器去下载对应的资源压缩包,然后一键导入到项目中
  • 等之后有时间我会去做一个可视化的代码生成器的版本,功能更加细致,更加方便快捷进行开发

结语

每天进步一点点,每天进行学习以及进行技术分享,加油,只要一直坚持总能越来越好

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/861370.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

web前端——VUE

1.什么是框架? ①概述 框架结构就是基本功能,把很多基础功能已经实现了、封装了。在基础语言之上,对各种基础功能进行封装,方便开发者,提高开发效率 ②前端框架 javaScript是原生的 vue.js: 是一个js框架&…

最新解决docker镜像无法下载问题

1.增加或修改daemon.json文件 ​ cd /etc/dockervi daemon.json{ "registry-mirrors": [ "https://docker.m.daocloud.io" ] }2.重启docker服务 sudo systemctl daemon-reload sudo systemctl restart docker 3.验证 下载https://txodoo.cn/blog/11/d…

双指针dd d df f

像二分这样的算法,我们甚至可以不用管,直接在问题空间之内搜索,但是双指针也非常好用,帮助我们来减少枚举对象,我们来总结一下这经典的三个题目: 最长上升不重复子序列活动 - AcWings 首先一定要写…

LabVIEW电路板故障诊断系统

基于LabVIEW软件开发的电路板故障诊断系统,涵盖功能测试、性能测试和通讯测试等多个方面。系统集成了多种硬件设备,包括NI PXI-1033机箱、NI PXI-4071数字万用表、NI PXI-4130电源模块、NI PXI-8512 CAN模块等,通过模块化设计实现了对电路板的…

shell中的函数

统计家目录下.c文件的个数 终端输入一个.sh文件,判断文件是否由可执行权限,如果有可执行权限运行脚本,没有可执行权限添加可执行权限后,再运行脚本 写一个函数,输出当前用户uid和gid,并使用变量接收结果 终…

【LLM Transparency Tool】用于深入分析和理解大型语言模型(LLM)工作原理的工具

背景 LLM Transparency Tool 是一个用于深入分析和理解大型语言模型(LLM)工作原理的工具,旨在增加这些复杂系统的透明度。它提供了一个交互式界面,用户可以通过它观察、分析模型对特定输入(prompts)的反应…

加速科技Flash存储测试解决方案 全面保障数据存储可靠性

Flash存储芯片 现代电子设备的核心数据存储守护者 Flash存储芯片是一种关键的非易失性存储器,作为现代电子设备中不可或缺的核心组件,承载着数据的存取重任。这种小巧而强大的芯片,以其低功耗、可靠性、高速的读写能力和巨大的存储容量&…

OpenGL-ES 学习(6)---- 立方体绘制

目录 立方体绘制基本原理立方体的顶点坐标和绘制顺序立方体颜色和着色器实现效果和参考代码 立方体绘制基本原理 一个立方体是由8个顶点组成,共6个面,所以绘制立方体本质上就是绘制这6个面共12个三角形 顶点的坐标体系如下图所示,三维坐标…

【目标检测】Yolov8 完整教程 | 检测 | 计算机视觉

学习资源:https://www.youtube.com/watch?vZ-65nqxUdl4 努力的小巴掌 记录计算机视觉学习道路上的所思所得。 1、准备图片images 收集数据网站:OPEN IMAGES 2、准备标签labels 网站:CVAT 有点是:支持直接导出yolo格式的标…

搜索引擎的妙用:掌握这些技巧,让你的搜索更高效!

搜索引擎是我们日常生活中不可或缺的工具,它帮助我们快速找到所需的信息。但是,你真的知道如何高效地使用搜索引擎吗?下面,我将分享一些高级搜索技巧,让你的搜索更加精准和高效。 1. 完全匹配搜索 当你想要搜索一个特…

第三十三篇——互联网广告:为什么Google搜索的广告效果好?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么? 四、总结五、升华 一、背景介绍 对于信息的利用,再广告这个维度中去洞察,你又能发…

光伏储能为什么变得那么受欢迎?

在当今这个追求可持续发展和清洁能源的时代,光伏储能技术逐渐崭露头角,并成为了能源领域的热门话题。其受欢迎程度不断攀升,背后有着多方面的原因。光伏储能技术的优点众多,涵盖了多个方面,以下是关于其安全、寿命等关…

【BUG记录】条件查询没有查询结果 || MybatisPlus打印查询语句

结论 先说结论,查询没有结果,可能是数据库连接,数据问题之类,最有可能的根本原因是查询语句问题,需要想办法检查查询语句,使用mybatisPlus等自动生成查询语句的框架不能直接看语句,可以依靠日志…

Python低溫半导体电子束量子波算法计算

🎯要点 🎯任意维度求解器,绘制三维投影结果 | 🎯解二维静电场、静磁场 | 🎯狄利克雷、诺依曼条件几何矩阵算子 | 🎯算法模拟低溫半导体材料 | 🎯计算曲面达西流 | 🎯电子结构计算和…

洗地机哪一款好用?家用洗地机推荐

洗地机是家庭必备的高效深度清洁机器,对于家庭用户而言,它可以自动吸尘、拖洗、自清洁,使用便捷高效,为众多家庭用户所欢迎。但市场上的洗地机品牌众多,很多消费者陷入了购买陷阱,为了帮助广大用户选购到合…

解决SD卡被写保护问题

存储卡在使用过程中,有时会遇到写保护问题,导致无法写入或删除数据。这可能会对用户的正常使用造成困扰。MK米客方德将为您介绍几种常见的解决方法,帮助用户解除存储卡的写保护。 一、检查物理写保护开关 许多存储卡,如SD卡&…

若依 ruoyi 显示隐藏搜索框 显示隐藏列

一、 显示隐藏搜索框 页面搜索关键字 showSearch,设置是否显示 隐藏: 显示: 二、自定义设置 显示隐藏列 1. 页面搜索关键字 right-toolbar,新增: :columns"columns" 2. js下 data(){return{}}中新增&am…

【MySQL事务】深刻理解事务隔离以及MVCC

文章目录 什么叫事务事务的提交方式常见的事务操作方式事务的开始与回滚总结 事务的隔离设置隔离级别解释脏读解释幻读解释不可重复读为什么可重复读不能解决幻读问题?总结 数据库并发的场景MVCC隐藏列字段undo日志Read view RR和RC的本质区别总结 什么叫事务 在My…

人工智能类SCI,1区TOP,3个月可录!

今天给大家推荐一本人工智能类SCIE领域的SCI,此期刊为我处目前合作的重点期刊!影响因子7.0-8.0之间,JCR1区,中科院2/1区(TOP),最重要的是审稿周期较短,对急投的学者较为友好&#xf…

搜索引擎的原理与相关知识

搜索引擎是一种网络服务,它通过互联网帮助用户找到所需的信息。搜索引擎的工作原理主要包括以下几个步骤: 网络爬虫(Web Crawler):搜索引擎使用网络爬虫(也称为蜘蛛或机器人)来遍历互联网&#…