Skip to content
nestjs完整增删改查(含jwt认证,md5加密,异常捕获和管道验证以及拦截器使用)

1.创建项目

js
nest new 项目名

2.下载和创建各种需要的包

项目依赖包

js
// 连接mysql
yarn add @nestjs/typeorm typeorm mysql2
// 以下两个是关于管道验证的模块
yarn add class-validator class-transformer
// jwt认证包模块
yarn add @nestjs/jwt
// md5密码加密
yarn add md5

nest内置模块包

js
// 创建含有CURD的模块包
nest g res yiyuan
// 创建jwt的验证守卫模块(可以校验token是否过期)
nest g guard yiyuan
// 创建异常捕获过滤器模块
nest g filter yiyuan
// 创建拦截器模块,拦截所有请求并响应
nest g interceptor yiyuan

3.创建三个公共模块(里面代码可以复用,简单来说就是把这三个模块当成工具包就行)

1.jwt校验token是否过期在刚刚创建的yiyuan.guard.ts里面直接放入以下代码即可

js
import {
  CanActivate,
  ExecutionContext,
  Inject,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { Observable } from 'rxjs';

@Injectable()
export class YiyuanGuard implements CanActivate {
  // 注入jwt
  @Inject(JwtService)
  private jwtservice: JwtService;

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    // 接下来就是逻辑问题
    const request: Request = context.switchToHttp().getRequest();
    const authorization = request.header('authorization') || '';
    const bearer = authorization.split(' ');
    if (!bearer || bearer.length < 2) {
      throw new UnauthorizedException('登陆token有误');
    }
    const token = bearer[1];
    try {
      console.log('token', token);
      this.jwtservice.verify(token);
      // (request as any).username = info.username;
      return true;
    } catch (e) {
      throw new UnauthorizedException('登陆token失败,请重新登陆');
    }
  }
}

2.异常捕获过滤器在刚刚生成的yiyuan.filter.ts里面直接插入以下代码即可

js
import {ArgumentsHost,Catch, ExceptionFilter, HttpException} from '@nestjs/common';

@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
  catch(exception: HttpException, host: ArgumentsHost) {
    const ctx = host.switchToHttp(); // 获取请求上下文
    const response = ctx.getResponse(); // 获取请求上下文中的 response对象
    const status = exception.getStatus(); // 获取异常状态码

    // 设置错误信息
    const message = exception.message
      ? exception.message
      : `${status >= 500 ? 'Service Error' : 'Client Error'}`;
    const errorResponse = {
      data: {},
      message: message,
      code: -1,
    };

    // 设置返回的状态码, 请求头,发送错误信息
    response.status(status);
    response.header('Content-Type', 'application/json; charset=utf-8');
    response.send(errorResponse);
  }
}

3.请求拦截器在刚刚创建的yiyuan.interceptor.ts里面直接插入以下代码即可

js
import {CallHandler, ExecutionContext, Injectable,NestInterceptor,} from '@nestjs/common';
import { map, Observable } from 'rxjs';

@Injectable()
export class TransformInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    return next.handle().pipe(
      map((data) => {
        return {
          data,
          code: 0,
          msg: '请求成功',
        };
      }),
    );
  }
}

以上三个其中的异常过滤器和请求拦截器需要在main.ts注册一下,代码如下

js
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { HttpExceptionFilter } from './yiyuan/yiyuan.filter'; //引入异常过滤器
import { TransformInterceptor } from './yiyuan/yiyuan.interceptor'; //引入请求拦截器

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe());
  app.useGlobalFilters(new HttpExceptionFilter()) // 注册异常过滤器
  app.useGlobalInterceptors(new TransformInterceptor()) //注册请求拦截器
  await app.listen(3000);
}
bootstrap();

关于jwt认证这个包的使用方式,点我直达:第一个使用的地方关于jwt认证这个包的使用方式,点我直达:第二个使用的地方

4.以上的前置准备做完以后,接下来直接上手项目

1.在app.module.ts里面连接数据库

