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

article/2025/8/24 14:54:26

用户模块

创建用户

        先使用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.hkcw.cn/article/ncuXhYZivH.shtml

相关文章

美创专家分享医疗数据安全分类分级实践与探索

医疗数据安全分类分级 近日&#xff0c;由浙江卫生信息学会主办的2025年卫生健康网络数据安全培训会&#xff08;宁波站&#xff09;顺利举办&#xff0c;美创科技专家许钰钢受邀分享《医疗数据安全分类分级实践与探索》&#xff0c;系统解析医疗行业数据安全分类分级的实施必…

Vision Transformer网络结构

0.前言 参考CSDN大佬(太阳花的小绿豆)的代码&#xff0c;梳理了一下vit的网络结构&#xff0c;代码地址如下&#xff1a; deep-learning-for-image-processing/pytorch_classification/vision_transformer at master WZMIAOMIAO/deep-learning-for-image-processing GitHub …

start-local:一键本地启动 Elasticsearch 和 Kibana

start-local&#xff1a;一键本地启动 Elasticsearch 和 Kibana start-local Try Elasticsearch and Kibana locally 项目地址: https://gitcode.com/gh_mirrors/st/start-local 项目介绍 start-local 是一个开源项目&#xff0c;它通过一个简单的 shell 脚本&#xff…

time-ghc-modules:快速定位Haskell编译性能瓶颈

time-ghc-modules&#xff1a;快速定位Haskell编译性能瓶颈 time-ghc-modules Analyze GHC .dump-timings files 项目地址: https://gitcode.com/gh_mirrors/ti/time-ghc-modules 项目介绍 在现代软件开发中&#xff0c;性能优化始终是一个核心话题。特别是对于使用Has…

【Cursor】配置全局 Rules:让 AI 生成的代码更符合你的开发风格

在现代软件开发中,AI 工具(如 Cursor AI)已经成为提升开发效率的重要助手。然而,为了让这些工具生成的代码更加贴合我们的开发习惯和项目需求,合理配置 全局 Rules 是至关重要的一步。本文将深入探讨如何通过全局 Rules 的配置,优化 AI 生成代码的质量、一致性和安全性。…

一文了解K8S(Kubernates)

K8S&#xff08;Kubernates&#xff09; 知识目录 一、K8S 1. 概述 Kubernetes 是一个可移植、可扩展的开源平台&#xff0c;用于管理容器化的工作负载和服务&#xff0c;可促进声明式配置和自动化。 Kubernetes 拥有一个庞大且快速增长的生态&#xff0c;其服务、支持和工具…

手把手教你实现文档搜索引擎

&#x1f3e0;大家好&#xff0c;我是Yui_&#x1f4ac; &#x1f351;如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x1f680;如有不懂&#xff0c;可以随时向我提问&#xff0c;我会全力讲解~ &#x1f52…

使用 LangGraph 和 Elasticsearch 构建强大的 RAG 工作流

作者&#xff1a;来自 Elastic Neha Saini 在这篇博客中&#xff0c;我们将向你展示如何配置和自定义 LangGraph Retrieval Agent 模板与 Elasticsearch&#xff0c;以构建一个强大的 RAG 工作流&#xff0c;实现高效的数据检索和由 AI 驱动的响应。 Elasticsearch 原生集成了…

OpenEvidence AI临床决策支持工具平台研究报告

平台概述 OpenEvidence是一个专为医疗专业人士设计的临床决策支持工具,旨在通过整合各类临床计算器和先进的人工智能技术,提高医生的诊疗决策效率和准确性。作为一款综合性医疗平台,OpenEvidence将复杂的医学计算流程简化,同时提供个性化的临床建议,使医生能够更快、更准…

Python使用FastMCP开发MCP服务端

MCP简介 Model Context Protocol (MCP) 是一个专门为 LLM&#xff08;大语言模型&#xff09;应用设计的协议&#xff0c;它允许你构建服务器以安全、标准化的方式向 LLM 应用程序公开数据和功能。FastMCP 作为 Python 生态中的一款轻量级框架&#xff0c;利用装饰器来简化路由…

