1.背景
基于项目需求,最近需要实现一个简单的聊天功能。日常生活中,大家对于聊天也习以为常,微信、QQ等软件也经常用到,其实我们也可以引入一些第三方的sdk包等去实现,也可以利用WebSocket通信协议去手动实现简单的聊天。本文主要讲述下WebSocket实现的具体步骤及实现的效果图。
2.方案选型及优缺点介绍
- 方案一 利用http接口手动实现三个接口:sengMsg(消息发送)、receiveMsg(消息接收)、getHistoryMsg(获取历史消息) ,然后前端发送消息时调用sendMsg接口,将数据写入数据库以便获取历史消息使用,接收消息时前端声明一个定时器,每一秒钟去刷新消息接收接口,来获取消息内容显示到聊天框中,最后,如果用户需要翻看历史消息,调用getHistoryMsg接口即可。优点 后端实现简单,且能将聊天消息持久化到数据库永久保存,可以根据聊天室id随时获取消息内容缺点 由于频繁调用接口,服务器和api接口压力比较大,高并发情况下服务器可能会宕机,而且不进行消息发送时,由于定时器的使用,前端频繁请求会造成空跑,显然不太合理
- 方案二 利用已有的WebSocket服务实现聊天功能优点 不用额外自己实现接口,直接按照WebSocket定义的规则直接套用即可缺点 消息没有持久化,如果服务宕机,可能无法查看历史消息
3.服务搭建及实现
- 3.1 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
- 3.2 声明socket配置类
@Configuration
public class WebSocketConfig {
//注入一个ServerEndpointExporter
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
- 3.3 声明聊天Controller
/**
* 聊天控制器
* @ServerEndpoint("/chat/{userId}")中的userId是前端创建会话窗口时当前用户的id,即消息发送者的id
*/
@ServerEndpoint("/chat/{userId}")
@Component
public class ChatWebSocketController {
private final Logger logger = Logger.getLogger(ChatWebSocketController.class);
//onlineCount:在线连接数
private static AtomicInteger onlineCount = new AtomicInteger(0);
//webSocketSet:用来存放每个客户端对应的MyWebSocket对象。
public static List<ChatWebSocketController> webSocketSet = new ArrayList<>();
//存放所有连接人信息
public static List<String> userList = new ArrayList<>();
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//用户ID
public String userId = "";
/**
* 连接建立成功调用的方法
*/
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
this.userList.add(userId) ;
//加入set中
webSocketSet.add(this);
//在线数加1
onlineCount.incrementAndGet();
logger.info("有新连接加入!" + userId + "当前在线用户数为" + onlineCount.get());
JSONObject msg = new JSONObject();
try {
msg.put("msg", "连接成功");
msg.put("status", "SUCCESS");
msg.put("userId", userId);
sendMessage(JSON.toJSONString(msg));
} catch (Exception e) {
logger.debug("IO异常");
}
}
/**
* 连接关闭调用的方法
*/
@OnClose
public void onClose(@PathParam("userId") String userId ) {
//从set中删除
webSocketSet.remove(this);
onlineCount.decrementAndGet(); // 在线数减1
logger.info("用户"+ userId +"退出聊天!当前在线用户数为" + onlineCount.get());
}
/**
* 收到客户端消息后调用的方法
*
* @param message 客户端发送过来的消息
*/
@OnMessage
public void onMessage(String message,