在前面的实现过程中,我们的低代码平台,在前端已经有一定的构建页面的能力了。
但是对于我们实现一个平台,肯定要支持用户对页面进行保存等功能,包括后面我们运行时的设计,都要依赖于后端的能力
所以,现在我们需要考虑开始使用数据存储了。那因为博主平时的工作主要都是前端开发,所以后端框架选择了比较贴合前端的Nest.js。
我们低代码来讲,通常是对协议的保存以及修改,所以我们的数据库使用MongoDB,当然,如果读者有一定的后端开发经验,可以自行选择后端框架和数据库。
当然,选择这一些列文章看的主要可能是前端开发,所以实现后端内容的这一部分我会写的比较详细。(虽然博主的后端知识也比较匮乏,如果有问题欢迎指正)。
我们来到Nest.js的中文文档:
https://nestjs.bootcss.com/controllers.html
当然,这里面很多也没有翻译,读者有兴趣可以看看,主要还是跟着我的节奏来吧。。。
首先是安装nest和创建项目。
$ npm i -g @nestjs/cli
$ nest new XinBuilderServer2
创建好之后,我们来到对应的目录下面,启动
npm run start
就可以在页面里看到Hello Word了,默认的端口号是3000, 如果想要修改的话可以在main.ts中进行修改。
现在我们来思考一下,我们要这个后端服务第一步需要干什么。对于协议,我希望我能将它保存在数据库里。
所以我们需要一个接口,用来对协议的保存和更新。
每当你选择新建一个功能模块的时候,比如现在我想有一个和存储协议相关的接口功能。
需要再控制台中输入以下命令:
nest g mo -p src pageJson
nest g co -p src pageJson
nest g service -p src pageJson
这三行命令是什么意思呢?就是说,在Nest中,新建一个Module + Controller + Service。这个时候你就会发现你的目录下新增了几个文件:
当然这几个名词,你也可以先不用知道什么意思(博主也知识大概理解)。后面会告诉你怎么去写。
你也可以手动添加。只不过费事一点而已。
有了后端服务之后,我们就要安装数据库了,数据库的话我们就选择MongoDB,读者可以到官网下载自己需要的安装包。
最好还是找一个教程,这里安装数据库的过程就不细写了,当你安装完后启动了,再回到项目里面。
我们需要一个库去操作数据库,在这里我们使用mongoose来操作数据库。安装的话只需要:
npm i mongoose
npm i @nestjs/mongoose
一切准备就绪之后,我们来到项目中:
xin-builder-server2\src\app.controller.ts
我们在入口的app中,引入MongoDB:
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { PageJsonModule } from './page-json/page-json.module';
import { MongooseModule } from '@nestjs/mongoose';
const DBRootModule = MongooseModule.forRoot('mongodb://127.0.0.1/localData');
@Module({
imports: [DBRootModule, PageJsonModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
切记切记,虽然上面只有短短的几句话,但是这一个过程还是比较让人烦躁的。因为在安装过程中,不确定会出现什么问题。
总之,我们的目的就是能在我们的项目中,可以和数据库建立联系。
对于一个模型来说,接口的工作就是增删改查,我们先写一个获取页面列表的接口。
那对于一个页面来讲,我们暂且只需要一个pageId和pageJson,分别代表页面的唯一表示和页面的JSON结构。
页面的展示还需要一个pageName作为页面名称。
在pageJson目录下新增一个page-json.interface.ts文件和pageJson.schema.ts文件,用来定义页面的结构:
xin-builder-server2\src\page-json\pageJson.schema.ts
import { Schema } from 'mongoose';
export const pageJsonSchema = new Schema({
pageId: { type: String, required: true },
pageName: { type: String, required: true },
pageJson: { type: Object, required: true }
});
xin-builder-server2\src\page-json\page-json.interface.ts
import { Document } from 'mongoose';
export interface PageJson extends Document {
readonly pageId: string;
readonly pageJson: Object;
}
接下来我们到service中:
xin-builder-server2\src\page-json\page-json.service.ts
一个正常的service应该这么写:
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { PageJson } from './page-json.interface';
@Injectable()
export class PageJsonService {
constructor(@InjectModel('PageJson') private readonly pageJsonModel: Model<PageJson>) {}
}
有了基础准备之后,我们开始实现获取页面列表的接口:
import { Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { PageJson } from './page-json.interface';
@Injectable()
export class PageJsonService {
constructor(@InjectModel('PageJson') private readonly pageJsonModel: Model<PageJson>) {}
async findAllPage(): Promise<PageJson []>{
return await this.pageJsonModel.find({})
}
}
pageJsonModel.find()的参数就是对应的查询条件,也就是sql语句的封装。如果我传一个空对象,那么就是全量查询。
现在我们来到page-json.controller.ts中:
xin-builder-server2\src\page-json\page-json.controller.ts
import { Controller, Post } from '@nestjs/common';
import { PageJson } from './page-json.interface';
import { PageJsonService } from './page-json.service'
interface PageJsonResponse<T = unknown> {
code: number;
data?: T;
message: string;
}
@Controller('page-json')
export class PageJsonController {
constructor(private readonly PageService: PageJsonService) {}
@Post('findAllPage')
async findAllPage(): Promise<PageJsonResponse<PageJson[]>> {
return {
code: 200,
data: await this.PageService.findAllPage(),
message: 'Success.',
};
}
}
在这里我们就相当于通过调用service中的方法,去实现一个接口控制器。
最后我们修改一下page-json.module文件:
import { Module } from '@nestjs/common';
import { PageJsonController } from './page-json.controller';
import { PageJsonService } from './page-json.service';
import { MongooseModule } from '@nestjs/mongoose';
import { pageJsonSchema } from './pageJson.schema'
const pageJsonSchemaTable = MongooseModule.forFeature([{ name: 'PageJson', schema: pageJsonSchema }]);
@Module({
imports: [pageJsonSchemaTable],
controllers: [PageJsonController],
providers: [PageJsonService]
})
export class PageJsonModule {}
OK,现在我们需要一个方式去验证一下了:
一般我们调试接口,都是使用postMan之类的可视化工具,在Nest中,可以直接使用swagger接口文档,我们继续安装:
ynpm i @nestjs/swagger
安装完成后我们在main.ts中将其引入:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const options = new DocumentBuilder()
.setTitle('API example')
.build()
const document = SwaggerModule.createDocument(app, options)
SwaggerModule.setup('api', app, document)
await app.listen(4000);
}
bootstrap();
安装好之后,我们修改一下page-json.controller里的接口:
ApiTags就是这个模块的描述,ApiOperation就是这个接口的描述
import { Controller, Post } from '@nestjs/common';
import { PageJson } from './page-json.interface';
import { PageJsonService } from './page-json.service'
import { ApiTags, ApiOperation } from '@nestjs/swagger'
interface PageJsonResponse<T = unknown> {
code: number;
data?: T;
message: string;
}
@ApiTags('页面管理')
@Controller('page-json')
export class PageJsonController {
constructor(private readonly PageService: PageJsonService) {}
@Post('findAllPage')
@ApiOperation({summary: '查询页面列表'})
async findAllPage(): Promise<PageJsonResponse<PageJson[]>> {
return {
code: 200,
data: await this.PageService.findAllPage(),
message: 'Success.',
};
}
}
这时候,我们可以通过localhost:3000/api
打开对应的接口文档页面:
当你点击Exute之后,应该是一个空数组,因为你的数据库中并没有数据。
OK,这一篇文章就不继续往下实现了,主要就是能将整体的安装过程以及配置过程串通。
只有这一步搞定了,我们才可以做后面的事情。
相关的代码提交在github上:
https://github.com/TeacherXin/XinBuilderServer2
commit: 初始化后端服务