龙空技术网

从0搭建一个内部mock工具(支持sql转换,自带增删改查)

Java机械师 96

前言:

现时朋友们对“虚拟sql数据库操作”大约比较关怀,小伙伴们都需要剖析一些“虚拟sql数据库操作”的相关知识。那么小编也在网络上收集了一些有关“虚拟sql数据库操作””的相关知识,希望大家能喜欢,各位老铁们一起来学习一下吧!

一. 前言

作为程序员的我们,通常避免不了对需求任务的追赶。

而作为切图仔的我们,作为开发最后提测前最后一环的我们,对无法准时提测,有时候可能存在一些委屈,相信肯定遇到接口不及时而导致页面进度延期的情况。

此外,在日常迭代的规律性的迭代,前端很容易出现一种形象,就是出现"区间性"忙碌。你说非常忙,把工作日平摊下来,实际上也没多少产出,但就是在最后时刻特别忙碌。给人的一种感觉就是,联调前,没事做;联调后,事太多。

如果,有一款能生成虚拟的联调数据,是能分担任务的比重的。而前端mock就是在这种背景中产生。

二. mock的意义

说完mock存在的背景,这里再分析一下mock的意义。

1) 草图

如何解决前端任务不聚焦的问题,笔者这里简单梳理了一个草稿图:

2) 分析

上图已经列出,我们面对的问题:

1.当前只有业务逻辑(表结构),无法生成对应接口2.模拟数据成本高,无法快速生成3.有数据了,也无法进行真实增删改查

根据如上,笔者认为一个好用的mock工具,我觉得应该保证下边的功能:

1.能自定义我们的数据格式,返回对应的数据结构以及相关的字段等。2.能快速自定义我们的数据源。3.能快速生成增删改查的接口,模拟真实数据的运转,否则就失去了意义4.如果能根据表结构直接生成,那就更完美

当然,博客上,也有好多博主有自己的见解,有些东西我觉得可以非必要追求:

1.过于追求数据结构。假设没有技术评审,还未确认表结构,我们设计一个差不多就可以。这玩意再怎么优秀,都只是“模拟”数据而已,你永远猜不中后端最终给你的格式。2.实现复杂的逻辑。越复杂的逻辑,也表示花费的时间越多。只要接口有了,也意味着这玩意作废。所以,不适宜投入太高的成本。

这里也有几个前置条件:

BFF接口设计规范,我们知道对应的接口设计规范。对应业务的表结构3) 结论

综上分析,我们需要一款,配置"简单"且能"快速"生成一个增删改查的mock工具。而"简单"与"快速",是mock的核心。

三. 市场的常用方案

此时我们已经有了需求,再来看看市场的解决方案。一起看看,市场是怎么设计这些mock工具的,或者是有什么解决方案。

1)手动虚拟数据

该方案,直接在代码中写死 Mock 数据,或者请求本地的 JSON 文件。相信也是日常大家使用最多的方案。

优势:

上手快,无需学习成本。

劣势:

做数据比较麻烦。无法自动生成增删改查等。会使项目太多冗余数据,解藕也较难。2)接口管理工具

这里以swagger为例,相信后端是java的切图仔都看过这玩意。

优势:

自带接口规范。配置功能强大。根据后端接口生成。

劣势:

资源问题:毕竟是后端项目,启动一个后端项目也麻烦。还耗后端资源。人员问题:让后端帮忙处理,后端还不如直接加紧赶出接口给出来。配置问题:强大也意外着,学习成本高。熟悉一些配置相关的成本也不低。3)node服务器

结合上边,如果说使用一个java后端比较麻烦,那么启动一个Node服务器的话呢?

常见的有我们的koa,或者是express框架等等。

优势:

前端学习成本相对较低,毕竟都是js

劣势:

增删改查,还是需要手动写4)MOCKJS

优势:

可随机生成所需数据,可模拟对数据的增删改查

劣势:

可以实现增删改查, 数据源的确比较灵活,支持随机数,正则等,但是模拟数据麻烦一些。5)抓包工具

