NestJS用户模块CRUD和分页实现

NestJS用户模块CRUD和分页实现

之前我们已经搭建好项目并且链接上了数据库,接下来我们就将user用户模块的CRUD操作给完善一下

模块搭建

👉搭建下面这个文件目录,准备放置用户表相关的操作规则

javascript 复制代码
src\modules\user\dto

👉生成用户相关模块

javascript 复制代码
// 完整命令
nest generate module modules/user --no-spec
nest generate controller modules/user --no-spec
nest generate service modules/user --no-spec

👉搭建用户表对应的实体user.entity.ts

这个时候我们数据库里面还没有任何的用户数据,搭建用户数据表以后增加用户对应的实体表信息

这部分主要就从typeorm引入对应的Entity(实体)PrimaryGeneratedColumn(主键)和Column(列表)即可,这样子稍后就可以跟我们实体表一一对应

javascript 复制代码
// user.entity.ts

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity('sys_user')
export class User {
  @PrimaryGeneratedColumn({ name: 'user_id' }) // 设置主键列
  userId: number;

  @Column({ nullable: true, name: 'username', comment: '用户的登录账号' })
  username: string;

  @Column({ length: 255, charset: 'utf8mb3', default: '123456', comment: '用户的登录密码' })
  password: string;

  @Column({ nullable: true, length: 255, charset: 'utf8mb3', comment: '姓名' })
  name: string;

  @Column({ nullable: true, length: 255, charset: 'utf8mb3', comment: '年龄' })
  age: string;

  @Column({ nullable: true, type: 'int', comment: '用户性别 1男 2女' })
  sex: number;

  @Column({ nullable: true, type: 'datetime', comment: '创建时间' })
  createTime: Date;

  @Column({ nullable: true, length: 255, charset: 'utf8mb3', comment: '用户的地址' })
  address: string;

  @Column({ nullable: true, type: 'tinyint', comment: '1 正常 0 2 禁用' })
  state: number;

  @Column({ nullable: true, length: 255, charset: 'utf8mb3', comment: '手机号' })
  phone: string;

  @Column({ nullable: true, length: 255, charset: 'utf8mb3', comment: '头像地址' })
  avatar: string;
  disease: string;
}

👉app.module.ts引入

在根目录之中引入了用户模块,上面的命令会帮我们自动生成

javascript 复制代码
import { UserModule } from './modules/user/user.module';