js
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { YiyuanModule } from './yiyuan/yiyuan.module';
@Module({
  imports: [
    TypeOrmModule.forRoot({
      type: 'mysql',
      host: 'localhost',
      port: 3306,
      username: 'root',
      password: 'admin',
      database: 'shop',
      autoLoadEntities: true,
      synchronize: true,
    }),
    YiyuanModule,
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

2.在yiyuan.entity.ts里面创建实体类

js
import {
  Entity,
  Column,
  PrimaryGeneratedColumn,
  CreateDateColumn,
  UpdateDateColumn,
} from 'typeorm';
@Entity()
export class Yiyuan {
  @PrimaryGeneratedColumn({ comment: '自增id主键' })
  id: number;

  @Column({ comment: '用户名' })
  username: string;

  @Column({ comment: '密码' })
  password: string;

  @CreateDateColumn({ comment: '创建时间' })
  createTime: Date;

  @UpdateDateColumn({ comment: '更新时间' })
  updateTime: Date;

  @Column({ default: false })
  isActive: boolean; // 修改用户权限(true为有权限,false为无权限)
}

3.在yiyuan.module.ts进行引入

(这里是使用jwt的第一个地方,在这里定义jwt的秘钥和过期时间)

js
import { Module } from '@nestjs/common';
import { YiyuanService } from './yiyuan.service';
import { YiyuanController } from './yiyuan.controller';
import { Yiyuan } from './entities/yiyuan.entity';
import { TypeOrmModule } from '@nestjs/typeorm';
import { JwtModule } from '@nestjs/jwt';
@Module({
  imports: [TypeOrmModule.forFeature([Yiyuan]),JwtModule.register({
    secret:'123456', //秘钥
    signOptions:{
      expiresIn:"60h" // 过期时间,这个是60小时
    }
  })],
  controllers: [YiyuanController],
  providers: [YiyuanService],
})
export class YiyuanModule {}

4.在dto里面进行数据校验

create-yiyuan.dto.ts里面代码如下

js
import { IsNotEmpty } from 'class-validator';
export class CreateYiyuanDto {
  id: number;
  // 登录
  @IsNotEmpty({ message: '缺少用户名信息' })
  username: string;
  @IsNotEmpty({ message: '缺少密码' })
  password: string;
  isActive: boolean;
}

update-yiyuan.dto.ts里面代码如下

js
import { IsNotEmpty } from 'class-validator';
export class UpdateYiyuanDto {
  @IsNotEmpty({ message: '缺少id' })
  id: number;
}

这里的class-validator在前面我们是已经安装过了,这里使用完需要到main.js去注册一下,否则不会起作用,代码如下

js
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';
import { HttpExceptionFilter } from './yiyuan/yiyuan.filter'; 
import { TransformInterceptor } from './yiyuan/yiyuan.interceptor';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.useGlobalPipes(new ValidationPipe()); // 注册管道进行验证数据
  app.useGlobalFilters(new HttpExceptionFilter()) 
  app.useGlobalInterceptors(new TransformInterceptor()) 
  await app.listen(3000);
}
bootstrap();

5.在yiyuan.controller.ts创建路由

这里是jwt的第二个地方PS:jwt的验证在这里使用,在哪个接口上面使用了@UseGuards(YiyuanGuard)哪个接口就必须使用带有token的header进行请求,否则在jwt的验证里面直接返回了,其中YiyuanGuard为上面创建的工具守卫

js
import {
  Controller,
  Get,
  Post,
  Body,
  Patch,
  Param,
  Delete,
  Query,
  HttpException,
  UseGuards,
} from '@nestjs/common';
import { YiyuanService } from './yiyuan.service';
import { CreateYiyuanDto } from './dto/create-yiyuan.dto';
import { UpdateYiyuanDto } from './dto/update-yiyuan.dto';
import { YiyuanGuard } from './yiyuan.guard';
@Controller('yiyuan')
export class YiyuanController {
  constructor(private readonly yiyuanService: YiyuanService) {}

  // 注册
  @Post('/reg')
  reg(@Body() regyiyuan: CreateYiyuanDto) {
    console.log('regyiyuan', regyiyuan);
    return this.yiyuanService.regyy(regyiyuan);
  }

  // 登录
  @Post('/login')
  create(@Body() user: CreateYiyuanDto) {
    console.log('user', user);
    return this.yiyuanService.login(user);
  }

  // 查询所有用户
  @Get('/selete')
  @UseGuards(YiyuanGuard)
  findAll(@Query() query: any) {
    // 前面一个是跳过多少页,后面那个是当前页面
    return this.yiyuanService.findAll(query.current, query.pagesize);
  }

  // 修改用户权限
  @Post('/quanxian')
  @UseGuards(YiyuanGuard)
  update(@Body() quanxian: UpdateYiyuanDto) {
    return this.yiyuanService.qx(quanxian);
  }

  // 删除指定用户
  @Post('/delete')
  @UseGuards(YiyuanGuard)
  remove(@Body() deleteuser: any) {
    if (deleteuser.id) {
      return this.yiyuanService.remove(deleteuser.id);
    } else {
      throw new HttpException('未传入用户id,删除失败', 200);
    }
  }
}

6.yiyuan.service.ts添加业务逻辑代码

js
import { HttpException, Injectable } from '@nestjs/common';
import { CreateYiyuanDto } from './dto/create-yiyuan.dto';
import { UpdateYiyuanDto } from './dto/update-yiyuan.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Yiyuan } from './entities/yiyuan.entity';
import { JwtService } from '@nestjs/jwt';
import * as md5 from 'md5';
import { BrowSe } from './entities/browse.entity';
@Injectable()
export class YiyuanService {
  constructor(
    @InjectRepository(Yiyuan) private yiyuan: Repository<Yiyuan>,
    private jwtService: JwtService,
  ) {}
  async regyy(updateYiyuanDto: CreateYiyuanDto) {
    console.log('updateYiyuanDto', updateYiyuanDto); //拿到了参数信息
    // 查找数据库是否有此信息
    const finduser = await this.yiyuan.find({
      where: {
        username: updateYiyuanDto.username,
      },
    });
    if (finduser.length > 0) {
      throw new HttpException('用户已存在', 200);
    } else {
      // 注册新用户
      const newuser = new Yiyuan(); // 创建新对象
      // 将传来的数据赋值给新对象
      newuser.username = updateYiyuanDto.username;
      newuser.password = md5(updateYiyuanDto.password);
      await this.yiyuan.save(newuser); // 对数据进行保存
      return {
        message: '注册用户成功',
      };
    }
  }
  async login(createYiyuanDto: CreateYiyuanDto) {
    // 登录
    // 查找数据库是否有此信息
    const finduser = await this.yiyuan.findOne({
      where: {
        username: createYiyuanDto.username,
      },
    });
    if (finduser) {
      let obj = {};
      if (md5(createYiyuanDto.password) == finduser.password) {
        return {
          user: {
            id: finduser.id,
            username: finduser.username,
            createTime: finduser.createTime,
            updateTime: finduser.updateTime,
            isActive: finduser.isActive,
          },
          token: this.jwtService.sign({
            id: finduser.id,
            username: finduser.username,
          }),
        };
      } else {
        return {
          message: '密码错误',
        };
      }
    } else {
      throw new HttpException('用户未注册,请先注册', 200);
    }
  }

  // 修改用户权限
  async qx(quanxian: UpdateYiyuanDto) {
    // 传入用户名即可修改
    const finduser = await this.yiyuan.findOne({
      where: {
        id: quanxian.id,
      },
    });
    console.log('finduser', finduser);
    if (finduser) {
      const user = new Yiyuan(); // 创建对象
      user.id = finduser.id; // 指定要修改的数据id
      user.isActive = !finduser.isActive;
      await this.yiyuan.save(user);
      return {
        message: '修改成功',
      };
    } else {
      throw new HttpException('未查询到此用户,修改失败', 200);
    }
  }

  // 参数一每页数量,参数二:当前页数
  findAll(current = 15, pagesize = 1) {
    console.log('current,pagesize', current, pagesize);
    // 查询所有用户信息
    return this.yiyuan.findAndCount({
      skip: (pagesize - 1) * current, // 跳过多少页
      take: current, // 当前页数的数量
      select: ['id', 'username', 'createTime', 'updateTime', 'isActive'], //指定返回的字段,将密码排除在外了
    });
  }

  // 删除用户
  async remove(id: number) {
    console.log('id', id);
    // 直接传入id即可删除了
    let res = await this.yiyuan.delete(id);
    if (res.affected > 0) {
      return { success: '删除成功' };
    } else {
      return { error: '删除失败' };
    }
  }
}