代表作Fiddler

优势:

脱离程序本身,可以直接映射,修改数据源。

劣势:

调试相对繁琐。定位并不是mock开发阶段,更适合偶尔模拟数据定位问题。

四.手动搭建自己的mock

介绍自己的Cb mock:

1)功能介绍能快速自定义我们的数据格式,能快速生成增删改查接口支持三种模式,自定义模式,json模式,sql模式支持接口校验,如必填,长度等校验能自定义返回接口格式,统一数据格式规范,项目也支持自定义规范与项目本身脱离解耦,可快速替换真实链接支持生成api文档说明2)核心技术栈/源码koa

启动koa服务,作为服务提供者,代码如下:

const Koa = require('koa')const app = new Koa();app.use(json())app.use(logger())app.use(koaBody());app.use(bodyParser({    enableTypes: ['json', 'form', 'text'],    multipart: true}));复制代码
2. mockjs

返回mock数据:

 const { mock } = require("mockjs"); ctx.body = Result.info(mock(Object.assign(defaultResult, result)));复制代码
3.commander指令

如启动commander指令:

const program = require('commander')program  .command("startMock")  .description("启动mock服务")  .action((appName, options) => {    startMock()  })复制代码
4. 正则sql转换

利用正则切割sql:

const nameMatch = line.match(' `(.*)`');const maxLengthMatch = line.match(' varchar\\((.*)\\) ');const defaultMatch = line.match(' DEFAULT \'(.*)\' ');const commentMatch = line.match(' COMMENT \'(.*)\',');const typePattern = / (?:\w+)(.*?) /;const typeMatch = line.match(typePattern, "$0");const requiredReg = /NOT NULL/.test(line);        const key = nameMatch[1];const maxLength = maxLengthMatch && maxLengthMatch.length > 0 ? Number(maxLengthMatch[1]) : undefined;const required = !requiredReg;const defaultValue = defaultMatch && defaultMatch.length > 0 ? defaultMatch[1] : undefined;const comment = commentMatch && commentMatch.length > 0 ? commentMatch[1] : undefined;const typeDb = typeMatch && typeMatch.length > 0 ? typeMatch[0] : [];复制代码
5. fs生成文档

利用fs生成文档文件:

    // 生成文档        const generateDoc = (table, port) => {            let str = '';            Object.keys(table).forEach(key => {                str += `## ${key}模块    |  参数名称  |  参数说明  |  数据类型  |  长度(字节)  |  是否必填  |  默认值  |     |  -------  |  -------  |  ------  |  -----  |  -------  |  ---------  |        `        const { column } = table[key]        column.forEach(item => {            const name = item.key;            const type = item.type;            const comment = item.comment ? item.comment : '-';            const defaultValue = item.default ? item.default : '-';            const isRequired = item.required ? "是" : "否"            const maxLength = item.maxLength ? item.maxLength : "-"            str += `| ${name} | ${comment} | ${type} | ${maxLength} | ${isRequired} | ${defaultValue} |\n`        })        // 获取接口名称        const apiList = getApiList(key);        for (let i = 0; i < apiList.length; i++) {            const { url, name, type } = apiList[i]            str += `###  http:/${url}    接口说明:${name}    请求类型: ${type}                \n`        }    })复制代码
