当前位置: 首页 > news >正文

Nest全栈到失业(三):半小时图书管理系统-User

用户模块

创建用户

        先使用nest g resource user --no-spec 创建一个用户的模块,并选择他的CRUD操作

        写一个注册接口

import { Controller, Post, Body } from '@nestjs/common';
import { UserService } from './user.service';
import { RegisterUserDto } from './dto/register-user.dto';@Controller('user')
export class UserController {// 注入user服务constructor(private readonly userService: UserService) {}@Post('register')create(@Body() registerUserDto: RegisterUserDto) {console.log(registerUserDto);return 'done';}
}

        编写dto对象,就是数据传输对象,你前端给来的数据,需要是什么叫结构的,有哪些字段

export class RegisterUserDto {username: string;password: string;
}

        测试,拿到数据了

数据校验

        我们使用pipe管道的方式,结合第三方的库实现数据的校验,这是两个包

npm install --save class-transformer class-validator
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { ValidationPipe } from '@nestjs/common';async function bootstrap() {const app = await NestFactory.create(AppModule);// 使用全局的管道校验数据,并转为dtoapp.useGlobalPipes(new ValidationPipe({ transform: true }));await app.listen(process.env.PORT ?? 3000);
}bootstrap();

dto中限制

import { IsNotEmpty, MinLength } from 'class-validator';export class RegisterUserDto {@IsNotEmpty({ message: '用户名不能为空' })username: string;@IsNotEmpty({ message: '密码不能为空' })@MinLength(6, { message: '密码最少 4 位'})password: string;
}

测试

如果你的数据没有问题,就可以接到dto对象了

数据持久化

        怎么办?还能怎么办,使用mysql呗

        我们使用docker拉去mysql镜像,并创建一个新的数据库容器

 

不管你用什么方式,使用navicat也好,什么都行.连接到数据库,我使用的是webstorm全家桶的dataGrip 创建一个数据库

我们使用typeorm链接数据库,使用mysql2来做项目的转接

npm i --save @nestjs/typeorm  typeorm mysql2  @types/node

使用最简单的方式(动态模块)链接数据库,因为我们的app模块是我们的默认必须的入口,所以直接在里边写链接mysql的动态配置吧

