阅读 568

全栈第一步 - 手把手教你使用NestJs搭建服务端应用 -- 1

介绍

Nest 是一个用于构建高效,可扩展的 Node.js 服务器端应用程序的框架。它使用渐进式 JavaScript,内置并完全支持 TypeScript(但仍然允许开发人员使用纯 JavaScript 编写代码)并结合了 OOP(面向对象编程),FP(函数式编程)和 FRP(函数式响应编程)的元素。

复制借鉴至NestJs中文文档

PS1: NestJs中文网

安装

与Vue一样,你可以使用脚手架来构建一个Nest项目,或者直接从git上clone源码。这里建议安装一下NestJs的脚手架。。。。因为比较简单

# npm
npm i -g @nestjs/cli

# yarn
yarn global add @nestjs/cli
复制代码

PS2: 依赖Node.js(ver>=10.13.0)

创建项目

nest new project-name
复制代码

image.png

这里选择使用yarn

image.png

创建成功,打开文件夹看一下,项目结构如下

src
 ├── app.controller.spec.ts
 ├── app.controller.ts
 ├── app.module.ts
 ├── app.service.ts
 └── main.ts
复制代码

看着这个结构,相信一些做过Java尤其是用过Spring框架的同学已经开始激动了,不着急,更令人激动的内容还在后面

PS3: 索尼公司推出的第三代家用电视游戏机

启动

打开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);
  // 3000 --> 8081
}
bootstrap();
复制代码

将默认监听端口改成8081,3000空出来给Vue使用

然后运行yarn start:dev以开发模式启动

访问localhost:8081,或者也可以使用postman来请求一下

image.png

那么,这个Hello World!是怎么返回的呢。

我们打开控制器的代码看一下

// 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();
  }
}
复制代码

可以看到,在这里引用并实例化了AppService的类,调用并返回了它的getHello方法。我们再看下service的代码

// app.service.ts

import { Injectable } from '@nestjs/common';

@Injectable()
export class AppService {
  getHello(): string {
    return 'Hello World!';
  }
}
复制代码

这样结构就很明了了,至于代码中出现的@开头的这些装饰器,后续会介绍到 可以去看下中文文档,这里就不详细介绍了,相信接触过Spring的同学看着会很眼熟。

为了验证一下猜想,我们把getHello()的返回值改成'Hello Nest',试一下。

image.png

PS4: 如果是以开发模式启动的项目yarn start:dev,在修改非配置项代码的时候是不需要重启项目的,而如果直接使用yarn start启动项目,每次修改代码都是需要重新启动的。

新增功能模块

在前面我们知道了,NestJs的项目结构是由Controller、Service、Module三个主要部分组成的,它们共同组成一个模块。

  • Controller: 控制器,通过@Controller()装饰器定义的类,目的是接收应用的特定请求。路由机制控制哪个控制器接收哪些请求。通常,每个控制器有多个路由,不同的路由可以执行不同的操作。它的功能类似Spring,主要就是为前端提供api接口,以及一些简单的验证。
  • Service: 提供者,又称为Provider,通过@Injectable()装饰器定义的类,功能也类似Spring的服务层,主要负责处理具体的业务,逻辑代码一般都写在这里。
  • Module: 模块,通过@Module()装饰器定义的类,这里和Spring有区别,它的作用主要是负责连接ControllerService,有些类似namespace

下面,我们新增一个登录服务的模块来试一下。

首先我们可以输入nest -h来查看下nest的command列表

Options:
  -v, --version                                   Output the current version.
  -h, --help                                      Output usage information.

Commands:
  new|n [options] [name]                          Generate Nest application.
  build [options] [app]                           Build Nest application.
  start [options] [app]                           Run Nest application.
  info|i                                          Display Nest project details.
  update|u [options]                              Update Nest dependencies.
  add [options] <library>                         Adds support for an external library to your project.
  generate|g [options] <schematic> [name] [path]  Generate a Nest element.
    Available schematics:
      ┌───────────────┬─────────────┬──────────────────────────────────────────────┐
      │ name          │ alias       │ description                                  │
      │ application   │ application │ Generate a new application workspace         │
      │ class         │ cl          │ Generate a new class                         │
      │ configuration │ config      │ Generate a CLI configuration file            │
      │ controller    │ co          │ Generate a controller declaration            │
      │ decorator     │ d           │ Generate a custom decorator                  │
      │ filter        │ f           │ Generate a filter declaration                │
      │ gateway       │ ga          │ Generate a gateway declaration               │
      │ guard         │ gu          │ Generate a guard declaration                 │
      │ interceptor   │ in          │ Generate an interceptor declaration          │
      │ interface     │ interface   │ Generate an interface                        │
      │ middleware    │ mi          │ Generate a middleware declaration            │
      │ module        │ mo          │ Generate a module declaration                │
      │ pipe          │ pi          │ Generate a pipe declaration                  │
      │ provider      │ pr          │ Generate a provider declaration              │
      │ resolver      │ r           │ Generate a GraphQL resolver declaration      │
      │ service       │ s           │ Generate a service declaration               │
      │ library       │ lib         │ Generate a new library within a monorepo     │
      │ sub-app       │ app         │ Generate a new application within a monorepo │
      │ resource      │ res         │ Generate a new CRUD resource                 │
      └───────────────┴─────────────┴──────────────────────────────────────────────┘
复制代码

创建模块

Module

使用generate来创建一个新模块

nest g mo user system
复制代码

这里的g和mo都是使用了别名简写,各指令的别名和描述上面的帮助列表里都有了,上述命令的意义就是在system下生成一个名为login的module。然后我们看下项目结构。

image.png

可以看到,对应的路径和文件都已经生成完毕, 当然,只有Module是肯定没用的,我们接下来再创建一下Controller。同样使用脚手架来生成

Controller

# Controller
nest g co user system
复制代码

打开user.module.ts

// user.module.ts

import { Module } from '@nestjs/common';
import { UserController } from './user.controller';

@Module({
  controllers: [UserController],
})
export class UserModule {}
复制代码

打开app.module.ts

import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './system/user/user.module';

@Module({
  imports: [UserModule],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}
复制代码

可以看到,新增的Controller已经自动引入进来了,新增的模块也自动被引入了,非常智能(傻瓜?)。

Service

# Service
nest g s user system
复制代码

同样,生成的Service会被自动引入,不需要手动配置

添加接口

我们首先在用户控制器中添加一个注册接口

import { Controller, Post } from '@nestjs/common';

@Controller('user')
export class UserController {
  @Post('register')
  register() {
    return true;
  }
}
复制代码

测试一下

image.png

  • 局部路由前缀

这里引出了路由的概念,由代码可以看出,我们生成的user模块下,@Controller修饰器中自动填入了一个user, 打开@Controller()的定义

export declare function Controller(prefix: string | string[]): ClassDecorator;
复制代码

可以看到这个入参是前缀的意思,同理,下面的@Post()就是定义了一个路径为/register的post请求接口,所以我们想要定位到某个控制器下的某个方法,需要访问控制器前缀 + 方法前缀。

  • 全局路由前缀

既然是全局,肯定需要在入口文件里设置,在main.ts中通过app.setGlobalPrefix()来设置全局路由

// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.setGlobalPrefix('api');
  await app.listen(8081);
}
复制代码

再测试一下

image.png

补充一下逻辑,测试入参

  • user.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { UserService } from './user.service';

@Controller('user')
export class UserController {
  constructor(private readonly userService: UserService) {}

  @Post('register')
  // @Body()可以帮助获取request.body中的参数
  register(@Body() user: any) {
    return this.userService.register(user);
  }
}
复制代码
  • user.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class UserService {
  register(user: any): boolean {
    // 这里输出一下,看参数有没有成功接到
    console.log(user);
    if (user?.userName && user?.pwd && user?.pwd === user?.confirmPwd) {
      return true;
    } else {
      return false;
    }
  }
}
复制代码

PS5:因为这里是测试逻辑,所以没有加类型约束(anyScript最棒了!),实际开发中一定要完善类型约束。会给我们后续的开发和维护带来很大的帮助

  • 测试一下接口

image.png

  • 看一下控制台输出

image.png

到这里,基本的架构就搭建好了。本文章主要用来记录自己学习过程中的一些知识点以及遇到的问题,如果有任何的不足欢迎在评论区指正。谢谢大家了~~ OVO

文章分类
前端
文章标签