从 0 开始实现一个网页聊天室 (小型项目)(上)

简介: 从 0 开始实现一个网页聊天室 (小型项目)

实现功能

  1. 用户注册和登录
  2. 好友列表展示
  3. 会话列表展示: 显示当前正在进行哪些会话 (单聊 / 群聊) , 选中好友列表中的某个好友, 会生成对应的会话
  4. 实时通信, A给B发送消息, B的聊天界面 / 会话界面能立刻显示新的消息


TODO:

  1. 添加好友功能
  2. 用户头像显示
  3. 传输图片 / 表情包
  4. 历史消息搜索
  5. 消息撤回

相关技术


网络通信: WebSocket

Spring + SpringBoot + SpringMVC + MyBatis

HTML + CSS + JS

数据库设计

项目的基本框架

前端页面

注册和登录页面

聊天界面

后端代码

实体类

User

本类表示一个用户的信息, 对应数据库的 user 表

@Data
public class User {

    private int userId;
    private String username = "";
    private String password = "";

    public User() {
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }
}

Friend

使用一个 Friend 对象表示一个好友

// 使用一个 Friend 对象表示一个好友, 对应数据库的 friend 表
@Data
public class Friend {
    private int friendId;
    private String friendName;

    public Friend() {
    }

    public Friend(int friendId, String friendName) {
        this.friendId = friendId;
        this.friendName = friendName;
    }
}

Message

本类表示一条消息的相关信息, 对应数据库的表 message + 字段: fromname

(没有 postTime 是因为: 在查询的时候就是一次性查出所有的时间, 按照时间结果排序后返回, 我们这里就不需要再获取时间了)

// 本类表示一条消息的相关信息
// (没有 postTime 是因为: 在查询的时候就是一次性查出所有的时间, 按照时间结果排序后返回, 我们这里就不需要再获取时间了)
@Data
public class Message {
    private Integer messageId;
    private int fromId;
    private String fromName;
    private int sessionId;
    private String content;

    public Message() {
    }

    public Message( int fromId, String fromName, int sessionId, String content) {
        this.fromId = fromId;
        this.fromName = fromName;
        this.sessionId = sessionId;
        this.content = content;
    }
}

MessageSession

使用该类表示一个会话, 对应数据库的 message_session + message_session_user

// 使用该类表示一个会话
@Data
public class MessageSession {
    private int sessionId;
    private List<Friend> friends;
    private String lastMessage;
}

MessageSessionUserItem

该类对象表示 message_session_user 表里的一个记录

// 该类对象表示 message_session_user 表里的一个记录
@Data
public class MessageSessionUserItem {
    private int sessionId;
    private int userId;

    public MessageSessionUserItem() {
    }

    public MessageSessionUserItem(int sessionId, int userId) {
        this.sessionId = sessionId;
        this.userId = userId;
    }
}

MessageRequest

WebSocket 请求

自定义格式, 用于网络通信中接受请求

// WebSocket请求
@Data
public class MessageRequest {
    private String type = "message";
    private int sessionId;
    private String content;
}

MessageResponse

WebSocket 响应

自定义格式, 用于网络通信中返回响应

// WebSocket响应
@Data
public class MessageResponse {
    private String type = "message";
    private int fromId;
    private String fromName;
    private int sessionId;
    private String content;

    public MessageResponse() {
    }

    public MessageResponse(int fromId, String fromName, int sessionId, String content) {
        this.fromId = fromId;
        this.fromName = fromName;
        this.sessionId = sessionId;
        this.content = content;
    }
}

数据库

FriendMapper

用户好友的相关操作

@Mapper
public interface FriendMapper {
    // 查询用户好友列表
    List<Friend> selectFriendList(@Param("userId") int userId);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.java_chatroom.model.FriendMapper">