//app.module.ts
import { Module } from '@nestjs/common';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { UserModule } from './user/user.module';
import { TypeOrmModule, TypeOrmModuleOptions } from '@nestjs/typeorm';
import { User } from './user/entities/user.entity';@Module({imports: [UserModule,TypeOrmModule.forRoot({type: 'mysql', //什么类型的数据库host: 'localhost', //端口ipport: 3306, //端口username: 'root', //用户名password: 'root', //密码database: 'book-end', //操作的数据库entities: [User], //注入那些实体synchronize: true, //同步构建数据库,真实开发千万别开logging: true, //日志打印等级connectorPackage: 'mysql2', //加密extra: {authPlugin: 'sha256_password', //加密},} as TypeOrmModuleOptions)],controllers: [AppController],providers: [AppService],
})
export class AppModule {
}

当然,在执行前,我们要写好自己的实体src/user/entities/user.entity.ts

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';@Entity()
export class User {// 定义自增的主键@PrimaryGeneratedColumn()id: number;// 定义其他特殊列@Column()username: string;@Column()password: string;
}

运行项目,npm run start:dev即可,它会自动链接数据库,并自动初始化数据库

测试一下吧?

我们在user.moudle中注入user这个实体,然后,我们在服务中使用一下 

写一个路由

  @Get()findAll(): Promise<User[]> {return this.userService.getAll();}

对应的操作数据库表的方法

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';@Injectable()
export class UserService {constructor(// 使用仓库管理器方式,注入我们的数据库中的表@InjectRepository(User) private userRepository: Repository<User>) {}getAll(){return this.userRepository.find()}}

你一查,什么也没有,原因是,刚刚没链接数据,我们创建的,现在新创建的数据库,还没有数据呢,所以先注册再查询

因为我们有了数据库,所以创建用户也改改

  // post请求@Post('register')// 使用接收body数据  ,数据必须符合registerUserDto的结构create(@Body() registerUserDto: RegisterUserDto) {return this.userService.create(registerUserDto)}
//报存到数据库create(registerUserDto: RegisterUserDto) {return this.userRepository.save(registerUserDto);}

然后你在查询就有了

走看看数据库去

 这里我们没有做重复校验,其实很简单的,就是你创建的时候,先按照用户名的方式再数据库里查一遍,就好了

完善代码

其实一个模块无非就是几个点

创建实体

首先是我们创建了一个实体

那么你就要再使用实体的module中注入他

import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';@Entity()
export class User {// 定义自增的主键@PrimaryGeneratedColumn()id: number;// 定义其他特殊列@Column()username: string;@Column()password: string;
}
import { Module } from '@nestjs/common';
import { UserService } from './user.service';
import { UserController } from './user.controller';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './entities/user.entity';@Module({// 注入实体imports: [TypeOrmModule.forFeature([User])],controllers: [UserController],providers: [UserService],
})
export class UserModule {
}

分发路由

我们写好了实体,就去看看需要那些接口,写一写,当然了,我们的逻辑是不会写在contorller中的

import { Controller, Post, Body, Get } from '@nestjs/common';
import { UserService } from './user.service';
import { RegisterUserDto } from './dto/register-user.dto';
import { User } from './entities/user.entity';
import { LoginUserDto } from './dto/login-user.dto';@Controller('user')
export class UserController {// 注入user服务constructor(private readonly userService: UserService) {}@Get()findAll(): Promise<User[]> {return this.userService.getAll();}// post请求@Post('register')// 使用接收body数据  ,数据必须符合registerUserDto的结构create(@Body() registerUserDto: RegisterUserDto) {return this.userService.create(registerUserDto);}// 登录@Post('login')login(@Body() loginUserDto: LoginUserDto) {return this.userService.login(loginUserDto);}
}

预写dto

就是我们的数据传输对象,说白了就是ts的接口,规定了你的结构和规范

import { IsNotEmpty, MinLength } from 'class-validator';export class RegisterUserDto {@IsNotEmpty({ message: '用户名不能为空' })username: string;@IsNotEmpty({ message: '密码不能为空' })@MinLength(6, { message: '密码最少 4 位'})password: string;
}
import { IsNotEmpty, MinLength } from 'class-validator';export class LoginUserDto {@IsNotEmpty({ message: '用户名不能为空' })username: string;@IsNotEmpty({ message: '密码不能为空' })@MinLength(6, { message: '密码最少 4 位'})password: string;
}

编写服务

只有注入了实体,然后你才可以再service中使用他

这里的注册和登录我写了几个内容哈

第一是我们注册之前,要看看数据库中有没有数据,避免重复

第二,我们注册成功的时候,,我把密码加密处理放在数据库了,参考 bcrypt 包

第三,我们登录的时候,我不仅看看有没有存在用户,其次,我把密码进行加密和数据库中加密密码做了比对

import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './entities/user.entity';
import { RegisterUserDto } from './dto/register-user.dto';
import { LoginUserDto } from './dto/login-user.dto';// 信息加密包
import * as bcrypt from 'bcrypt';@Injectable()
export class UserService {constructor(// 使用仓库管理器方式,注入我们的数据库中的表@InjectRepository(User) private userRepository: Repository<User>) {}// 写一个查询用户是否存在的公共逻辑async findUser(registerUserDto: RegisterUserDto): Promise<boolean> {// 先查询用户是否存在const findUser = await this.userRepository.findOne({where: {username: registerUserDto.username,},});// 存在报错if (findUser) {throw new HttpException(`用户已存在了`, HttpStatus.CONFLICT);}return false;}// 查询所有用户getAll() {return this.userRepository.find();}// 创建用户async create(registerUserDto: RegisterUserDto) {// 看看存在不await this.findUser(registerUserDto);// 不存在的处理const user = new User();// 这里不用搞id,因为在实体里,id是自增量的主键user.username = registerUserDto.username;// user.password = registerUserDto.password;// 重新加密密码user.password = await bcrypt.hash(registerUserDto.password, 10);// 写入数据库await this.userRepository.save(user);return {status: HttpStatus.CREATED,message: '用户创建成功',user,};}async login(loginUserDto: LoginUserDto) {const user = await this.userRepository.findOne({where: {username: loginUserDto.username,},});// 用户不存在if (!user) {throw new HttpException(`用户不存在`, HttpStatus.NOT_FOUND);}// 校验密码// const isPasswordValid = user.password === loginUserDto.password;// if (!isPasswordValid) {//   throw new HttpException(`密码错误`, HttpStatus.UNAUTHORIZED);// }// 解密密码,并且自动和login的密码校验了const bcryptPassWord = await bcrypt.compare(loginUserDto.password, user.password);if (!bcryptPassWord) {throw new HttpException(`密码错误`, HttpStatus.UNAUTHORIZED);}return {status: HttpStatus.OK,message: '登录成功',user,};}}

最后测试

查询所有用户

注册用户

测试登录

 

用户不存在

密码不对

 登陆成功

当然了,其实一个用户模块不仅如此,后续你为了实现RBAC权限控制,你还要写很多东西,包括使用redis做缓存查询,等等等,当然了,我们操作数据库的方式,这是最简单的,不涉及任何的多表查询操作,事务等,因为你页用不了,你得用别的方式才可以更加灵活的深层次的操作数据库数据

慢慢看吧

http://www.xdnf.cn/news/711451.html

相关文章:

  • Ubuntu 22.04 上安装 PostgreSQL(使用官方 APT 源)
  • CRMEB 单商户Java版 v2.3公测版发布,欢迎体验!
  • 收集飞花令碎片——C语言(数组+函数)
  • 酷派Cool20/20S/30/40手机安装Play商店-谷歌三件套-GMS方法
  • 小程序为什么要安装SSL安全证书
  • LeetCode 55 45:跳跃游戏与跳跃游戏 II - 贪心算法详解
  • 前端开发中 <> 符号解析问题全解:React、Vue 与 UniApp 场景分析与解决方案
  • 题目 3298: 蓝桥杯2024年第十五届决赛真题-兔子集结
  • WPF log4net用法
  • STM32 AD单通道与多通道实战指南
  • 【QT】理解QT的“元对象系统”
  • 【Tips】关于PCI和PCIe的配置空间差异和io/memory io读写
  • 【CF】Day69——⭐Codeforces Round 897 (Div. 2) D (图论 | 思维 | DFS | 环)
  • Redis--基础知识点--28--慢查询相关
  • 【ConvLSTM第二期】模拟视频帧的时序建模(Python代码实现)
  • CppCon 2014 学习第4天:Transactional Language Constructs for C++ TS(未进入到标准)
  • RDS PostgreSQL手动删除副本集群副本的步骤
  • 58同城C++开发面试题及参考答案
  • OpenCV CUDA模块结构分析与形状描述符------计算指定阶数的矩(Moments)所需的总数量函数:numMoments
  • json转成yolo用的txt(json中没有宽高,需要自设宽高的)
  • Mysql数据库 索引,事务
  • 数据库 | 时序数据库选型
  • 物联网常用协议Modbus、CAN、BACnet介绍
  • UniApp X:鸿蒙原生开发的机会与DCloud的崛起之路·优雅草卓伊凡
  • EasyVoice:开源的文本转语音工具,让文字“开口说话“
  • C语言学习笔记四---V
  • Spring官方的在线教程也可以用中文观看了
  • js如何把json对象格式数据快速字符串
  • 长安链合约操作 查询合约命令解析
  • 基于 GitLab CI + Inno Setup 实现 Windows 程序自动化打包发布方案