NestJs 权限管理系统三、system功能开发

233 阅读4分钟

引入数据库

初始化

Mysql 导入 deploy/sql/init.sql

连接

  1. 安装依赖 pnpm install @nestjs/typeorm typeorm mysql2

  2. 新建 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对应。

其他实体类类似。

  1. 配置连接 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,

...

  1. 全局导入 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],

}),

entitiesadminsys-开头的实体类导入到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

  1. 先通过@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