【科研绘图系列】R语言绘制GO term 富集分析图(enrichment barplot)

禁止商业或二改转载,仅供自学使用,侵权必究,如需截取部分内容请后台联系作者! 文章目录 介绍加载R包数据下载导入数据数据预处理画图code 2code 3系统信息介绍 本文介绍了使用R语言绘制GO富集分析条形图的方法。通过加载ggplot2等R包,对GO term数据进行预处理,包括p值转换…

利用Flask来实现留言板的基本操作

留言板开发 一、相关技术介绍 本项目基于现代Web开发技术栈构建&#xff0c;采用Python 3.12作为后端开发语言&#xff0c;搭配轻量级Flask 2.3.2框架实现核心功能。数据库层使用Flask-SQLAlchemy ORM框架操作MySQL 8.0数据库&#xff0c;通过对象关系映射简化数据操作。用户…

vue3: tmap (腾讯地图)using typescript

项目结构&#xff1a; <!--* ___-_ _-___* _--^^^#####// \\#####^^^--_* _-^##########// ( ) \\##########^-_* -############// |\^^/| \\############-* _/############// (::) \############\_* …

【Linux】线程概念

&#x1f4dd;前言&#xff1a; 这篇文章我们来讲讲Linux——线程概念&#xff1a; 线程的基本概念线程的优缺点线程与进程 &#x1f3ac;个人简介&#xff1a;努力学习ing &#x1f4cb;个人专栏&#xff1a;Linux &#x1f380;CSDN主页 愚润求学 &#x1f304;其他专栏&am…

技术文档撰写指南:从结构到细节的全流程解析

在技术领域&#xff0c;一份优质的技术文档不仅是项目成果的载体&#xff0c;更是技术思想的可视化表达。本文结合《汽车导航系统电路设计及故障分析》课程设计说明书&#xff0c;拆解技术文档的核心要素&#xff0c;提供可复用的撰写范式&#xff0c;助力技术内容高效传播。 …

如何用AI设计海报,DeepSeek+即梦免费批量生成

大家好&#xff0c;这里是K姐。 一个帮助你把AI真正用起来的女子。 佳节将至&#xff0c;还在为节日海报而苦恼吗&#xff1f; 520刚过&#xff0c;端午节、六一儿童节、618就接踵而至&#xff0c;满街满屏的海报让人眼花缭乱。 做自媒体电商以及实体店的小伙伴现在已经一个…

全国一体化算力体系建设:破解算力困局,赋能数字经济新未来​

在数字经济蓬勃发展的当下&#xff0c;算力作为核心生产力&#xff0c;正面临着前所未有的挑战与机遇。从 GPT3.5 到 GPT4 的升级&#xff0c;算力需求呈现跳跃式增长&#xff0c;需要至少提高 3 到 5 倍的算力&#xff0c;国内算力供应出现断层&#xff0c;难以满足当前需求。…

window安装nginx

步骤1&#xff1a;下载Nginx for Windows​ 访问Nginx官网下载页面&#xff1a;https://nginx.org/en/download.html 在​​Stable version​​&#xff08;稳定版&#xff09;下找到Windows版本&#xff0c;点击下载.zip文件&#xff08;如 nginx-1.28.0.zip&#xff09; 步…

秋招Day11 - JVM - 垃圾回收

讲讲JVM的垃圾回收机制 垃圾回收是指JVM对内存中已经死亡的&#xff0c;不再使用的对象进行清除或回收。 常见的垃圾回收算法有标记-复制&#xff0c;标记-整理&#xff0c;标记-清除&#xff0c;分代收集算法等 一般的垃圾回收。过程是先使用可达性分析算法得出内存中哪些对…

Deepseek应用技巧-Dify安装和踩坑指南

前言&#xff1a;Dify的名号是非常大的&#xff0c;作为私有化AI部署中必不可少的一个组件&#xff0c;他的功能和COZE十分相似&#xff0c;可以进行工作流和智能体的搭建&#xff0c;有非常强大的功能&#xff0c;那本节就将来揭开Dify的神秘的面纱&#xff0c;首先看一下Dify…