关于我们

质量为本、客户为根、勇于拼搏、务实创新

< 返回新闻公共列表

Vue3 + Nest 实现权限管理系统 后端篇(一):NestJS入门与基础配置(上)

发布时间:2023-06-27 00:00:36

NestJS 是一个 NodeJS 的后端服务框架,它与传统的 NodeJS 框架不一样的是采用了控制反转(IOC)和依赖注入(DI)的模式进行开发,当然如果你对这中开发模式不熟悉的话也没关系,你可以查找资料去了解这种模式,或者直接开始阅读本篇文章你就会用 NestJS 了(会用就行)。接下来我们开始介绍 NestJS


全局安装 NestJS



npm i -g @nestjs/cli

   


第一个 NestJS 程序



nest new management_nest

   

执行完毕就会看到 src 下有这样一个目录

  • app.controller.ts

这里控制层,这里主要是写路由相关代码以及处理前端传来的一些参数(后面文章会介绍如何接收参数)

import { Controller, Get } from '@nestjs/common'; import { AppService } from './app.service'; @Controller() export class AppController {  constructor(private readonly appService: AppService) {}  @Get()  getHello(): string {  return this.appService.getHello();  } }

   

  • app.service.ts

这里是业务层,在这里写一些与业务相关的逻辑。比如对数据库的 CRUD 就可以写到这里

import { Injectable } from "@nestjs/common"; @Injectable() export class AppService {  getHello(): string {  return "Hello World!";  } }

   

  • app.module.ts

它可以组织应用程序中的许多功能,如控制器、服务以及可以导入其他模块等

import { Module } from "@nestjs/common"; import { AppController } from "./app.controller"; import { AppService } from "./app.service"; @Module({  imports: [],  controllers: [AppController],  providers: [AppService], }) export class AppModule {}

   

  • main.ts
import { NestFactory } from "@nestjs/core"; import { AppModule } from "./app.module"; async function bootstrap() {  const app = await NestFactory.create(AppModule);  await app.listen(3000); } bootstrap();

   

main.ts 则是整个程序的入口文件

我们可以执行pnpm run start:dev开启一个可以热更新的 NestJS 服务,浏览器打开http://localhost:3000/便可发送一个 get 请求到app.controller.ts中的 getHello 函数,然后再调用app.service.ts里的 getHello 函数返回Hello World!

这里我们发现app.controller.ts的 appService 并没有实例化就可以直接使用了,其实这里是因为在app.module.ts已经进行了依赖注入(providers)这里已经将其处理好了


装饰器



在上面的代码中我们看到了譬如@Controller(),@get(),@Module()之类的东西,其实这些东西就是装饰器,你可以把它看作一个函数就行了,比如@Controller()它属于一个类装饰器,他会把下面的类当作参数传入然后进行一些处理从而实现处理路由的功能

为了更好的演示,我们新建一个模块,NestJS 给我们提供了一些命令可以创建对应文件,比如

  • 生成一个 module (nest g mo) 。
  • 生成一个 controller (nest g co) 。
  • 生成一个 service (nest g s) 。

你可以执行nest -h 查看这些命令

我们可以执行nest g res user生成一个 user 模块,包括它的module,controller,service,执行之前可以在nest-cli.json中配置

"generateOptions": {  "spec": false  }

   

让其不生成测试文件,执行命令我们可以选择 REST API 的形式,这样我们 src 下就会出现了 user 模块

我们可以看到user.controller.ts引入了很多装饰器,已经给我们写好了 CRUD 的模板

import {  Controller,  Get,  Post,  Body,  Patch,  Param,  Delete, } from '@nestjs/common'; import { UserService } from './user.service'; import { CreateUserDto } from './dto/create-user.dto'; import { UpdateUserDto } from './dto/update-user.dto'; @Controller('user') export class UserController {  constructor(private readonly userService: UserService) {}  @Post()  create(@Body() createUserDto: CreateUserDto) {  return this.userService.create(createUserDto);  }  @Get()  findAll() {  return this.userService.findAll();  }  @Get(':id')  findOne(@Param() id: string) {  return this.userService.findOne(+id);  }  @Patch(':id')  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto) {  return this.userService.update(+id, updateUserDto);  }  @Delete(':id')  remove(@Param('id') id: string) {  return this.userService.remove(+id);  } }

   

@Post,@Get,@Patch等就是对应的请求方式装饰器,比如你用 POST 请求调用http://localhost:3000/user就会进入@Post()下面的 create()方法,@Body,@Params则是请求参数装饰器,我们可以从中获取到前端传来的参数

拿第一个Post请求举例,发送 post 请求我们可以使用postman,apifox等工具进行测试,这里我使用apifox进行演示

我们可以先打印一下前端@Body()装饰的createUserDto,然后发送一个 Post 请求

@Post()  create(@Body() createUserDto: CreateUserDto) {  console.log(createUserDto);  return this.userService.create(createUserDto);  }

   

此时我们就会发现控制台打印了前端传来的 Body 参数

如果想使用别的请求路径,可以在@Post 传入路径,比如@Post('list'),请求路径就会变成/user/list


如果你想获取 Get 请求传来的参数可以使用@Query,获取 Header 中的参数可以使用@Header 等等,这些装饰器有很多这里就不过多介绍了,后面的教程中遇到会作一个详细说明