@Module({
  imports: [
    TypeOrmModule.forRoot(typeOrmConfig), 
    UserModule, //用户模块
  ],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

👉搭建user.module.ts

这部分主要帮助我们合拢整个user模块

javascript 复制代码
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UserService } from './user.service';
import { UserController } from './user.controller';

@Module({
  imports: [TypeOrmModule.forFeature([User])],  // 导入实体
  controllers: [UserController],               // 注册控制器
  providers: [UserService],                    // 注册服务
})
export class UserModule {}

👉搭建user.controller.ts

user.controller.ts主要控制用户的接口,并且返回用户操作方法,这部分写入userService.ts之中

javascript 复制代码
import { Controller, Get, Post, Param, Body, Put, Delete } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from './user.entity';

// 定义接口,支持泛型
interface AppServiceResponse<T> {
  code: number;
  data?: T;
  message: string;
}

// 返回数据格式
interface UserResponse<T> {
  code: number;
  data?: T;
  message: string;
}
// 创建用户
class CreateUserDTO {
  readonly _id: string;
  readonly user_name: string;
  readonly password: string;
}
@Controller()
export class UserController {
  constructor(private readonly userService: UserService) {}
}

👉搭建userService.ts

javascript 复制代码
import { Injectable ,ConflictException,HttpException, HttpStatus} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
import * as bcrypt from 'bcryptjs';
interface ResponseData<T> {
  data: T;// data 是泛型 T 类型,这里 T 会是 User
  message: string; // message 是字符串类型
  code: number;    // code 是数字类型
}
@Injectable()
export class UserService {
  constructor(
    @InjectRepository(User)
    private userRepository: Repository<User>,
  ) {}
}

新增用户

基础的结构搭建好了以后,接下来我们先从新增开始做起,写用户的新增模块

👉user.controller.ts

增加对应的用户新增接口时调用的方法addOne

typescript 复制代码
// 新增用户
  @Post('/system/user')
  async addOne(
    @Body('username') username: string,
    @Body('password') password: string,
  ) {
    return this.userService.addOne(username, password);
}

👉user.service.ts

写好新增用户时候的方法addOne

javascript 复制代码
// 增加用户服务(User Service)
async addOne(username: string,password:string){
  const user = this.userRepository.create({ username,password}); // 创建一个新用户
  return this.userRepository.save(user);
}

👉测试新增接口

这个时候我们测试已经有数据了,调用[http://localhost:8888/api/system/user](http://localhost:8888/api/system/user)的post方式

javascript 复制代码
{
    "userId": 8,
    "username": "111",
    "password": "111",
    "name": null,
    "age": null,
    "sex": null,
    "createTime": null,
    "address": null,
    "state": null,
    "phone": null,
    "avatar": null,
    "updateTime": null,
    "userHeight": null,
    "userWeight": null,
    "disease": null
}

上面数据还比较简单,所以我们要根据自己的需求规范一下返回的数据格式,完善一下,新增ok

javascript 复制代码
return {
  message: '添加成功!',
  code: 200,
};

查询用户

👉user.controller.ts

增加对应的用户查询接口时调用findAll

typescript 复制代码
// 获取所有用户
  @Get('/system/user')
  async getAll(){
    return this.userService.getAll();
  }

👉user.service.ts

javascript 复制代码
async getAll(){
  // 调用userRepository的find方法,返回一个User数组
  const user = this.userRepository.find();
  return {
    message: '查询成功!',
    code: 200,
    data: user, // 返回查询到的用户数据
  };
}

👉测试接口

这个时候我们测试返回如下

javascript 复制代码
{
    "message": "查询成功!",
    "code": 200,
    "data": {}
}

这里面的data是空的,这是因为我们没有规范好对应的数据,这里我们规范一下想要返回的数据格式

javascript 复制代码
export interface ResponseDto<T> {
  code: number;
  message?: string;
  data: T;
  total?: number;
}


//重新定义一下服务返回的数据在user.service.ts中
async getAll(): Promise<ResponseDto<User[]>>{
  // 调用userRepository的find方法,返回一个User数组
  const user = await this.userRepository.find();
  return {
    message: '查询成功!',
    code: 200,
    data: user, // 返回查询到的用户数据
    total: user.length,
  };
}

再次查询数据正常

javascript 复制代码
{
    "message": "查询成功!",
    "code": 200,
    "data": [
        {
            "userId": 1,
            "username": "XXX",
            "password": "XXX",
            "name": "11111",
            "age": "18",
            "sex": 1,
            "createTime": null,
            "address": "11111",
            "state": null,
            "phone": "123456",
            "avatar": null,
            "updateTime": null,
            "userHeight": null,
            "userWeight": null,
            "disease": null
        },
        .....
    ],
    "total": 12
}

查询用户信息

👉user.controller.ts

javascript 复制代码
 // 查询单个用户
  @Get('/system/user/:id')
  async getOne(@Param('id') id: string){
    return this.userService.getOne(id);
  }

👉user.service.ts

javascript 复制代码
async getOne(id){
    try {
      // 查询用户,确保 id 与数据库字段类型一致
      const user = await this.userRepository.findOne({ where: { userId: id } });

      // 如果找不到用户,返回 404 错误
      if (!user) {
        return {
          code: 404,
          message: '用户不存在',
          data: null, // 当用户不存在时,data 返回 null
        };
      }

      // 如果找到用户,返回 200 和用户数据
      return {
        code: 200,
        message: '查询成功',
        data: user, // 返回找到的用户数据
      };
    } catch (error) {
      // 捕获并返回数据库查询中的异常
      return {
        code: 500,
        message: '服务器内部错误',
        data: null,
      };
    }
  }

👉测试接口

javascript 复制代码
{
    "code": 200,
    "message": "查询成功",
    "data": {
        "userId": 1,
        "username": "12",
        "password": "XXX",
        "name": "XXX",
        "age": "18",
    }
}

修改提交用户信息

👉user.controller.ts

javascript 复制代码
 // 更新用户
  @Put('/system/user')
  async updateUser(
    // @Param('id') id: number,
    @Body('id') id: number,
    @Body('username') username: string,
    @Body('password') password: string,
    @Body('name') name: string,
    @Body('age') age: number,
    @Body('address') address: number,
  ) {
    return this.userService.updateUser(id, username, password, name,age,address);
  }

👉user.service.ts

javascript 复制代码
 // 修改
  async updateUser(id,username, password,name,age,address){
      const user = await this.userRepository.findOne({ where: { userId:id } });
      if (!user) {
        return {
          code: 404,
          message: '用户不存在!',
          data: null,
        };
      }
      user.username = username;
      user.name = name;
      user.password = password;
      user.age = age;
      user.address = address;
      const updatedUser = await this.userRepository.save(user);
      return {
        code: 200,
        message: '更新成功',
        // data: updatedUser,
      };
  }

👉测试接口

javascript 复制代码
{
    "code": 200,
    "message": "更新成功",
}

删除用户信息

👉user.controller.ts

javascript 复制代码
 // 删除用户
  @Delete('/system/user/:id')
  async deleteUser(@Param('id') id: number){
    return this.userService.deleteUser(id);
  }

👉user.service.ts

javascript 复制代码
// 删除
  async deleteUser(id: number){
    const delUser = await this.userRepository.delete(id);
    if(delUser){
      return {
        code: 200,
        message: '删除成功',
        // data: updatedUser,
      };
    }
    return {
      code: 401,
      message: '删除失败',
      // data: updatedUser,
    };
  }

👉测试接口

javascript 复制代码
{
    "code": 200,
    "message": "删除成功",
}

分页信息

👉user.controller.ts

javascript 复制代码
import { Query} from '@nestjs/common';

// 获取所有用户分页
@Get('/system/user')
async getAll(
  @Query('pageNum') pageNum = 1,  // 默认第1页
  @Query('pageSize') pageSize= 10, // 默认每页10条
) {
  return this.userService.getAll(pageNum, pageSize);
}

👉user.service.ts

javascript 复制代码
// 查询所有用户-User Service
async getAll(pageNum: number = 1, pageSize: number = 10): Promise<ResponseDto<User[]>>{
   // 设置分页的偏移量和限制
  // const skip = (pageNum - 1) * pageSize // 偏移量 (页码从 1 开始)
  
  // 使用 find 方法查询分页数据,skip 和 take 分别控制数据的偏移和返回数量
  const [users, total] = await this.userRepository.findAndCount({
    skip:(pageNum - 1) * pageSize, // 偏移量
    take: pageSize, // 每页返回的数据数量
  });
  const totalPages = Math.ceil(total / pageSize);
  // 调用userRepository的find方法,返回一个User数组
  const user = await this.userRepository.find();
  return {
    message: '查询成功!',
    code: 200,
    data: users, // 返回查询到的用户数据
    total: total,
  };
}

👉测试接口

这个时候我们的分页参数和返回的数据格式也已经正确了

javascript 复制代码
{
    "message": "查询成功!",
    "code": 200,
    "data": [
        {
            "userId": 1,
            "username": "123456",
            "password": "11111111",
            "name": "11111",
            "age": "18",
            "sex": 1,
            "createTime": null,
            "address": "11111",
            "state": null,
            "phone": "123456",
            "avatar": null,
            "updateTime": null,
            "userHeight": null,
            "userWeight": null,
            "disease": null
        },
    ],
    "total": 11
}
相关推荐
mldong7 小时前
你的 Vue3 项目也能有钉钉同款审批流设计器:npm 装包,10 分钟画出第一条审批流
前端·vue.js
2分钟速写快排8 小时前
什么是 RAG?如何用 RAG 实现一个用户记忆?
前端·后端·ai编程
passerby60618 小时前
如何自己造一个时间处理库
前端·javascript·github
走到天涯海角9 小时前
react里面的长列表渲染优化
前端·react.js·前端框架
小羊没烦恼!9 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
北岛贰10 小时前
迷茫焦虑期,我做了一个带支付带官网的 AI 聊天虚拟恋人 App
前端·人工智能·后端
mayaairi11 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js
kyriewen12 小时前
面试官问我:AI 都能写代码了,前端凭什么还值 25K
前端·javascript·人工智能
风骏时光牛马12 小时前
AI源码分析:拆解模型底层实现逻辑
前端
BillKu13 小时前
全局样式变量:CSS 自定义属性(--border-color)和SCSS 变量($border-color)的说明
javascript·css·scss