NestJS-聊天模块

NestJS-聊天模块

1、模块文件搭建

javascript 复制代码
nest g controller modules/chat --no-spec
nest g module modules/chat --no-spec
nest g service modules/chat --no-spec

生成的文件

javascript 复制代码
chat.controller.ts
chat.module.ts
chat.service.ts

2、模块实体创建

创建聊天消息实体(Entity): 我们需要定义一个数据库sys_chat表来存储消息

👉sql数据

javascript 复制代码
CREATE TABLE sys_chat (
  chatId INT AUTO_INCREMENT PRIMARY KEY,
  senderId VARCHAR(255) NOT NULL,
  receiverId VARCHAR(255) NOT NULL,
  chatType ENUM('single', 'group') NOT NULL,
  content TEXT NOT NULL,
  messageType ENUM('text', 'image', 'audio', 'video', 'file') NOT NULL,
  status ENUM('sent', 'delivered', 'read') DEFAULT 'sent',
  timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  attachments JSON DEFAULT NULL,
  groupId INT DEFAULT NULL,
  groupName VARCHAR(255) DEFAULT NULL,  -- 添加群组名称字段
  isSystem BOOLEAN DEFAULT FALSE,
  isDeleted BOOLEAN DEFAULT FALSE,
  create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP,  -- 记录创建时间
  update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP -- 记录更新时间,每次更新时自动更新
);

👉 chat.entity.ts

javascript 复制代码
import { Entity, PrimaryGeneratedColumn, Column, UpdateDateColumn, CreateDateColumn } from 'typeorm';

@Entity('sys_chat')
export class SysChat {
  @PrimaryGeneratedColumn()
  chatId: number;

  @Column({ type: 'varchar', length: 255 })
  senderId: string;

  @Column({ type: 'varchar', length: 255 })
  receiverId: string;

  @Column({ type: 'enum', enum: ['single', 'group'] })
  chatType: 'single' | 'group';

  @Column({ type: 'text' })
  content: string;

  @Column({ type: 'enum', enum: ['text', 'image', 'audio', 'video', 'file'] })
  messageType: 'text' | 'image' | 'audio' | 'video' | 'file';

  @Column({ type: 'enum', enum: ['sent', 'delivered', 'read'], default: 'sent' })
  status: 'sent' | 'delivered' | 'read';

