公司低代码项目接口用NestJS重写完整闭环落地

背景

公司低代码平台目前支持的功能有配置管理后台的列表页面、表单、图表等,而且支持在配置出的页面上增加各种钩子函数,完成自定义开发需求,基本满足常规管理后台的需求。

目前做法是设计器保存大JSON字符串到后端一个字段存起来,后端也只使用到一个单表,基本就是单表CRUD提供给前端而已(还有一个大部分是和流程那边相关的,这块先不动)。

我考虑的是把这块CRUD的接口从后端java程序改为前端NestJS,数据库用sqllite,这样后端就完全不用管整个低代码设计了,后续增加需求前端自己搞就行了。

思路

大概要做这么几件事:

  • 梳理要迁移的接口并NestJS实现
  • 统一鉴权处理并NestJS实现,因为接口token需要鉴权
  • sqllite设计根据字段设计表结构
  • Dockerfile改造支持pm2跑nodejs服务
  • 旧数据从mysql迁移到sqlite
  • Jenkins和流水线新增配置

项目里面搜索了下,总共6个接口,整理出来是需要去重写的,再需要考虑鉴权问题

bash 复制代码
post /online/desform/page
post /online/desform/add
post /online/desform/edit
delete /online/desform/delete
get /online/desform/detail
get /online/desform/detailKey

NestJS 项目配置

初始化项目

css 复制代码
npm i -g @nestjs/cli
nest new [项目名]
npm run start:dev // 运行开发模式,看到 http://localhost:3000 页面正常

启用CORS跨域

一般我在nginx里面统一做跨域,这里我就在代码main.js里支持

javascript 复制代码
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as bodyParser from 'body-parser';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  // 防止 报错 request entity too large
  app.use(bodyParser.json({ limit: '50mb' }));
  app.use(bodyParser.urlencoded({ limit: '50mb', extended: true }));
  // 启用CORS
  app.enableCors();
  await app.listen(3000);
}
bootstrap();

解决 Delete eslint

VSCODE很多eslint的报错提示,原因是windows的文件结尾是CRLF,linux的文件结尾是LF。

eslint就提示报错了,解决方法很多。我们直接把修改 .eslintrc.js 不提示报错就行,在 rules 添加如下规则

arduino 复制代码
'prettier/prettier': ['error',
      {
        endOfLine: 'auto', //不让prettier检测文件每行结束的格式
      },
],

sqllite3安装

bash 复制代码
npm install @nestjs/typeorm typeorm sqlite3

正式创建接口

创建模块资源文件

arduino 复制代码
nest g resource desform  // 快速创建CRUD相关文件,选RestApi即可,desform是模块名称

自动创建了如下dto\entiryes\controller\module\service文件

修改 create-desform.dto.ts

这个类是http请求时,请求参数映射的实体,修改完 create-desform.dto.ts,同理 update-desform.dto.ts也可同样修改,如果感觉麻烦,后面都用同一个也行

typescript 复制代码
export class CreateDesformDto {
  alias: string;
  formContent: string;
  formName: string;
  id: number;
  formType: number;
}

修改 desform.entity.ts

这个是 对应数据库的字段映射,这里保存文件后,会自动生成sqllite的表结构,而且 entity.ts 文件属性更改,也会自动更新数据库的表结构

这里我考虑formContent字段是很大字符串字段,我查了说sqllite varchar字段类型是无限大小的,大概可以存2G的内容,那够用了

less 复制代码
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Desform {
  @PrimaryGeneratedColumn()
  id: number;       // id自增长
  @Column({ nullable: true }) 
  alias: string;   // 可为null
  @Column()                   
  formContent: string; // 必填
  @Column()
  formName: string;    // 必填
  @Column({ default: 1 })
  formType: number;   // 默认值1
}

修改 desform.module.ts

主要是增加imports内容,导入对象映射

python 复制代码
import { Module } from '@nestjs/common';
import { DesformService } from './desform.service';
import { DesformController } from './desform.controller';
import { Desform } from './entities/desform.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forFeature([Desform])], // 增加 imports 内容
  controllers: [DesformController],
  providers: [DesformService],
})
export class DesformModule {}

修改 desform.service.ts

主要是添加constructor内容,而且在create中调用save方法,就保存数据成功

typescript 复制代码
import { Injectable } from '@nestjs/common';
import { CreateDesformDto } from './dto/create-desform.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Desform } from './entities/desform.entity';
import { Repository } from 'typeorm';

@Injectable()
export class DesformService {
  constructor(
    @InjectRepository(Desform) private desformRepository: Repository<Desform>,
  ) {}

  create(createDesformDto: CreateDesformDto) {
    return this.desformRepository.save(createDesformDto);
  }
}

修改 app.module.ts

主要是增加 sqllite 配置,导入引用模型

这里特别注意 synchronize: true,这里会自动同步enity.ts中数据结构到sqllite表结构里面

typescript 复制代码
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { DesformModule } from './desform/desform.module';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'sqlite',
      database: 'jeecgdb.db',
      autoLoadEntities: true, // 自动加载实体,也就是数据库表和 TypeScript 的映射类。
      synchronize: true, // 设置为 true 后,项目启动的时候会根据实体的配置,自动创建 sqlite3 的数据库表。
    }),
    DesformModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

postman测试

我们代码里面有个create方法,是默认post方法,所以不用带路径,调用后数据库会插入一条数据,成功!

下载个SQLiteStudio可以打开jeecgdb.db这个文件看到数据库数据。

工程化设置

.npmrc 和 .dockerignore

添加文件 .npmrc

ini 复制代码
registry=https://registry.npmmirror.com