连接 MySql 数据库



作为一个后端框架肯定是离不开数据库的,NestJS 连接数据库其实很简单,可以先安装@nestjs/typeormmysql,typeorm可以让对数据库的 sql 操作映射成对象的操作

pnpm install @nestjs/typeorm typeorm mysql -S

   

然后你需要在本地安装 mysql 数据库,这里可以自行百度~(注意记住你的用户名和密码以及数据库安装位置)

推荐一个 VSCode 数据库可视化插件Database Client,安装完后连接我们的数据库就能进行一个可视化操作

一切准备就绪,我们新建一个数据库名为easyestadmin,然后开始连接 mysql,我们来到app.module.ts中进行数据库的配置,引入TypeOrmModule调用forRoot进行配置

import { Module } from "@nestjs/common"; import { AppController } from "./app.controller"; import { AppService } from "./app.service"; import { UserModule } from "./user/user.module"; import { TypeOrmModule } from "@nestjs/typeorm"; @Module({  imports: [  TypeOrmModule.forRoot({  type: "mysql",  synchronize: true,  autoLoadEntities: true, //自动加载实体  host: "localhost",  port: 3306, // 端口号  username: "root", // 用户名  password: "root", // 密码  database: "management", //数据库名  synchronize: true, //是否自动同步实体文件,生产环境建议关闭  }),  UserModule,  ],  controllers: [AppController],  providers: [AppService], }) export class AppModule {}

   

当我们将autoLoadEntities设置为 true 的时候,NestJS 会自动加载数据库实体文件xx.entity.ts文件来创建数据表(如果没有的话),比如 user/entities/user.entity.ts,我们简单加一些字段

import { Column, Entity, PrimaryGeneratedColumn } from "typeorm"; @Entity("user") export class User {  @PrimaryGeneratedColumn("uuid")  id: number; // 标记为主键,值自动生成  @Column({ length: 30 })  username: string; //用户名  @Column()  password: string; //密码 }

   

启动项目,然后就会发现自动创建了一个 user 表

如果我们想对 user 表进行一些 CRUD 的操作.可以在user.module.ts中导入

import { Module } from "@nestjs/common"; import { UserService } from "./user.service"; import { UserController } from "./user.controller"; import { User } from "./entities/user.entity"; import { TypeOrmModule } from "@nestjs/typeorm"; @Module({  controllers: [UserController],  providers: [UserService],  imports: [TypeOrmModule.forFeature([User])], }) export class UserModule {}

   

user.service.ts中引入使用,比如在 create 函数中创建一条数据

import { Injectable } from "@nestjs/common"; import { CreateUserDto } from "./dto/create-user.dto"; import { UpdateUserDto } from "./dto/update-user.dto"; import { User } from "./entities/user.entity"; import { InjectRepository } from "@nestjs/typeorm"; import { Repository } from "typeorm"; @Injectable() export class UserService {  constructor(  @InjectRepository(User)  private userRepository: Repository ) {}  async create(createUserDto: CreateUserDto) {  return await this.userRepository.save(createUserDto);  }  async findAll() {  return await this.userRepository.find();  }  findOne(id: number) {  return `This action returns a #${id} user`;  }  update(id: number, updateUserDto: UpdateUserDto) {  return `This action updates a #${id} user`;  }  remove(id: number) {  return `This action removes a #${id} user`;  } }

   

再调用 user 接口,传入 username 和 password

我们就完成了一条数据的插入,在 findAll 中查询所有数据,调用 get 请求便可拿到 user 表中的数据

一般来说数据库的配置包含了一些敏感信息不宜写在代码中提交到远程仓库,所以我们可以将配置写在配置文件中,然后提交 git 时候将生产环境的配置文件其忽略,这里我们新建.env.env.prod两个文件分别存放开发与生产环境配置

我们还安装 cross-env 来判断我们是处于什么环境

pnpm install cross-env

   

然后修改package.json中的script

"start:prod": "cross-env NODE_ENV=production node dist/main",

   

这样我们生成环境的 NODE_ENV 就是 production 了,我们可以根据这个加载不同配置文件。想要加载配置文件,NestJS 给我们提供了@nestjs/config,这个需要手动安装,安装完成之后,在app.module.ts进行配置

import { Module } from "@nestjs/common"; import { AppController } from "./app.controller"; import { AppService } from "./app.service"; import { UserModule } from "./user/user.module"; import { TypeOrmModule } from "@nestjs/typeorm"; import { ConfigModule } from "@nestjs/config"; import * as path from "path"; const isProd = process.env.NODE_ENV == "production"; @Module({  imports: [  ConfigModule.forRoot({  envFilePath: [isProd ? path.resolve(".env.prod") : path.resolve(".env")],  }),  TypeOrmModule.forRoot({  type: "mysql",  host: process.env.DB_HOST,  port: parseInt(process.env.DB_PORT), // 端口号  username: process.env.DB_USER, // 用户名  password: process.env.DB_PASSWD, // 密码  autoLoadEntities: true, //自动加载实体  synchronize: !isProd, //是否自动同步实体文件,生产环境建议关闭  database: process.env.DB_DATABASE, //数据库名  }),  UserModule,  ],  controllers: [AppController],  providers: [AppService], }) export class AppModule {}

   



/template/Home/leiyu/PC/Static