    <select id="selectFriendList" resultType="com.example.java_chatroom.model.Friend">
        select userId as friendId, username as friendName
        from user
        where userId in
        (select friendId from friend where userId = #{userId})
    </select>
</mapper>

MessageMapper

消息的相关操作

@Mapper
public interface MessageMapper {

    // 获取指定会话的最后一条消息
    String getLastMessageBySessionId(@Param("sessionId") int sessionId);

    // 获取指定会话的历史消息 (限制100条)
    List<Message> getMessagesBySessionId(@Param("sessionId") int sessionId);

    // 插入一条消息到数据库表中
    void add(@Param("message") Message message);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.java_chatroom.model.MessageMapper">

    <select id="getLastMessageBySessionId" resultType="java.lang.String">
        select content from message
        where sessionId = #{sessionId}
        order by postTime desc
        limit 1
    </select>

    <select id="getMessagesBySessionId" resultType="com.example.java_chatroom.model.Message">
        select
            messageId, sessionId, fromId, content, username as fromName
        from
            message, user
        where
            sessionId = #{sessionId}
            and fromId = userId
        order by
            postTime desc
        limit 100 offset 0
    </select>

    <insert id="add">
        insert into message values(null, #{message.fromId}, #{message.sessionId}, #{message.content}, now());
    </insert>
</mapper>

MessageSessionMapper

会话的相关操作

@Mapper
public interface MessageSessionMapper {
    // 1.根据 userId 获取到该用户在哪些会话中存在, 返回结果是一组 sessionId.
    List<Integer> getSessionIdsByUserId(@Param("userId") int userId);

    // 2. 根据 sessionId 查询这个会话包含哪些用户(刨除掉最初的 user)
    List<Friend> getFriendsBySessionId(@Param("sessionId") int sessionId,@Param("selfUserId") int selfUserId);

    // 3. 新增会话记录, 返回会话 id
    int addMessageSession(@Param("messageSession") MessageSession messageSession);

    // 4.给 message_session_user 表新增对应记录
    int addMessageSessionUser(@Param("messageSessionUserItem") MessageSessionUserItem messageSessionUserItem);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.java_chatroom.model.MessageSessionMapper">

    <select id="getSessionIdsByUserId" resultType="java.lang.Integer">
        select sessionId from message_session
        where sessionId in
            ( select sessionId from message_session_user
             where userId = #{userId} )
        order by lastTime desc
    </select>

    <select id="getFriendsBySessionId" resultType="com.example.java_chatroom.model.Friend">
        select userId as friendId, username as friendName
        from user
        where userId in
            ( select userId from message_session_user
                where sessionId = #{sessionId}
                and userId != #{selfUserId} )
    </select>

    <insert id="addMessageSession" useGeneratedKeys="true" keyProperty="messageSession.sessionId">
        insert into message_session values(null, now())
    </insert>

    <insert id="addMessageSessionUser">
        insert into message_session_user values(
            #{messageSessionUserItem.sessionId},
            #{messageSessionUserItem.userId}
        )
    </insert>
</mapper>

从 0 开始实现一个网页聊天室 (小型项目)(下):https://developer.aliyun.com/article/1520799

目录
相关文章
|
5月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的网络游戏交易平台信息管理系统附带文章和源代码设计说明文档ppt
基于ssm+vue.js+uniapp小程序的网络游戏交易平台信息管理系统附带文章和源代码设计说明文档ppt
35 1
|
5月前
|
数据安全/隐私保护
那些酷炫的网页你也可以做到——第六篇,小型公司web开发
那些酷炫的网页你也可以做到——第六篇,小型公司web开发
|
2月前
|
前端开发 开发者 开发框架
JSF与Bootstrap,打造梦幻响应式网页!让你的应用跨设备,让用户爱不释手!
【8月更文挑战第31天】在现代Web应用开发中,响应式设计至关重要,以确保不同设备上的良好用户体验。本文探讨了JSF(JavaServer Faces)与Bootstrap框架的结合使用,展示了如何构建响应式网页。JSF是一个基于Java的Web应用框架,提供丰富的UI组件和表单处理功能;而Bootstrap则是一个基于HTML、CSS和JavaScript的前端框架,专注于实现响应式设计。通过结合两者的优势,开发者能够更便捷地创建自适应布局,提升Web应用体验。然而,这种组合也有其局限性,如JSF组件库较小和较高的学习成本等,因此在选择开发框架时需综合考虑具体需求和应用场景。
32 0
|
3月前
|
开发框架 前端开发 JavaScript
循序渐进BootstrapVue,开发公司门户网站(1)---基于Bootstrap网站模板构建组件界面
循序渐进BootstrapVue,开发公司门户网站(1)---基于Bootstrap网站模板构建组件界面
|
5月前
|
前端开发 JavaScript
从 0 开始实现一个网页聊天室 (小型项目)(下)
从 0 开始实现一个网页聊天室 (小型项目)
74 16
|
4月前
|
前端开发 JavaScript 容器
程序与技术分享:BeetleX之快速构建Web多房间聊天室
程序与技术分享:BeetleX之快速构建Web多房间聊天室
33 0
|
5月前
|
存储 前端开发 JavaScript
网页应用与开发
网页应用与开发
36 1
|
5月前
|
前端开发 JavaScript Java
基于Jeecgboot前后端分离的聊天功能正式发布
基于Jeecgboot前后端分离的聊天功能正式发布
47 0
|
5月前
|
前端开发 API
基于Jeecgboot前后端分离的聊天功能集成(一)
基于Jeecgboot前后端分离的聊天功能集成(一)
152 0
|
5月前
|
前端开发
基于Jeecgboot前后端分离的聊天功能集成(二)
基于Jeecgboot前后端分离的聊天功能集成(二)
84 0