全栈第一步 - 使用NestJs搭建服务端应用 -- ③(连接数据库)

1,048 阅读5分钟

前言

本篇文章主要来记录下NestJs如何连接数据库,不要问问啥要连数据库。服务端应用不连数据库难道只写Hello World吗。至于数据库还是选择了MySQL,王道!别问Oracle,问就是收钱。至于连接工具,这里选择了NestJs推荐的TypeORM,当然,这里完全自由啊,如果有同学喜欢其他的工具也是完全可以的。

环境准备

MySQL

既然要连数据库,肯定得先有数据库哈。这里我直接使用了我自己云端的数据库,有个人服务器的同学建议直接使用远程的,没有的同学也可以在本机装一个MySQL服务,安装方式这里就不介绍了,大家可自行问度娘。

  • 新建数据库以及数据表 首先我们新建一个test库,然后在这个库里新建一个user表。BTW,这里其实可以使用可视化工具来操作的哈,个人感觉比较好用的还是Navicat,我这里因为不方便安装,所以直接访问的服务。

image.png

这就是建好表之后的样子了,然后我们在表里先插入一条测试数据,方便等会测试数据库连接。

image.png

到这里,数据库的准备基本结束了。

TypeORM

TypeORM 是一个ORM (opens new window)框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8)一起使用。 它的目标是始终支持最新的 JavaScript 特性并提供额外的特性以帮助你开发任何使用数据库的(不管是只有几张表的小型应用还是拥有多数据库的大型企业应用)应用程序。
不同于现有的所有其他 JavaScript ORM 框架,TypeORM 支持 Active Record](active-record-data-mapper.md#what-is-the-active-record-pattern) 和 Data Mapper 模式,这意味着你可以以最高效的方式编写高质量的、松耦合的、可扩展的、可维护的应用程序。 -- TypeORM中文文档

关于一些修饰器的定义和用方法,本文不会再详细介绍了,大家有问题可以去查询下TypeORM中文文档

  • 安装
# yarn
@nestjs/typeorm typeorm mysql

#npm
npm install --save @nestjs/typeorm typeorm mysql

项目配置

创建实体

我们首先在项目根路径下创建entities文件夹,后续新增的eneity文件都会放到这里面,里面也可以再根据业务来区分模块。

image.png

然后我们新建一个user.eneity.ts文件

  • user.entity.ts
import { Column, Entity, PrimaryGeneratedColumn, BaseEntity } from 'typeorm';

@Entity()
export class UserEntity extends BaseEntity {
  // 自增主键
  @PrimaryGeneratedColumn()
  id: number;

  // 列
  @Column({ type: 'varchar', name: 'userName' })
  userName: string;

  @Column({ type: 'varchar', name: 'userPwd' })
  // 此处key可自定义,在项目中使用的key
  userPwd: string;
}

如果不需要做列名映射的话,其实这里可以简写成@Column(type),type建议还是不要省略了。至于继承的BaseEneity实体,这是TypeORM提供的基础实体,里面有一些封装好的简单的CRUD方法,如果有接触过Hibernate的同学应该对这里比较容易理解。有兴趣的同学也可以去看下这个实体里面具体都封装了哪些方法,有些简单的业务或许可以用到。

数据库配置

既然想使用数据库,那么肯定需要先连接。这里有两种方式。可以使用配置文件或者在app.moudle.ts中直连。

  • 配置文件 在项目根路径下新增ormconfig.json文件
{
    "type": "mysql", // 数据库类型
    "host": "localhost", // 数据库地址
    "port": 3306, // 端口号,如果没有自定义的话,这里默认就是3306
    "username": "test", // 用户名
    "password": "test", // 密码
    "database": "test", // 需要连接的数据库
    "synchronize": true, // 数据库与实体同步(如果在实体中新增的字段,那么数据库对应表里会自动插入)
    "entities": ["src/entity/**/*.ts"], // 实体扫描路径
}

其余的配置项这里就不详细介绍了,可按需查文档

  • app.module.ts 我是采用了这种方式,配置文件中配置动态路径会稍微复杂一点~~
...
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [
    TypeOrmModule.forRoot({ // 配置写在这里
      type: 'mysql',
      host: '***.***.***.***',
      port: 3306,
      username: 'root',
      password: '************',
      database: 'test',
      entities: [__dirname + '/**/*.entity{.ts,.js}'],
      synchronize: true,
    }),
    ...
  ],
  ...
})
export class AppModule {}

PS:...代表的是没有变更的代码,不是真的...

新增测试接口

  • user.module.ts
import { Module } from '@nestjs/common';
import { UserController } from './user.controller';
import { UserService } from './user.service';
import { UserEntity } from '@/entities/system/user.entity';
import { TypeOrmModule } from '@nestjs/typeorm';

@Module({
  imports: [TypeOrmModule.forFeature([UserEntity])],
  controllers: [UserController],
  providers: [UserService],
})
export class UserModule {}

PS2: 每一个实体文件都需要在其对应模块中导入并使用TypeOrmModule.forFeature()注册

  • user.service.ts 我们在这里注入实体并编写一个测试方法
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { UserEntity } from '@/entities/system/user.entity';

@Injectable()
export class UserService {
  // 在构造方法中注入实体
  constructor(
    @InjectRepository(UserEntity)
    private readonly userRepository: Repository<UserEntity>,
  ) {}
  ...
  // 在这里新增一个getAll方法,测试配置是否正确
  async getAllUserTest(): Promise<UserEntity[]> {
    // 其实这里也可以使用BaseEntity里提供的Read方法,不过建议还是自己写SQL比较好
    return await this.userRepository.query('select * from user');
  }
}
  • user.controller.ts 最后在controller中新增一个测试接口
...

@Controller('user')
@ApiTags('用户操作')
export class UserController {
  ...
  @Get('get_all_list')
  findAll(): any {
    return this.userService.getAllUserTest();
  }
}

测试

首先运行 yarn start:dev启动项目 然后通过工具请求一下刚定义的接口

image.png

OK,可以看到正常返回了正确的结果。那么本篇文章就到此结束了~~~

PS: 下集预告:引入JWT实现登录验证