SpringBoot与webSocket实现在线聊天室——实现私聊+群聊+聊天记录保存
引用参考:原文章地址:https://blog.csdn.net/qq_41463655/article/details/92410518
在此基础上实现对聊天记录的保存。
代码地址:链接:https://pan.baidu.com/s/1IJFZDa4S_DF08773sKJWeA 提取码:jkui
思路:新建一个实体类用于保存聊天记录,在消息发送时,设置对象的各个值然后保存到数据库中。
实现步骤:
- 实体类: 新建实体类UserMessage,根据需要设置对象的字段,如:发送者、接收者、信息内容、发送时间等。
- mapper层:写UserMessageMapper接口,继承BaseMapper(我使用的是mybatis-plus,也可以使用其他方法)。
- service层:UserMessageService继承IService,service实现类UserMessageServiceImpl继承ServiceImpl<UserMessageMapper, UserMessage> 实现UserMessageService。
- controller层:在UserMessageController中的onMessage方法中,将前端传过来的json解析为字段,新建UserMessage对象message1,设置message1对象的各个值,通过消息接收者类型的判断,确实数据库中接收者的值如何设置,然后将UserMessage对象保存到数据库中。
此时,聊天记录保存到数据库时,是一条一条进行保存,为了减少对数据库频繁的操作,在UserMessageController类中定义一个静态的集合MessageList用来暂时保存聊天记录,并且设置MessageList集合的长度为一个固定值不可变,目的是为了实现将聊天记录保存到集合中,当集合的长度等于设定的值时,批量将聊天记录保存到数据库中。
- 所以将聊天记录保存到数据库前,先将聊天记录保存到集合MessageList中,判断集合的长度,如果集合的长度等于设定的值,将集合中的数据批量保存到数据库中,然后清空集合,为下一次保存聊天记录做准备。
我在实现保存聊天记录功能时遇到的问题:
- 代码没有错,群聊、私聊都可以实现,但是无法保存聊天记录,错:设置的表名与数据库没有对应好。
- 保存聊天记录的集合一定要设置为全局,如果是在方法中新建集合,那么聊天记录保存的并不是同一个集合,导致集合的长度永远无法达到设定的值,无法批量保存,导致数据保存失败。
- 当聊天页面关闭时,聊天记录的数据就会丢失,为什么不在UserMessageController中的onClose方法中判断在关闭聊天框前,集合中是否有聊天记录,如果有则进行保存??因为设置的集合为全局变量,就算是关闭了聊天页面,聊天记录也会暂时保存到集合中,并不会丢失。
效果展示图:
完整代码实现如下:
包结构图:
代码部分:
webSocket配置类:WebSocketConfig.java
package com.example.springboot_websocket.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
/**
* @author Administrator
*/
@Configuration
@Component
public class WebSocketConfig {
/**
* 服务器节点
*
* 如果使用独立的servlet容器,而不是直接使用springboot的内置容器,就不要注入ServerEndpointExporter,因为它将由容器自己提供和管理
*/
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
实体类:UserMessage.java 定义实体类与数据库连接,存储聊天记录
package com.example.springboot_websocket.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.Date;
/**
* @author Administrator
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserMessage {
/**
* 消息发送者
*/
private String username;
/**
* 聊天文本
*/
private String message;
/**
* 消息接受者
*/
private String tousername;
/**
* 发送时间
*/
private Date createtime;
}
mapper层:UserMessageMapper.java
package com.example.springboot_websocket.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.example.springboot_websocket.bean.UserMessage;
import org.apache.ibatis.annotations.Mapper;
/**
* extends BaseMapper<T>:继承接口即可实现基本的CRUD方法
* <p>
* 1.如果自定义的mapper继承了mybatis-plus的BaseMapper时,xxxMapper.xml中不可以包含insert方法,因为在BaseMapper中存在该方法
* 2.如果对应的xxxMapper.xml中包含insert方法,那么就会执行xxxMapper.xml中的方法,相当于重写BaseMapper中的insert方法;
* 如果xxxMapper.xml中没有insert方法,默认使用BaseMapper中的方法
* 3.注意:BaseMapper<T>中的泛型对应相应的实体类
*/
/**
* @author Administrator
*/
@Mapper
public interface UserMessageMapper extends BaseMapper<UserMessage> {
}
service层:UserMessageService.java
package com.example.springboot_websocket.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.example.springboot_websocket.bean.UserMessage;
/**
* @author Administrator
*/
public interface UserMessageService extends IService<UserMessage> {
}
service层:UserMessageServiceImpl .java
package com.example.springboot_websocket.service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.springboot_websocket.bean.UserMessage;
import com.example.springboot_websocket.mapper.UserMessageMapper;
import org.springframework.stereotype.Service;
/**
* @author Administrator
*/
@Service
public class UserMessageServiceImpl extends ServiceImpl<UserMessageMapper, UserMessage> implements UserMessageService {
}
controller层:UserMessageController.java
package com.example.springboot_websocket.controller;
import com.alibaba.fastjson.JSON;
import com.example.springboot_websocket.bean.UserMessage;
import com.example.springboot_websocket.service.UserMessageService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
/**
* websocket类
*
* @ServerEndpoint: socket链接地址
*/
/**
* @author Administrator
*/
@ServerEndpoint("/websocket/{username}")
@Controller
@Component
public class UserMessageController {
/**
* 设置一次性存储数据的list的长度为固定值,每当list的长度达到固定值时,向数据库存储一次
*/
private static final Integer LIST_SIZE = 3;
/**
* 设置在线人数为静态变量
*/
public static int onlineNumber = 0;
private static UserMessageService userMessageService;
/**
* 新建list集合存储数据
*/
private static ArrayList<UserMessage> MessageList = new ArrayList<>();
/**
* map(username,websocket)作为对象添加到集合中
*/
private static Map<String, UserMessageController> clients = new ConcurrentHashMap<String, UserMessageController>();
private Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* session会话
*/
private Session session;
/**
* 用户名称
*/
private String username;
public static synchronized int getOnlineCount() {
return onlineNumber;
}
@Autowired
public void setOgLocationService(UserMessageService userMessageService) {
UserMessageController.userMessageService = userMessageService;
}
/**
* 进入聊天室 --> 项目中读取用户信息获取用户名
*/