  @CreateDateColumn({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
  timestamp: Date;

  @Column({ type: 'json', nullable: true })
  attachments: any;

  @Column({ type: 'int', nullable: true })
  groupId: number;

  @Column({ type: 'varchar', length: 255, nullable: true })
  groupName: string;

  @Column({ type: 'boolean', default: false })
  isSystem: boolean;

  @Column({ type: 'boolean', default: false })
  isDeleted: boolean;

  @CreateDateColumn({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
  create_time: Date;

  @UpdateDateColumn({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP', onUpdate: 'CURRENT_TIMESTAMP' })
  update_time: Date;
}

👉 引入实体和控制器

chat.module.ts导入需要的部分然后进行导出

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';
import { AuthModule } from '@/auth/auth.module';

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

3、模块功能

增加

👉chat.module.ts
javascript 复制代码
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { ChatService } from './chat.service';
import { ChatController } from './chat.controller';
import { SysChat } from './chat.entity';
import { ChatGateway } from './chat.gateway';

@Module({
  imports: [TypeOrmModule.forFeature([SysChat])],
  providers: [ChatService],
  controllers: [ChatController, ChatGateway],
})
export class ChatModule {}
👉 chat.service.ts

这里我们先简单填写一下我们的方法逻辑

javascript 复制代码
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { SysChat } from './chat.entity';
import { CreateChatDto,UpdateChatDto } from './dto/chat.dto';

async create(createChatDto: CreateChatDto): Promise<SysChat> {
  const chat = this.chatRepository.create(createChatDto);
  return this.chatRepository.save(chat);
}
👉chat.controller.ts
javascript 复制代码
// chat.controller.ts

import { Controller, Get, Post, Body, Param, Put, Delete } from '@nestjs/common';
import { ChatService } from './chat.service';
import { CreateChatDto,UpdateChatDto} from './dto/chat.dto';
import { SysChat } from './chat.entity';

@Controller('chat')
export class ChatController {
  constructor(private readonly chatService: ChatService) {}
  // 创建消息
  @Post()
  async create(@Body() createChatDto: CreateChatDto): Promise<SysChat> {
    return this.chatService.create(createChatDto);
  }
}
👉 调用接口

这个时候我们调用接口,返回的信息如下,新增接口就成功了

javascript 复制代码
{
    "chatId": 2,
    "senderUserId": "57",
    "receiverUserId": "user123",
    "chatType": "single",
    "content": "Hello, how are you?",
    "messageType": "text",
    "status": "sent",
    "attachments": null,
    "groupId": null,
    "groupName": null,
    "isSystem": false,
    "isDeleted": false,
    "createTime": "2025-05-13 16:16:13",
    "updateTime": "2025-05-13 16:16:13"
}

查找

👉 chat.service.ts

这里我们先简单填写一下我们的方法逻辑

javascript 复制代码
// 获取所有消息
async findAll(): Promise<SysChat[]> {
  return this.chatRepository.find();
}
👉chat.controller.ts
javascript 复制代码
async findAll(): Promise<SysChat[]> {
  return this.chatService.findAll();
}
👉 调用接口

这个时候我们调用接口,返回的信息如下,查询接口ok

javascript 复制代码
[
    {
        "chatId": 1,
        "senderUserId": "57",
        "receiverUserId": "user123",
        "chatType": "single",
        "content": "Hello, how are you?",
        "messageType": "text",
        "status": "sent",
        "attachments": null,
        "groupId": null,
        "groupName": null,
        "isSystem": false,
        "isDeleted": false,
        "createTime": "2025-05-13 16:15:09",
        "updateTime": "2025-05-13 16:15:09"
    },
    {
        "chatId": 2,
        "senderUserId": "57",
        "receiverUserId": "user123",
        "chatType": "single",
        "content": "Hello, how are you?",
        "messageType": "text",
        "status": "sent",
        "attachments": null,
        "groupId": null,
        "groupName": null,
        "isSystem": false,
        "isDeleted": false,
        "createTime": "2025-05-13 16:16:13",
        "updateTime": "2025-05-13 16:16:13"
    }
]

详情

👉chat.controller.ts
javascript 复制代码
 // 获取单个详情
  @Get('/system/chat/:id')
  async findOne(@Param('id') id: number){
    return this.chatService.findOne(id);
  }
👉 chat.service.ts

这里我们先简单填写一下我们的方法逻辑

javascript 复制代码
// 根据 ID 获取单个消息
  async findOne(chatId: number){
    return this.chatRepository.findOne({ where: { chatId } });
  }
👉 调用接口

这个时候我们调用接口,返回的信息如下,查询接口ok

javascript 复制代码
{
    "chatId": 1,
    "senderUserId": "57",
    "receiverUserId": "user123",
    "chatType": "single",
    "content": "Hello, how are you?",
    "messageType": "text",
    "status": "sent",
    "attachments": null,
    "groupId": null,
    "groupName": null,
    "isSystem": false,
    "isDeleted": false,
    "createTime": "2025-05-13 16:15:09",
    "updateTime": "2025-05-13 16:15:09",
    "senderUserAvatar": null,
    "senderUserName": null
}

更新

👉chat.controller.ts
javascript 复制代码
 @Put('/system/chat')
  async update(
    @Body('id') id: number,
    @Body() updateChatDto, // : UpdateChatDto
  ) {
    return this.chatService.update(id, updateChatDto);
  }
👉 chat.service.ts

这里我们先简单填写一下我们的方法逻辑

javascript 复制代码
async update(chatId: number, updateChatDto: UpdateChatDto) {
    const resdata = await this.chatRepository.findOne({ where: { chatId } });
    if (!resdata) {
      return {
        code: 404,
        message: '数据不存在!',
        data: null,
      };
      //throw new Error('Message not found');
    }
    const updateData = { ...resdata, updateTime: new Date() }; // 合并更新的数据-确保更新时间是最新的
    // Object.assign(resdata, updateChatDto);
    console.log(resdata, 'resdata-----------更新信息');
    const result = await this.chatRepository.save(resdata);
    if (result) {
      return {
        code: 200,
        message: '更新成功',
        // data: updatedUser,
      };
    } else {
      return {
        code: 500,
        message: '更新失败',
      };
    }
    // return this.chatRepository.save(resdata);
  }
👉 调用接口

这个时候我们调用接口,返回的信息如下,查询接口ok

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

删除

删除部分我们一般只是做一个假的删除部分

👉chat.controller.ts
javascript 复制代码
// 删除消息 : Promise<void> 
@Delete('/system/chat/:id')
async remove(@Param('id') id: number){
  return this.chatService.remove(id);
}
👉 chat.service.ts

这里我们先简单填写一下我们的方法逻辑

javascript 复制代码
// 删除消息(软删除) : Promise<void> 
async remove(chatId: number) {
  const chat = await this.chatRepository.findOne({ where: { chatId } });
  if (chat) {
    chat.isDeleted = true;
    const delUpdateData = {...chat,isDeleted: true};
    await this.chatRepository.save(delUpdateData);
    // const delUser = await this.userRepository.delete(id);
    const delData = await this.chatRepository.save(chat);
    if( delData) {
      return {
        code: 200,
        message: '删除成功',
      };
    }else {
      return {
        code: 200,
        message: '删除失败',
      };
    }
  } else {
    return {
      code: 401,
      message: '数据不存在!',
    };
  }
}
👉 调用接口

这个时候我们调用接口,返回的信息如下,查询接口ok

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

4、报错以及处理

👉An invalid controller has been detected

javascript 复制代码
UnknownRequestMappingException [Error]: An invalid controller has been detected. "ChatGateway" does not have the @Controller() 
decorator but it is being listed in the 
"controllers" array of some module.
写法
javascript 复制代码
controllers: [ChatController, ChatGateway],
原因

"ChatGateway"网关应该放入providers模块中

处理方式
javascript 复制代码
controllers: [ChatController, ChatGateway],
=> 
providers: [ChatService, ChatGateway],

问题解决!

相关推荐
木斯佳21 分钟前
前端八股文面经大全:26届秋招滴滴校招前端一面面经-事件循环题解析
前端·状态模式
光影少年40 分钟前
react状态管理都有哪些及优缺点和应用场景
前端·react.js·前端框架
野犬寒鸦1 小时前
从零起步学习并发编程 || 第六章:ReentrantLock与synchronized 的辨析及运用
java·服务器·数据库·后端·学习·算法
saber_andlibert2 小时前
TCMalloc底层实现
java·前端·网络
逍遥德2 小时前
如何学编程之01.理论篇.如何通过阅读代码来提高自己的编程能力?
前端·后端·程序人生·重构·软件构建·代码规范
冻感糕人~2 小时前
【珍藏必备】ReAct框架实战指南:从零开始构建AI智能体,让大模型学会思考与行动
java·前端·人工智能·react.js·大模型·就业·大模型学习
程序员agions2 小时前
2026年,“配置工程师“终于死绝了
前端·程序人生
alice--小文子2 小时前
cursor-mcp工具使用
java·服务器·前端
晚霞的不甘3 小时前
揭秘 CANN 内存管理:如何让大模型在小设备上“轻装上阵”?
前端·数据库·经验分享·flutter·3d
MX_93593 小时前
Spring的bean工厂后处理器和Bean后处理器
java·后端·spring