NestJS 搭建博客系统(三)— 使用TypeORM+Mysql实现数据持久化
前言
这一节我们使用 TypeORM + Mysql 实现数据持久化。
TypeORM 是一个 ORM 框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8)一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。
你也可以选择 Squelize ORM
环境配置
安装 Mysql
这里我不详细展开 Mysql 的安装方法。顺便安利个简便的配置方式,同时也是我正在使用的方式。使用 docker 运行 mysql。 github.com/huihuipan/e… 这个库里面配置了 Mysql、Mongodb、Redis、nginx、jenkins、yapi 等服务,可以根据自己需要选择自己的服务。
软件部分
软件会用到数据库工具,如 navicat / dbeaver 调试请求会用到 postman 或者也可以使用上面的 environment 里面提供的 yapi
编写代码
安装依赖
使用 TypeORM 和 mysql 需要在项目中安装以下包
npm install --save @nestjs/typeorm typeorm mysql2
复制代码
引用配置
首先我们在 app.module 中引用 TypeOrmModule,TypeOrmModule 由 @nestjs/typeorm 提供
// src/app.modules.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { ArticleModule } from './modules/article/article.module';
import { TypeOrmModule } from '@nestjs/typeorm'
@Module({
imports: [
// 使用 TypeORM 配置数据库
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: '888888',
database: 'test',
entities: ["dist/modules/**/*.entity{.ts,.js}"],
synchronize: true,
}),
ArticleModule
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
复制代码
创建实体 Entity
Entity 是由 @Entity 装饰器装饰的模型。 TypeORM 会为此类模型创建数据库表。
新建文件 src/modules/article/entity/article.entity.ts
// src/modules/article/entity/article.entity.ts
import {
Entity,
Column,
PrimaryGeneratedColumn,
UpdateDateColumn,
CreateDateColumn,
VersionColumn,
} from 'typeorm';
@Entity()
export class Article {
// 主键id
@PrimaryGeneratedColumn()
id: number;
// 创建时间
@CreateDateColumn()
createTime: Date
// 更新时间
@UpdateDateColumn()
updateTime: Date
// 软删除
@Column({
default: false
})
isDelete: boolean
// 更新次数
@VersionColumn()
version: number
// 文章标题
@Column('text')
title: string;
// 文章描述
@Column('text')
description: string;
// 文章内容
@Column('text')
content: string;
}
复制代码
使用 DTO
关于 DTO,NestJS 是这么说的
DTO(数据传输对象)模式。DTO是一个对象,它定义了如何通过网络发送数据。我们可以通过使用 TypeScript 接口(Interface)或简单的类(Class)来定义 DTO 模式。有趣的是,我们在这里推荐使用类。为什么?类是 JavaScript ES6 标准的一部分,因此它们在编译后的 JavaScript 中被保留为实际实体。另一方面,由于 TypeScript 接口在转换过程中被删除,所以 Nest 不能在运行时引用它们。这一点很重要,因为诸如管道(Pipe)之类的特性为在运行时访问变量的元类型提供更多的可能性。
在 java 里面
DTO: 数据传输对象,原先是为分布式提供粗粒度的数据实体,减少调用次数来提升性能和降低网络压力。
简单来说,就是定义一个数据,作用类似于定义方法的入参,而且还能方便我们做其他事情。比如我们的表单验证就可以在 DTO 中使用。
创建以下文件
// src/modules/article/dto/list.dto.ts
export class ListDTO {
readonly page: number;
readonly pageSize: number;
}
复制代码
// src/modules/article/dto/id.dto.ts
export class IdDTO {
readonly id: number
}
复制代码
// src/modules/article/dto/article-create.dto.ts
export class ArticleCreateDTO {
readonly title: string;
readonly description: string;
readonly content: string;
}
复制代码
// src/modules/article/dto/article-edit.dto.ts
export class ArticleEditDTO {
readonly id: number;
readonly title: string;
readonly description: string;
readonly content: string;
}
复制代码
控制器中使用 DTO
import {
Controller,
Body,
Query,
Get,
Post,
} from '@nestjs/common';
import { ArticleService } from './article.service';
import { ArticleCreateDTO } from './dto/article-create.dto';
import { ArticleEditDTO } from './dto/article-edit.dto';
import { IdDTO } from './dto/id.dto';
import { ListDTO } from './dto/list.dto';
@Controller('article')
export class ArticleController {
constructor(
private articleService: ArticleService
) {}
@Get('list')
getMore(
@Query() listDTO: ListDTO,
) {
return this.articleService.getMore(listDTO)
}
@Get('info')
getOne(
@Query() idDto: IdDTO
) {
return this.articleService.getOne(idDto)
}
@Post('create')
create(
@Body() articleCreateDTO: ArticleCreateDTO
) {
return this.articleService.create(articleCreateDTO)
}
@Post('edit')
update(
@Body() articleEditDTO: ArticleEditDTO
) {
return this.articleService.update(articleEditDTO)
}
@Post('delete')
delete(
@Body() idDto: IdDTO,
) {
return this.articleService.delete(idDto)
}
}
复制代码
在 article.module 中定义使用那些存储库
import { Module } from '@nestjs/common';
import { ArticleService } from './article.service';
import { ArticleController } from './article.controller';
import { Article } from './entity/article.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forFeature([Article]),
],
providers: [ArticleService],
controllers: [ArticleController]
})
export class ArticleModule {}
复制代码
同时修改下我们的服务,改为使用 TypeORM 存取数据
import { Injectable } from '@nestjs/common';
import { ArticleCreateDTO } from './dto/article-create.dto';
import { ArticleEditDTO } from './dto/article-edit.dto';
import { IdDTO } from './dto/id.dto';
import { ListDTO } from './dto/list.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Article } from './entity/article.entity';
@Injectable()
export class ArticleService {
list: any[];
constructor(
@InjectRepository(Article)
private readonly articleRepository: Repository<Article>,
) {
this.list = []
}
async getMore(
listDTO: ListDTO,
) {
const { page = 1, pageSize = 10 } = listDTO
const getList = this.articleRepository
.createQueryBuilder('article')
.where({ isDelete: false })
.select([
'article.id',
'article.title',
'article.description',
'article.createTime',
'article.updateTime',
])
.skip((page - 1) * pageSize)
.take(pageSize)
.getMany()
const list = await getList
return list
}
async getOne(
idDto: IdDTO
) {
const { id } = idDto
const articleDetial = await this.articleRepository
.createQueryBuilder('article')
.where('article.id = :id', { id })
.getOne()
return articleDetial;
}
async create(
articleCreateDTO: ArticleCreateDTO
):Promise<Article>{
const article = new Article();
article.title = articleCreateDTO.title
article.description = articleCreateDTO.description
article.content = articleCreateDTO.content
const result = await this.articleRepository.save(article);
return result
}
async update(
articleEditDTO: ArticleEditDTO
): Promise<Article>{
const { id } = articleEditDTO
let articleToUpdate = await this.articleRepository.findOne({ id })
articleToUpdate.title = articleEditDTO.title
articleToUpdate.description = articleEditDTO.description
articleToUpdate.content = articleEditDTO.content
const result = await this.articleRepository.save(articleToUpdate)
return result
}
async delete (
idDTO: IdDTO,
) {
const { id } = idDTO
let articleToUpdate = await this.articleRepository.findOne({ id })
articleToUpdate.isDelete = true
const result = await this.articleRepository.save(articleToUpdate)
return result
}
}
复制代码