引入数据库
初始化
Mysql 导入 deploy/sql/init.sql
实体类
- 安装依赖
pnpm install @nestjs/typeorm typeorm mysql2
-
新建
src/entities
这里存放所有entity
实体 -
新建
system.module
模块, 使用 nest 内置指令:nest g mo modules/admin/system
-
新建
src/entities/base.entity.ts
,定义一个抽象类BaseEntity
用于被其他实体类继承,因为基本每个实体类都必不可少createAt(创建时间)和updateAt(更新时间)
- 说明: 其中
name
属性用于指定数据库表中对应的列名。如果不指定 name 属性,则 TypeORM 默认会将属性名转换为下划线分隔的列名。例如,如果属性名为 createdAt,则默认列名为 created_at。如果指定了 name 属性,则 TypeORM 会将该属性映射到指定的列名。
import { ApiProperty } from '@nestjs/swagger';
import { CreateDateColumn, UpdateDateColumn } from 'typeorm';
export abstract class BaseEntity {
@ApiProperty()
@CreateDateColumn({ name: 'created_at' })
createdAt: Date;
@ApiProperty()
@UpdateDateColumn({ name: 'updated_at' })
updateAt: Date;
}
新建 src/entities/admin/sys-user.entity.ts
- 在 TypeORM 中,@Entity 装饰器用于定义一个实体类,并将该实体类映射到数据库中的一个特定表。@Entity 装饰器可以接受一个可选的配置对象,其中包含了表名、表选项等属性。
name 属性用于指定实体类映射到数据库表的名称。如果不指定 name 属性,则 TypeORM 默认会将实体类名转换为下划线分隔的表名。例如,如果实体类名为 User,则默认表名为 user。如果指定了 name 属性,则 TypeORM 会将该实体类映射到指定的表名。
定义的属性和sys_user
对应。其他实体类类似。
连接数据库&配置
- 配置连接在
config/configuration
里新增database字段
import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
...
database: {
type: MYSQL_CONFIG.type,
...MYSQL_CONFIG,
entities: [__dirname + '/../**/entities/*.entity.{ts,js}'],
synchronize: true,
logging: ['error'],
timezone: '+08:00', // 东八区
} as MysqlConnectionOptions,
...
- 全局导入
TypeOrmModule
// app.module.ts
TypeOrmModule.forRootAsync({
imports: [ConfigModule, LoggerModule],
useFactory: (
configService: ConfigService<ConfigurationKeyPaths>,
loggerOptions: LoggerModuleOptions,
) => ({
autoLoadEntities: true,
type: configService.get<any>('database.type'),
host: configService.get<string>('database.host'),
port: configService.get<number>('database.port'),
username: configService.get<string>('database.username'),
password: configService.get<string>('database.password'),
database: configService.get<string>('database.database'),
synchronize: configService.get<boolean>('database.synchronize'),
logging: configService.get('database.logging'),
timezone: configService.get('database.timezone'), // 时区
// 自定义日志
logger: new TypeORMLoggerService(
configService.get('database.logging'),
loggerOptions,
),
}),
inject: [ConfigService, LOGGER_MODULE_OPTIONS],
}),
将entities
下 admin
以sys-
开头的实体类导入到SystemModule
中。
这里能使用@/*
导入文件是因为在 tsconfig.json 里加了这个配置:
"paths": {
"@/*": ["src/*"]
}
system.module.ts
import { Module } from '@nestjs/common';
import { SysUserService } from './user/user.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UserController } from './user/user.controller';
import SysUser from '@/entities/admin/sys-user.entity';
import SysRole from '@/entities/admin/sys-role.entity';
import SysUserRole from '@/entities/admin/sys-user-role.entity';
import SysMenu from '@/entities/admin/sys-menu.entity';
import SysDepartment from '@/entities/admin/sys-department.entity';
import SysRoleDepartment from '@/entities/admin/sys-role-department.entity';
@Module({
imports: [
TypeOrmModule.forFeature([
SysUser,
SysRole,
SysUserRole,
SysMenu,
SysDepartment,
SysRoleDepartment,
SysRoleDepartment,
]),
],
providers: [SysUserService],
controllers: [UserController],
})
export class SystemModule {}
路由配置
因为这些权限模块是在 admin 里实现的,所以路由模块配置一个 admin
前缀
文件 admin.module.ts
import { Module } from '@nestjs/common';
import { RouterModule } from '@nestjs/core';
@Module({
imports: [
RouterModule.register([
{
path: 'admin',
children: [{ path: 'system', module: SystemModule }],
},
]),
...
],
...
})
export class AdminModule {}
System 子模块编写
service 类是服务者(@Injectable()注册为一个可以被注入到其他类中的服务), 负责数据存储和检索。所以以下类开发的时候 基本都是围绕“增删改查”的路子来。只要写过一两个基本就掌握了,复杂的可能就是数据库查询的操作了。
1. 部门模块
nest g service modules/admin/system/department
, system.module.ts
会自动导入DepartmentService
- 先通过
@nestjs/typeorm
的@InjectRepository
注入对应的实体类,用于进行数据库操作。
关于新增,使用 save
还是 insert
-
save 方法:当你使用 save 方法时,如果实体已经存在于数据库中(即,实体对象有一个设置了值的 id),则 TypeORM 会执行 UPDATE 操作,如果实体在数据库中不存在(即,实体对象没有设置值的 id 或者 id 在数据库中没有对应的记录),则 TypeORM 会执行 INSERT 操作。
-
insert方法:无论实体是否已经存在于数据库中,insert方法都会尝试执行INSERT操作。如果数据库中已经存在相同id的记录,则会抛出一个错误。
2. 角色模块
nest g service modules/admin/system/role
3. 用户模块
nest g service modules/admin/system/user
4. 菜单模块
nest g service modules/admin/system/menu
鉴权与登录
这里说明一下,使用 JWT 进行身份验证时,盐值(salt)是一种用于加密和解密 JWT 令牌的字符串。盐值可以用于增加 JWT 令牌的复杂度和安全性,以防止攻击者破解 JWT 令牌并篡改或伪造身份验证信息。
NestJS 提供的 Guards 模块、Passport 与 JWT 来完成登录模块的开发。
安装依赖:
pnpm install --save @nestjs/passport passport passport-local
pnpm install --save-dev @types/passport-local