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
}
相关推荐
胖方Hale1 分钟前
11. Typescript 泛型
前端·typescript
brzhang5 分钟前
代码Review老被怼?这10个编程好习惯,让你写出同事都点赞的好代码!
前端·后端·架构
几度泥的菜花6 分钟前
优雅实现网页弹窗提示功能:JavaScript与CSS完美结合
开发语言·javascript·css
佳腾_21 分钟前
【Web应用服务器_Tomcat】三、Tomcat 性能优化与监控诊断
前端·中间件·性能优化·tomcat·web应用服务器
brzhang25 分钟前
告别 CURD,走向架构:一份帮你打通任督二脉的知识地图
前端·后端·架构
Moment32 分钟前
在 React 里面实现国际化实现是太简单了 🙂‍↔️🙂‍↔️🙂‍↔️
前端·javascript·react.js
兜小糖的小秃毛33 分钟前
el-Input输入数字自动转千分位进行展示
前端·javascript·vue.js
兜小糖的小秃毛34 分钟前
文号验证-同时对两个输入框验证
开发语言·前端·javascript
brzhang35 分钟前
代码越写越乱?掌握这 5 种架构模式,小白也能搭出清晰系统!
前端·后端·架构
J总裁的小芒果42 分钟前
el-table 自定义列、自定义数据
前端·javascript·vue.js