五.使用配置1)安装本地
git clone  installnpm link复制代码
2)配置mock.config.js
module.exports = {    common: {//支持公用配置        port: 8000,        timeout: 0,        rate: 1,    },    sqlDataSource: [//支持sql数据源        `      CREATE TABLE \`jsh_depot\` (        \`id\` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',        \`name\` varchar(20) DEFAULT NULL COMMENT '仓库名称',        \`address\` varchar(50) DEFAULT NULL COMMENT '仓库地址',        \`warehousing\` decimal(24,6) DEFAULT NULL COMMENT '仓储费',        \`truckage\` decimal(24,6) DEFAULT NULL COMMENT '搬运费',        \`type\` int DEFAULT NULL COMMENT '类型',        \`sort\` varchar(10) DEFAULT NULL COMMENT '排序',        \`remark\` varchar(100) DEFAULT NULL COMMENT '描述',        \`principal\` bigint DEFAULT NULL COMMENT '负责人',        \`tenant_id\` bigint DEFAULT NULL COMMENT '租户id',        \`delete_Flag\` varchar(1) DEFAULT '0' COMMENT '删除标记,0未删除,1删除',        \`is_default\` bit(1) DEFAULT NULL COMMENT '是否默认',        PRIMARY KEY (\`id\`)      ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb3 COMMENT='仓库表';      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (14,'仓库1','dizhi','12.000000','12.000000',0,'1','描述',131,63,'0','');      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (15,'仓库2','地址100','555.000000','666.000000',0,'2','dfdf',131,63,'0','\0');      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (17,'仓库3','123123','123.000000','123.000000',0,'3','123',131,63,'0','\0');      CREATE TABLE \`jsh_depot22\` (        \`id\` bigint NOT NULL AUTO_INCREMENT COMMENT '主键',        \`name\` varchar(20) DEFAULT NULL COMMENT '仓库名称',        \`address\` varchar(50) DEFAULT NULL COMMENT '仓库地址',        \`warehousing\` decimal(24,6) DEFAULT NULL COMMENT '仓储费',        \`truckage\` decimal(24,6) DEFAULT NULL COMMENT '搬运费',        \`type\` int DEFAULT NULL COMMENT '类型',        \`sort\` varchar(10) DEFAULT NULL COMMENT '排序',        \`remark\` varchar(100) DEFAULT NULL COMMENT '描述',        \`principal\` bigint DEFAULT NULL COMMENT '负责人',        \`tenant_id\` bigint DEFAULT NULL COMMENT '租户id',        \`delete_Flag\` varchar(1) DEFAULT '0' COMMENT '删除标记,0未删除,1删除',        \`is_default\` bit(1) DEFAULT NULL COMMENT '是否默认',        PRIMARY KEY (\`id\`)      ) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8mb3 COMMENT='仓库表';      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (14,'仓库1','dizhi','12.000000','12.000000',0,'1','描述',131,63,'0','');      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (15,'仓库2','地址100','555.000000','666.000000',0,'2','dfdf',131,63,'0','\0');      insert  into \`jsh_depot\`(\`id\`,\`name\`,\`address\`,\`warehousing\`,\`truckage\`,\`type\`,\`sort\`,\`remark\`,\`principal\`,\`tenant_id\`,\`delete_Flag\`,\`is_default\`) values (17,'仓库3','123123','123.000000','123.000000',0,'3','123',131,63,'0','\0');      `    ],    jsonDataSource: [//支持json数据源        {            account_detail: {                column: [                    "id",                    { key: 'username', required: true },                    "auth_key",                    "password_hash",                    "password_reset_token",                    "email",                    "created_at",                ],                dataSource: [                    {                        "id": 13,                        "email": "368938"                    },                    [14, 45457]                ],            },        },    ],    customDataSource: [[//支持自定义数据源        {            url: "/login",            returnFn: (req) => {                const { name, password } = req.query;                if (name === 'admin' || password === 'a123456') {                    return { status: 1, msg: "登录成功" }                }                return { status: 0, msg: "账号或密码错误" }            }        },        {            url: "/addUser",            type: "post",            returnFn: (req) => {                const { name } = req.request.body;                if (name !== '' && name !== undefined) {                    return { status: 1, msg: "新增账号成功" }                }                return { status: 0, msg: "请输入用户名" }            }        },    ]};复制代码
3)启动服务
cb startMock复制代码
4)启动结果

会生成mock.md接口文档说明:

五.源码

github.com/zhuangweizh…

六.结语

时间仓促,一些功能未完善。分享一下未来计划:

支持sql的left join生成完成文档的生成欢迎反馈bug

标签: #虚拟sql数据库操作