添加文件 .dockerignore

.git
node_modules

pm2 支持

pm2学习可以看 juejin.cn/post/722959...

全局安装pm2

npm install -g pm2

新建pm2配置文件

根目录 ecosystem.config.js,其中apps是数组,可以放多个启动脚本;scripts是指向最终nestjs执行build之后的文件

css 复制代码
module.exports = {
  apps: [
    {
      name: 'jeecg-nest-server',
      script: './dist/main.js',
    },
  ],
};

pm2 命令

arduino 复制代码
pm2 logs  // 查看日志
pm2 delete [pid] // 根据启动后得到的id,删除进程 

// 普通命令行启动,黑框框弹出后消失运行在后台,容器中不能用这个
pm2 start ecosystem.config.js 

// Docker 容器中使用这个启动,因为用 pm2 start 容器将在运行该进程后立即死亡,
// 所以为了容器专门用 pm2-runtime。
pm2-runtime ecosystem.config.js  

pm2 和 pm2-runtime 之间的主要区别是

  • pm2-runtime 专为 Docker 容器设计,它将应用程序保持在前台,使容器保持运行,

  • pm2 专为在后台发送或运行应用程序的正常使用而设计。

build打包项目

Dockerfile 文件

三点:要用node18版本的,要python环境,时区东八区

bash 复制代码
FROM keymetrics/pm2:18-alpine

# 默认是UTC时间,改为我们的日期东八区
ENV TZ=Asia/Shanghai
RUN apk update \
    && apk add tzdata \
    && echo "${TZ}" > /etc/timezone \
    && ln -sf /usr/share/zoneinfo/${TZ} /etc/localtime \
    && rm /var/cache/apk/*

# NestJS需要安装python3
ENV PYTHONUNBUFFERED=1
RUN apk add --update --no-cache python3 && ln -sf python3 /usr/bin/python && python3 -m ensurepip && pip3 install --no-cache --upgrade pip setuptools

# 打包
RUN mkdir -p /app
WORKDIR /app
COPY . ./
RUN npm install -g pnpm && pnpm install &&  pnpm run build

# 暴露端口和pm2运行
EXPOSE 3000
CMD [ "pm2-runtime", "ecosystem.config.js" ]

【废弃尝试】pm2:18-buster

pm2:18-buster 是全面版本容器,但是太大了有900M,改用pm2:18-alpine只有149M,但是打包中发现报错,需要python环境,于是在alpine中配置python3环境,最后我看Harbor里面压缩后只有155M还是能接受

【废弃尝试】引入webpack打包

为什么要引入webpack呢,很扯蛋,如果谁看到有其他办法请告诉我

正常在 package.json 中有build命令,我正常执行 npm run build 之后发布到linux上,看起来docker容器已经运行起来了,但是其实报错了 Error: Cannot find module '@nestjs/core',除非在容器中安装node_modules,但是我又不想在镜像里面安装node_modules,会导致镜像文件太大了

原因是 build 之后dist里面没有引入这些包,从上面Dockerfile可以看到是Jenkins里面构建之后,只是把dist目录拷贝进去了,如果是本地开发会自动找到node_modules能正常运行,但是服务器上没有node_modules那肯定运行不了,也不能把这个拷贝进去吧

找到一篇文章说方法 juejin.cn/post/706572... , 方法就是在nest-build章节找到了这个配置项的相关内容,发现他可以在打包命令后面添加--webpack参数来生成单文件main.js

安装包

注意:上述webpack配置文件要求package.json中webpack的版本号为^5.11.0",还需要安装fork-ts-checker-webpack-plugin依赖包到devDependencies中。

perl 复制代码
npm install webpack fork-ts-checker-webpack-plugin -D

修改 package.json

json 复制代码
{ 
    "scripts": { 
        "build": "nest build --webpack --webpackPath=./webpack.config.js", 
    } 
}

新建 webpack.config.js

javascript 复制代码
/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const webpack = require('webpack');
// fork-ts-checker-webpack-plugin需要单独安装
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');

module.exports = {
  entry: './src/main',
  target: 'node',
  // 置为空即可忽略webpack-node-externals插件
  externals: {},
  // ts文件的处理
  module: {
    rules: [
      {
        test: /\.ts?$/,
        use: {
          loader: 'ts-loader',
          options: { transpileOnly: true },
        },
        exclude: /node_modules/,
      },
    ],
  },
  // 打包后的文件名称以及位置
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
  },
  resolve: {
    extensions: ['.js', '.ts', '.json'],
  },
  plugins: [
    // 需要进行忽略的插件
    new webpack.IgnorePlugin({
      checkResource(resource) {
        const lazyImports = [
          '@nestjs/microservices',
          '@nestjs/microservices/microservices-module',
          '@nestjs/websockets/socket-module',
          'cache-manager',
          'class-validator',
          'class-transformer',
        ];
        if (!lazyImports.includes(resource)) {
          return false;
        }
        try {
          require.resolve(resource, {
            paths: [process.cwd()],
          });
        } catch (err) {
          return true;
        }
        return false;
      },
    }),
    new ForkTsCheckerWebpackPlugin(),
  ],
};

结果还是报错了

算了,还是在服务器上安装包吧,认命吧

前端nginx增加转发规则

如图把前端nest前端的接口,都转发到新的nestjs开发的接口上去

Jenkins 新增项目流水线配置

nestjs流水线注意两点,把sqlite挂载到宿主机上,监听暴露的3000端口

相关推荐
浮华似水20 分钟前
简洁之道 - React Hook Form
前端
正小安2 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch4 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光4 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   4 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   4 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web4 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常4 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇5 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr5 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui