Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

37. typescript 企业级服务器开发:实战篇 #38

Open
hello-chinese opened this issue Sep 27, 2021 · 0 comments
Open

37. typescript 企业级服务器开发:实战篇 #38

hello-chinese opened this issue Sep 27, 2021 · 0 comments
Labels
typescript学习 Improvements or additions to documentation

Comments

@hello-chinese
Copy link
Owner

typescript 企业级服务器开发:实战篇

Nest 初始化

我们先在全局安装 nest.js 的 cli,然后初始化我们的项目:

npm install -g @nestjs/cli
nest new nest-app

我们选择 npm 进行安装:

2019-10-21-01-15-54

我们安装完毕后打开编辑器,它的目录结构是这样的:

2019-10-21-01-18-34

运行 npm start 后,在浏览器访问http://localhost:3000/,效果如下:

2019-10-21-01-20-36

那么我们的第一个 Nest.js 程序就启动了。

Controller

Controller 控制器,controller 负责处理传入的请求, 并调用对应的 service 完成业务处理,返回对客户端的响应。

我们创建一个新的 controller:

nest g co books

这个命令会产生两个动作:

  1. 创建 controller 文件:

2019-10-21-01-40-42

  1. 将新创建的 controller 注册到 module 中去

2019-10-21-01-41-35

我们看到生成的 books.controller.ts 文件:

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

@Controller('books')
export class BooksController {}

@Controller('books') 指定了当前路由路径为 books,可见 Nest.js 采用的是分散式路由。

我们对此文件进行改写:

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

@Controller('books')
export class BooksController {
@Get('/js')
findJavaScript() {
return 'JavaScript高级程序设计';
}
}

这里引入的 Get('/js') 代表了 get 方法,针对 books/js 的路由下进行的处理。

我们现在把服务暂停,选择开发模式再次启动项目:

npm run start:dev

这个时候我们的每次更改都会触发项目的二次编译,就不用反复运行项目了。

访问 http://localhost:3000/books/js 路由,我们看到的结果如下:

2019-10-21-01-49-29

果然,Controller 可以控制处理路由,但是在实际开发中这些返回的数据并不是写死的,我们必须在 Controller 中调用 Service 来获取数据。

Service

我们继续用命令行生成 Service:

nest g s books

效果如下:

2019-10-21-01-54-56

我们改写 books.service.ts 如下:

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

@Injectable()
export class BooksService {
getBooks() {
return 本书找到了!;
}
}

改写 books.controller.ts 如下:

@Controller('books')
export class BooksController {
    constructor(private readonly booksService: BooksService) {
    }

    @Get('/js')
    findBook() {
        const res = this.booksService.getBooks();

        return res;
    }
}

我们在 BooksController 注入了 BooksService,从而可以在 BooksController 调用相关的方法 this.booksService.getBooks(),这里就是依赖注入的运用。

但是仅仅有 Service、Controller 也是不够的,我们需要一个持久化储存数据的数据库,通常情况下我们在 Service 与 数据库之间需要加一层 DAO,开发者不应该直接操纵数据库,一方面性能没有保证,另一方面不易维护,这就涉及到了 TypeORM。

TypeORM

TypeORM 是一个 ORM 框架,在 Nest.js 架构中充当 DAO 层,我们通过操纵 TypeORM 来间接操纵数据库。

我们先安装相关的库以便在 nest.js 框架中使用:

npm install --save @nestjs/typeorm typeorm mysql

然后我们在 mysql 中新建一个数据库 nest:

2019-10-21-02-26-06

我们在 app.module.ts 配置 TypeOrmModule

import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { BooksController } from './books/books.controller';
import { BooksService } from './books/books.service';
import { BooksEntity } from './entities/books.entity';

@Module({
imports: [
TypeOrmModule.forRoot({
keepConnectionAlive: true,
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '',
database: 'nest',
synchronize: true,
entities: [BooksEntity],
}),
],
controllers: [AppController, BooksController],
providers: [AppService, BooksService],
})
export class AppModule {}

我们的 Entity 设置如下 entities/books.entity.ts:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('books')
export class BooksEntity {
  @PrimaryGeneratedColumn()
  id: number;

  @Column({ length: 20 })
  name: string;

  @Column({ length: 10 })
  author: string;
}

成功运行之后,我们的 Entity 会被映射到数据库中:

2019-10-21-03-15-14

接下来我们就可以通过这层 DAO 进行数据库操作了, 在 books.service.ts 中如下:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import * as _ from 'lodash';

import { BooksEntity } from '../entities/books.entity';
import { CreateBooksDto } from '../dtos/books.dto';

@Injectable()
export class BooksService {
constructor(
@InjectRepository(BooksEntity)
private readonly booksRepository: Repository<BooksEntity>,
) {}
async getBooks(id: number) {
return await this.booksRepository.findOne(id);
}

async createBooks(book: CreateBooksDto) {
const res = await this.booksRepository.save(book);

return _.pick(res, 'id');

}
}

我们用 @InjectRepository() 修饰器向 BooksService 注入 booksRepository,这样我们就可以在 BooksService 中利用this.booksRepository 进行 DAO 的操作了,比如查找、删除、创建等等。

我们在 books.controller.ts 中编辑控制器,至于 HTTP 请求对象的内容,在大多数情况下, 不必手动获取它们。 我们可以使用专用的装饰器,比如 @Body()@Query() 来自动获取。

import { Controller, Get, Param, Post, Body } from '@nestjs/common';
import { BooksService } from './books.service';
import { CreateBooksDto } from '../dtos/books.dto';

@Controller('books')
export class BooksController {
constructor(private readonly booksService: BooksService) {}

@Get(':id')
findBook(@Param('id') id: number) {
return this.booksService.getBooks(id);
}

@Post()
async create(@Body() createCatDto: CreateBooksDto): Promise<{ id: number }> {
return await this.booksService.createBooks(createCatDto);
}
}

接下来我们进行一下测试,我们在 PostMan 中进行如下测试:

2019-10-21-04-21-18

我们传入一个 json,包含书名和作者名字,用 post 方法发送,结果如下:

2019-10-21-04-22-49

我们看到了 201 创建成功的状态码,并受到了我们的 book 的 id,再看看数据库是否保存了数据:

2019-10-21-04-23-38

没问题,我们继续尝试查询 id 为 14 的书籍信息:

2019-10-21-04-24-22

我们成功查询:

2019-10-21-04-25-30

我们这个简易的服务器搭建算是基本告一段落。

小结

我们学习了基于 Nest.js 的简易服务器搭建,其分层的思想无处不在:

  • 我们通过 Controller 处理路由请求
  • 通过 Service 进行计算和数据操作
  • 通过 typeorm 生成 dao 层,我们间接操作数据库

各个层各司其职,通过依赖注入的方式充分解耦,这是企业级服务器开发的基本设计思想。

我已经把完整代码发布到了github 仓库 中。

@hello-chinese hello-chinese added the typescript学习 Improvements or additions to documentation label Sep 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
typescript学习 Improvements or additions to documentation
Projects
None yet
Development

No branches or pull requests

1 participant