SpringBoot 整合WebSocket 实现简单聊天室
Posted ꧁এ悲宸๓₯㎕
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot 整合WebSocket 实现简单聊天室相关的知识,希望对你有一定的参考价值。
项目结构:
效果展示:
实现步骤
步骤一:添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- json 返回数据需要 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.54</version>
</dependency>
<!-- 热部署 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<!-- websocket 在线聊天支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
步骤二:Java 代码
1,配置类:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExportelr() {
return new ServerEndpointExporter();
}
}
2,控制层
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* @author ylwang
* @version 1.0
* @date 2021/8/15 0015 15:23
*/
@ServerEndpoint("/websocket/{username}")
@Controller
public class WebsocketController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
//在线人数
private static int onlineNumber = 0;
private static Map<String, WebsocketController> clients =
new ConcurrentHashMap<>();
//会话
private Session session;
//用户名称
private String username;
/**
* 进入聊天室 --> 项目中读取用户信息获取用户名
*/
@RequestMapping("/websocket")
public String webSocket(Model model) {
//定义随机时间戳名称
String name = "游客:";
String dataName = new SimpleDateFormat("yyyyMMddHHmmsss").format(new Date());
name = name + dataName;
//websocket链接地址 + 游客名 ----> 项目种请定义在配置文件 ---> 或直接读取服务器,ip 端口
String path = "ws://127.0.0.1:8080/websocket/";
//讲用户、地址信息放在域中
model.addAttribute("path", path);
model.addAttribute("username", name);
//返回到html页面
return "socket";
}
/**
* 监听连接(有用户连接,立马到来执行这个方法)
* session 发生变化
*
* @param username
* @param session
*/
@OnOpen
public void onOpen(@PathParam("username") String username, Session session) {
onlineNumber++;
//把新用户赋给变量
this.username = username;
//把新用户的session信息赋给变量
this.session = session;
//输出websocket信息
logger.info("现在来连接的客户id:" + session.getId() + "用户名:" + username);
logger.info("有新连接加入! 当前在线人数" + onlineNumber);
try {
//把自己的信息加入到map当中,this = 当前类(把当前类作为对象保存起来)
clients.put(username, this);
//获得所有的用户
Set<String> userLists = clients.keySet();
//先给所有用户发送通知,上线了
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
HashMap<String, Object> map1 = new HashMap<>();
// 把所有用户列表
map1.put("onlineUsers", userLists);
//返回所有上线状态
map1.put("messageType", 1);
//返回用户名
map1.put("username", username);
//返回在线人数
map1.put("number", onlineNumber);
//发送全体信息,(用户上线信息)
sendMessageAll(JSON.toJSONString(map1), username);
//给自己发一条消息,告诉自己现在都有谁在线
HashMap<String, Object> map2 = new HashMap<>();
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
map2.put("messageType", 3);
//把所有用户放入map2
map2.put("onlineUsers", userLists);
//返回在线人数
map2.put("number", onlineNumber);
//消息发送指定人(所用的在线用户信息)
sendMessageAll(JSON.toJSONString(map2), username);
} catch (Exception e) {
logger.info(username + "上线的时候通知所有人发生了错误");
}
}
/**
* 监听连接断开(有用户退出,会立马到来执行这个方法)
*/
@OnClose
public void onClose(){
onlineNumber--;
//所有在线用户中去除下线用户
clients.remove(username);
try {
//messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
Map<String, Object> map1 = new HashMap();
map1.put("messageType", 2);
//所有在线用户
map1.put("onlineUsers", clients.keySet());
//下线用户的用户名
map1.put("username", username);
//返回在线人数
map1.put("number", onlineNumber);
//发送信息,所有人,通知谁下线了
sendMessageAll(JSON.toJSONString(map1), username);
}catch (Exception e){
logger.info(username + "下线的时候通知所有人发生了错误");
}
logger.info("有连接关闭! 当前在线人数" + onlineNumber);
}
@OnError
public void onError(Session session,Throwable error){
logger.info("服务器发生了错误" + error.getMessage());
}
/**
* 监听消息(收到客户端的消息立即执行)
*
* @param message 消息
* @param session 会话
*/
@OnMessage
public void OnMessage(String message,Session session){
try {
logger.info("来自客户端消息:" + message +"客户端的id是:"+ session.getId());
//用户发送的信息
JSONObject jsonObject = JSON.parseObject(message);
//发送的内容
String textMessage = jsonObject.getString("message");
//发送人
String fromUserName = jsonObject.getString("username");
//接收人 to=all 发送消息给所有人 || to= !all to == 用户名
String toUserName = jsonObject.getString("to");
//发送消息 -- messageType 1代表上线 2代表下线 3代表在线名单 4代表消息
HashMap<String, Object> map1 = new HashMap<>();
map1.put("messageType",4);
map1.put("textMessage", textMessage);
map1.put("fromusername", fromUserName);
if (toUserName.equals("All")){
//消息发送所有人(同步)
map1.put("toUserName","所有人");
sendMessageAll(JSON.toJSONString(map1),fromUserName);
}else {
//消息发送指定人(同步)
map1.put("toUserName",toUserName);
sendMessageTo(JSON.toJSONString(map1), toUserName);
}
}catch (Exception e){
logger.info("发生了错误了");
}
}
/**
* 消息发送指定人
*/
private void sendMessageTo(String message, String toUserName) throws IOException {
//遍历所有用户
for (WebsocketController item : clients.values()) {
if (item.username.equals(toUserName)){
//消息发送指定人(同步)
item.session.getBasicRemote().sendText(message);
break;
}
}
}
/**
* 消息发送所有人
*/
private void sendMessageAll(String message, String username) throws IOException {
for (WebsocketController item : clients.values()) {
//消息发送所有人(同步)getAsyncRemote
item.session.getBasicRemote().sendText(message);
}
}
//在线人数
public static synchronized int getOnlineCount(){
return onlineNumber;
}
}
如果在配置类中写path:
url:
path: ws://127.0.0.1:8080/websocket/
控制层:
@Value("${url.path}")
private String path;
方便实现的话,可以直接写在控制层,不过建议写在配置文件中
步骤三:socket页面
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head>
<meta charset="UTF-8">
<meta name="renderer" content="webkit">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="../frame/layui/css/layui.css">
<link rel="stylesheet" href="../frame/static/css/style.css">
<link rel="icon" href="../frame/static/image/code.png">
<title>websocket</title>
<script type="text/javascript" src="http://ajax.microsoft.com/ajax/jquery/jquery-1.4.min.js"></script>
<script src="http://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
<script src="https://cdn.bootcss.com/sockjs-client/1.1.4/sockjs.min.js"></script>
</head>
<body>
<!-- socket url -->
<input type="hidden" th:value="${path}" id="path" style="display: none"/>
<!-- 用户名 -->
<input type="hidden" th:value="${username}" id="username" style="display: none"/>
<br>
<!--<input type="hidden" value="所有人" id="onLineUser" text="所有人" style="display: none" />-->
<!-- overflow-y :auto;overflow :auto; 宽高自适应滚动条-->
<span id="miqx"
style="width:80%;height:300px; background-color: papayawhip;float:left;overflow-y :auto;overflow :auto;">
<li style="text-align: center">群聊信息</li>
</span>
<span id="miax" style="width:20%;background-color: #24eb04;float:left;overflow-y :auto;overflow :auto以上是关于SpringBoot 整合WebSocket 实现简单聊天室的主要内容,如果未能解决你的问题,请参考以下文章
springboot整合websocket实现一对一消息推送和广播消息推送
SpringBoot 整合WebSocket 实现简单聊天室