NestJS 搭建博客系统(二)— 编写静态文章CURD

3,756 阅读4分钟

NestJS 搭建博客系统(二)— 编写静态文章CURD

前言

根据上一篇NestJS 搭建博客系统(一)— 搭建框架我们已经准备好了NestJS的基本框架,并且也熟悉了一些基本的概念,那么现在就开始填充我们的第一个功能吧。

简介

本篇将通过一个简单的例子来熟悉 NestJS 里 Controller 和 Service 的基本用法。

编写代码

创建模块

使用 Nest CLI 可以快速帮助我们新建相应的文件 在终端输入 nest -h

namealiasdescription
applicationapplicationGenerate a new application workspace
classclGenerate a new class
configurationconfigGenerate a CLI configuration file
controllercoGenerate a controller declaration
decoratordGenerate a custom decorator
filterfGenerate a filter declaration
gatewaygaGenerate a gateway declaration
guardguGenerate a guard declaration
interceptorinGenerate an interceptor declaration
interfaceinterfaceGenerate an interface
middlewaremiGenerate a middleware declaration
modulemoGenerate a module declaration
pipepiGenerate a pipe declaration
providerprGenerate a provider declaration
resolverrGenerate a GraphQL resolver declaration
servicesGenerate a service declaration
librarylibGenerate a new library within a monorepo
sub-appappGenerate a new application within a monorepo
resourceresGenerate a new CRUD resource

新建一个 article 模块,依次在命令行输入

nest g mo modules/article # 创建模块
nest g s modules/article  # 创建服务
nest g co modules/article # 创建控制器

此时我们的代码结构为

.
├── README.md
├── nest-cli.json
├── package.json
├── src
│   ├── app.controller.spec.ts
│   ├── app.controller.ts
│   ├── app.module.ts
│   ├── app.service.ts
│   ├── filters
│   ├── main.ts
│   └── modules # 新增
│       └── article
│           ├── article.controller.spec.ts
│           ├── article.controller.ts
│           ├── article.module.ts
│           ├── article.service.spec.ts
│           └── article.service.ts
├── test
│   ├── app.e2e-spec.ts
│   └── jest-e2e.json
├── tsconfig.build.json
├── tsconfig.json
└── yarn.lock

Nest CLI 会帮我们自动在 article.module 引入 article.controller 和 article.service,并在 app.module 引入 article.module

看起来就像这样

main: {
  app.module: {
    app.controller
    app.service

    article.module: {
      article.controller
      article.service
    }

  }
}

编写路由

在 article.controller 中编写路由

// src/modules/article/article.controller.ts

import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ArticleService } from './article.service';
import { Article } from './interface/article.interace';

@Controller('article')
export class ArticleController {
  constructor(
    private articleService: ArticleService
  ) {}

  @Get('list')
  getMore() {
    return '文章列表'
  }

  @Get('info')
  getOne(
    @Query() id:string
  ) {
    return '文章详情'
  }

  @Post('create')
  create(
    @Body() article: Article
  ) {
    return '创建文章'
  }

  @Post('edit')
  update(
    @Body() article: Article
  ) {
    return '编辑文章'
  }

  @Post('remove')
  delete(
    @Body() id: number
  ) {
    return '删除文章'
  }
}

当然,NestJS 提供标准 Http 方法的装饰器,你也可以这样子

// src/modules/article/article.controller.ts

import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ArticleService } from './article.service';
import { Article } from './interface/article.interace';

@Controller('article')
export class ArticleController {
  constructor(
    private articleService: ArticleService
  ) {}

  @Get()
  getMore() {
    return '文章列表'
  }

  @Get(':id')
  getOne(
    @Query() id:string
  ) {
    return '文章详情'
  }

  @Post(':id')
  create(
    @Body() article: Article
  ) {
    return '创建文章'
  }

  @Put(':id')
  update(
    @Body() article: Article
  ) {
    return '编辑文章'
  }

  @Delete(':id')
  delete() {
    return '删除文章'
  }
}

Nest 提供相当丰富的装饰器可供使用,详细可以看考控制器

我这里为了简单,只选择了 Get、Post 两种请求方式

编写服务

现在我们只有路由,请求 localhost:3000/article/list 只会返回简单的文章列表几个字符串。所以我们需要编写服务,也就是这样 控制器(路由) -> 提供者(服务)

在编写服务前,我们先定义一下文章的字段结构,这里采用 创建 src/modules/article/interface/article.interface.ts

export interface Article {
  id?: '',          // id
  title: '',        // 标题
  description: '',  // 描述
  content: '',      // content
  createTime?: '',  // 创建时间
  updateTime?: '',  // 更新时间
  isDelete?: '',    // 是否删除
}

定义完文章的字段结构就可以开始编写服务了

// src/modules/article/article.service.ts

import { Injectable } from '@nestjs/common';
import { Article } from './interface/article.interace';

@Injectable()
export class ArticleService {
  list: any[]; // 存放临时数据
  constructor() {
    this.list = []
  }

  // 获取列表
  getMore() {
    return this.list.filter(item => !item.isDelete)
  }

  // 获取单条
  getOne({ id }) {
    const item = this.list.filter(item => {
      return item.id === id
    })[0]
    if (item) {
      return item
    }
    return '找不到文章'
  }

  // 创建文章
  create(
    article: Article
  ) {
    const id = this.list.length
    const item = {
      id,
      ...article
    }
    this.list.push(item)
  }

  // 更新文章
  update(
    article: Article
  ) {
    let idx = 0
    const item = this.list.filter((item, i) => {
      if (item.id === article.id) {
        idx = i
      }
      return item.id === article.id
    })
    if (!item) {
      return '找不到文章'
    }
    const nItem = {
      ...item,
      ...article,
    }
    this.list.splice(idx, 1, nItem)
  }
  
  // 删除文章
  delete({ id }) {
    let idx = 0
    const item = this.list.filter((item, i) => {
      if (item.id === id) {
        idx = i
      }
      return item.id === id
    })
    if (!item) {
      return '找不到文章'
    }
    const nItem = {
      ...item,
      isDelete: true,
    }
    this.list.splice(idx, 1, nItem)
  }
}

改写一下我们的控制器, 把路由和服务对应起来

import { Body, Controller, Get, Post, Query } from '@nestjs/common';
import { ArticleService } from './article.service';
import { Article } from './interface/article.interace';

@Controller('article')
export class ArticleController {
  constructor(
    private articleService: ArticleService
  ) {}

  @Get('list')
  getMore() {
    return this.articleService.getMore()
  }

  @Get('info')
  getOne(
    @Query() id:string
  ) {
    return this.articleService.getOne({ id })
  }

  @Post('create')
  create(
    @Body() article: Article
  ) {
    return this.articleService.create(article)
  }

  @Post('edit')
  update(
    @Body() article: Article
  ) {
    return this.articleService.update(article)
  }

  @Post('remove')
  delete(
    @Body() id: number
  ) {
    return this.articleService.delete({ id })
  }
}

这时我们就可以对文章进行增删改查操作了。

到这里,我们了解到了 nest 的基本的请求,但是数据是存放在变量list 里面的,也就是说,当我们重新启动服务后,数据将会丢失。

下一节,我们使用 TypeORM 和 mysql 实现数据持久化

参考

系列