从零实现一套低代码(保姆级教程)【后端服务】 --- 【1】初始化后端项目

摘要

在前面的实现过程中,我们的低代码平台,在前端已经有一定的构建页面的能力了。

在专栏中 从零实现一套代码 ,介绍了前端部分的实现。

但是对于我们实现的平台,肯定要支持用户对页面进行保存等功能,包括后面我们运行时的设计,都要依赖于后端的能力。

所以,现在我们需要考虑开始使用数据存储了。那因为博主平时的工作主要都是前端开发,所以后端框架选择了比较贴合前端的Nest.js

我们低代码来讲,通常是对协议的保存以及修改,所以我们的数据库使用MongoDB,当然,如果读者有一定的后端开发经验,可以自行选择后端框架和数据库。

当然,选择这一些列文章看的主要可能是前端开发,所以实现后端内容的这一部分我会写的比较详细。(虽然博主的后端知识也比较匮乏,如果有问题欢迎指正)。

1.初始化Nest项目

我们来到Nest.js的中文文档: nestjs.bootcss.com/controllers...

当然,这里面很多也没有翻译,读者有兴趣可以看看,主要还是跟着我的节奏来吧。。。 首先是安装nest和创建项目。

javascript 复制代码
$ npm i -g @nestjs/cli
$ nest new XinBuilderServer2

创建好之后,我们来到对应的目录下面,启动

javascript 复制代码
npm run start

就可以在页面里看到Hello Word了,默认的端口号是3000, 如果想要修改的话可以在main.ts中进行修改。

现在我们来思考一下,我们要这个后端服务第一步需要干什么。对于协议,我希望我能将它保存在数据库里。

这里要理解什么是协议,就是我低代码平台中,左侧的数据,也是redux中保存的数组。

所以我们需要一个接口,用来对协议的保存和更新。

每当你选择新建一个功能模块的时候,比如现在我想有一个和存储协议相关的接口功能。 需要再控制台中输入以下命令:

javascript 复制代码
nest g mo -p src pageJson  
nest g co -p src pageJson  
nest g service -p src pageJson

这三行命令是什么意思呢?就是说,在Nest中,新建一个Module + Controller + Service。这个时候你就会发现你的目录下新增了几个文件:

当然这几个名词,你也可以先不用知道什么意思(博主也只是大概理解)。后面会告诉你怎么去写。

你也可以手动添加。只不过费事一点而已。

2.引入MongoDB

有了后端服务之后,我们就要安装数据库了,数据库的话我们就选择MongoDB,读者可以到官网下载自己需要的安装包。

最好还是找一个教程,这里安装数据库的过程就不细写了,当你安装完后启动了,再回到项目里面。

我们需要一个库去操作数据库,在这里我们使用mongoose来操作数据库。安装的话只需要:

javascript 复制代码
npm i mongoose
npm i @nestjs/mongoose

一切准备就绪之后,我们来到项目中:
xin-builder-server2\src\app.controller.ts

我们在入口的app中,引入MongoDB:

javascript 复制代码
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 {}

切记切记,虽然上面只有短短的几句话,但是这一个过程还是比较让人烦躁的。因为在安装过程中,不确定会出现什么问题。

总之,我们的目的就是能在我们的项目中,可以和数据库建立联系。

3.实现获取页面列表的接口

对于一个模型来说,接口的主要工作就是增删改查,我们先写一个获取页面列表的接口。

那对于一个页面来讲,我们暂且只需要一个pageId和pageJson,分别代表页面的唯一表示和页面的JSON结构。 页面的展示还需要一个pageName作为页面名称。

在pageJson目录下新增一个page-json.interface.ts文件和pageJson.schema.ts文件,用来定义页面的结构:

xin-builder-server2\src\page-json\pageJson.schema.ts

javascript 复制代码
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

javascript 复制代码
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应该这么写:

javascript 复制代码
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>) {}
}

有了基础准备之后,我们开始实现获取页面列表的接口:

javascript 复制代码
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

javascript 复制代码
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文件:

javascript 复制代码
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,现在我们需要一个方式去验证一下了:

4.实现swagger接口文档

一般我们调试接口,都是使用postMan之类的可视化工具,在Nest中,可以直接使用swagger接口文档,我们继续安装:

javascript 复制代码
ynpm i @nestjs/swagger

安装完成后我们在main.ts中将其引入:

javascript 复制代码
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就是这个接口的描述

javascript 复制代码
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上:
github.com/TeacherXin/...
commit: 初始化后端服务

如果有后端大佬,欢迎提出建议和修改。o.O

相关推荐
低代码布道师1 天前
低代码实战训练营教学大纲 (10天)
低代码
NocoBase1 天前
为什么越来越多 Airtable 用户开始尝试 NocoBase?
低代码·开源·资讯
SailingCoder1 天前
MongoDB Memory Server与完整的MongoDB的主要区别
数据库·mongodb
水木石画室1 天前
MongoDB 常用增删改查方法及示例
数据库·mongodb
旷世奇才李先生1 天前
MongoDB 安装使用教程
数据库·mongodb
qq_339282231 天前
mongodb 中dbs 时,local代表的是什么
数据库·mongodb
Accpdaiyekun1 天前
C# 操作mongodb 多次查询快还是使用管道查询速度快
mongodb·c#·lua
NocoBase11 天前
Airtable 的数据超出上限,3 种常见应对方式
低代码·开源·资讯
踩着两条虫11 天前
AI + 低代码 技术揭秘(十八):集成指南
低代码·ai编程
五_谷_丰_登11 天前
mongoDB服务本地化部署
数据库·c++·qt·mongodb