【十五】springboot整合WebSocket实现聊天室

互相交流入口地址 

整体目录:

【一】springboot整合swagger

【二】springboot整合自定义swagger

【三】springboot整合token

【四】springboot整合mybatis-plus

【五】springboot整合mybatis-plus

【六】springboot整合redis

【七】springboot整合AOP实现日志操作

【八】springboot整合定时任务

【九】springboot整合redis实现启动服务时热点数据保存在全局和缓存

【十】springboot整合quartz实现定时任务优化

【十一】springboot整合异步调用并获取返回值

【十二】springboot整合WebService

【十三】springboot整合WebService关于传参数

【十四】springboot整合WebSocket

【十五】springboot整合WebSocket实现聊天室

【十六】RabbitMQ基础篇(下载安装并基础使用,内含各种坑问题)

【十七】RabbitMQ基础篇(延迟队列和死信队列实战)

【十八】springboot实现自定义全局异常处理

【十九】初学Kafka并实战整合SpringCloudStream进行使用

【二十】springboot整合ElasticSearch实战(万字篇)

【二十一】springboot整合过滤器实战

【二十二】springboot整合拦截器实战并对比过滤器

【二十三】springboot整合activiti7(1)实战演示篇

【二十四】springboot整合spring事务详解以及实战

【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据

【二十六】springboot整合jedis和redisson布隆过滤器处理缓存穿透

【二十七】springboot实现多线程事务处理

【二十八】springboot之threadLocal参数解析器实现session一样保存当前登录功能 

【二十九】springboot整合logback实现日志管理

【三十】springboot项目上高并发解决示例

目录

第一步:改造WebSocket

第二步:创建前端html文件

第三步:演示


        介绍:接下来我会把学习阶段学到的框架等知识点进行整合,每一次整合是在前一章的基础上进行的,所以后面的整合不会重复放前面的代码。每次的demo我放在结尾,本次是接着上一章的内容延续的,只增加新增的或者修改的代码。

        上一章是初步整合websocket之后实现了一个进度条的小demo,这次使用websocket实现聊天室功能,实现多个用户在线聊天以及私聊。

         首先我先展示一下效果图(随便弄的,界面比较丑陋):

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16         我再展示一下我的目录结构(前端我用的HbuilderX):

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        前端就一个html文件,引用的线上的jquery和bootstrap,所以我没有写样式文件。

        后端相比上一章没有新增文件。只是进行了WebSocket文件的改造,websocket的依赖不需要导了,上一章已经导入了。

第一步:改造WebSocket

package com.swagger.demo.config;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * @ClassName WebSocketConfig
 * @Description TODO
 * @Author zrc
 * @Date 11:01
 * @Version 1.0
 **/
//注册成组件
@Component
//定义websocket服务器端,它的功能主要是将目前的类定义成一个websocket服务器端。注解的值将被用于监听用户连接的终端访问URL地址
@ServerEndpoint("/websocket/{username}")
//如果不想每次都写private  final Logger logger = LoggerFactory.getLogger(当前类名.class); 可以用注解@Slf4j;可以直接调用log.info
@Slf4j
public class WebSocket {

    //实例一个session,这个session是websocket的session
    private Session session;

    //存放当前用户名
    private String userName;

    //存放需要接受消息的用户名
    private String toUserName;

    //存放在线的用户数量
    private static Integer userNumber = 0;

    //存放websocket的集合(本次demo不会用到,聊天室的demo会用到)
    private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>();

    //前端请求时一个websocket时
    @OnOpen
    public void onOpen(Session session,@PathParam("username") String username) throws IOException {
        this.session = session;
        //将当前对象放入webSocketSet
        webSocketSet.add(this);
        //增加在线人数
        userNumber++;
        //保存当前用户名
        this.userName = username;
        //获得所有的用户
        Set<String> userLists = new TreeSet<>();
        for (WebSocket webSocket : webSocketSet) {
            userLists.add(webSocket.userName);
        }

        //将所有信息包装好传到客户端(给所有用户)
        Map<String, Object> map1 = new HashMap();
        //  把所有用户列表
        map1.put("onlineUsers", userLists);
        //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
        map1.put("messageType", 1);
        //  返回用户名
        map1.put("username", username);
        //  返回在线人数
        map1.put("number", this.userNumber);
        //发送给所有用户谁上线了,并让他们更新自己的用户菜单
        sendMessageAll(JSON.toJSONString(map1),this.userName);
        log.info("【websocket消息】有新的连接, 总数:{}", this.userNumber);

        // 更新在线人数(给所有人)
        Map<String, Object> map2 = new HashMap();
        //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
        map2.put("messageType", 3);
        //把所有用户放入map2
        map2.put("onlineUsers", userLists);
        //返回在线人数
        map2.put("number", this.userNumber);
        // 消息发送指定人(所有的在线用户信息)
        sendMessageAll(JSON.toJSONString(map2),this.userName);
    }

    //前端关闭时一个websocket时
    @OnClose
    public void onClose() throws IOException {
        //从集合中移除当前对象
        webSocketSet.remove(this);
        //在线用户数减少
        userNumber--;
        Map<String, Object> map1 = new HashMap();
        //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
        map1.put("messageType", 2);
        //所有在线用户
        map1.put("onlineUsers", this.webSocketSet);
        //下线用户的用户名
        map1.put("username", this.userName);
        //返回在线人数
        map1.put("number", userNumber);
        //发送信息,所有人,通知谁下线了
        sendMessageAll(JSON.toJSONString(map1),this.userName);
        log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
    }

    //前端向后端发送消息
    @OnMessage
    public void onMessage(String message) throws IOException {
        log.info("【websocket消息】收到客户端发来的消息:{}", message);
        //将前端传来的数据进行转型
        com.alibaba.fastjson.JSONObject jsonObject = JSON.parseObject(message);
        //获取所有数据
        String textMessage = jsonObject.getString("message");
        String username = jsonObject.getString("username");
        String type = jsonObject.getString("type");
        String tousername = jsonObject.getString("tousername");
        //群发
        if(type.equals("群发")){
            Map<String, Object> map3 = new HashMap();
            map3.put("messageType", 4);
            //所有在线用户
            map3.put("onlineUsers", this.webSocketSet);
            //发送消息的用户名
            map3.put("username", username);
            //返回在线人数
            map3.put("number", userNumber);
            //发送的消息
            map3.put("textMessage", textMessage);
            //发送信息,所有人,通知谁下线了
            sendMessageAll(JSON.toJSONString(map3),this.userName);
        }
        //私发
        else{
            //发送给对应的私聊用户
            Map<String, Object> map3 = new HashMap();
            map3.put("messageType", 4);
            //所有在线用户
            map3.put("onlineUsers", this.webSocketSet);
            //发送消息的用户名
            map3.put("username", username);
            //返回在线人数
            map3.put("number", userNumber);
            //发送的消息
            map3.put("textMessage", textMessage);
            //发送信息,所有人,通知谁下线了
            sendMessageTo(JSON.toJSONString(map3),tousername);

            //发送给自己
            Map<String, Object> map4 = new HashMap();
            map4.put("messageType", 4);
            //所有在线用户
            map4.put("onlineUsers", this.webSocketSet);
            //发送消息的用户名
            map4.put("username", username);
            //返回在线人数
            map4.put("number", userNumber);
            //发送的消息
            map4.put("textMessage", textMessage);
            //发送信息,所有人,通知谁下线了
            sendMessageTo(JSON.toJSONString(map3),username);
        }
    }

    /**
     *  消息发送所有人
     */
    public void sendMessageAll(String message, String FromUserName) throws IOException {
        for (WebSocket webSocket: webSocketSet) {
            //消息发送所有人(同步)getAsyncRemote
            webSocket.session.getBasicRemote().sendText(message);
        }
    }

    /**
     *  消息发送指定人
     */
    public void sendMessageTo(String message, String ToUserName) throws IOException {
        //遍历所有用户
        for (WebSocket webSocket : webSocketSet) {
            if (webSocket.userName.equals(ToUserName)) {
                //消息发送指定人
                webSocket.session.getBasicRemote().sendText(message);
                log.info("【发送消息】:", this.userName+"向"+ToUserName+"发送消息:"+message);
                break;
            }
        }
    }

}

        下面,我逐步介绍:

1、定义全局变量

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        首先定义几个全局变量:

  •         username用于保存当前的websocket连接传过来的用户名,作为websocket的唯一标识,后面私聊时通过这个唯一标识发送消息给对应的websocket连接。
  •         userNumber用于保存更新在线用户数,每次新增或断开一个websocket连接之后,更新该在线用户数。
  •         webSocketSet用于保存在线的所有websocket对象,是个websocket对象的集合,使用Set集合,保证不会出现重复的对象,后面私发或群发时通过遍历该对象,将消息发送给对应的对象。

2、新增两个发送消息的方法

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        sendMessageAll是将消息发送给全部websocket对象,从上面可以看到,遍历websocket集合的所有对象,调用websocket的session里面的getBasicRemote的sendText方法发送传入的message消息。

        sendMessageTo是将消息发送给指定的websocket对象,从上面可以看到,遍历websocket集合的所有对象,当用户名满足传入的接受用户时,调用websocket的session里面的getBasicRemote的sendText方法发送传入的message消息。

3、改造onOpen

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        @PathParam("username") String username用来接受前端传入的用户名,注意在ServerEndpoint注解参数改一下,加上用户名的传输。

        在onopen里面增加全局的在线人数以及websocket对象集合,保存当前用户名。

遍历webSocketSet集合,获取出来所有在线用户。

        将所有前端需要的信息包装到map,调用sendMessageAll方法,通知所有在线用户,某某用户上线了。

        此处为了前端方便处理,调用两次sendMessageAll方法,type如上图所示,分别两次sendMessageAll方法处理上线通知和用户列表更新通知。

4、改造onClose

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        该方法是连接关闭时触发,所以将当前websocket对象从websocket的集合从移除并减少在线用户数,将前端需要的数据包装好后调用sendMessageAll方法,通知前端某某用户下线了。

5、改造onMessage

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        onMessage方法是接受前端传来数据时触发。

        通过JSON.parseObject方法解析前端传过来的数据。

        获取message里面的键值对数据

        判断是群发还是私发然后调用不同的方法。

        此处私发时需要发送给对应的websocket对象还需要发送给自己。

后端的改造到此结束,下面介绍前端的代码。

第二步:创建前端html文件

<!DOCTYPE HTML>
<html>
<head>
    <title>聊天室</title>
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
	<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
	<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
	<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
	<script src="https://code.jquery.com/jquery-3.1.1.min.js"></script>
</head>
 
<body style="padding-left: 200px;padding-right: 200px;">
	<div class="alert alert-primary" style="margin-bottom: -20px;text-align: center;" role="alert">聊天室</div>
    <div class="jumbotron" style="height: 500px;width: 1135px;">
		<!-- 用户列表 -->
		<div class="jumbotron" style="height: 500px;width: 200px;float: right;background-color: green;margin-top: -65px;margin-right: -30px;">
			<div class="alert alert-primary" role="alert" style="width: 200px;margin-top: -43px;margin-left: -32px;">在线用户列表:</div>
			<ul class="list-group" id="userlist" style="width: 200px;margin-top: -18px;margin-left: -32px;">

			</ul>
		</div>
		<div id="content" style="height: 500px;width: 900px;background-color: white;margin-top: -45px;margin-left: -20px;">
			
		</div>
    </div>
	<div class="form-group">
	    <input type="text" style="width: 90%;;float: left;" class="form-control" id="message"  placeholder="请输入内容">
		<button type="button" style="width: 10%;float: left;" class="fasong">发送</button>
		<button type="button" style="width: 10%;float: left;" class="qingping">清屏</button>
	</div>
</body>
 
<script type="text/javascript">
	
	//私发全局消息
	var tomessage = "";
	//私发用户名称
	var tousername = "";
	//清屏
	$(".qingping").click(function(){
		$("#content").html(``);
	})
	
	//生成一个随机用户名
	var username = "用户"+Math.random()*100;
	
	//定义一个websocket
    var websocket = null;
 
    //判断当前浏览器是否支持WebSocket(固定写法)
    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:8090/websocket/"+username);
    }else{
        alert('浏览器不支持websocket')
    }
 
    //连接发生错误的回调方法
    websocket.onerror = function(){
        console.log("发生错误");
    };
 
    //连接成功建立的回调方法
    websocket.onopen = function(event){
        console.log("建立连接"+"event");
    }
 
    //接收到消息的回调方法
    websocket.onmessage = function(event){
		var data = JSON.parse(event.data);
		console.log(JSON.parse(event.data))
		
		//更新content的内容(上线)
		if(data.messageType=="1"){
			// console.log("成功")
			$("#content").append(`<span style="width: 100%;height: 30px;line-height: 30px;font-size: 14px;">`+data.username+"上线了"+`</span><br>`);
		}
		//更新content的内容(下线)
		if(data.messageType=="2"){
			// console.log("成功")
			$("#content").append(`<span style="width: 100%;height: 30px;line-height: 30px;font-size: 14px;">`+data.username+"下线了"+`</span><br>`);
		}
		//更新content的内容(更新用户列表)
		if(data.messageType=="3"){
			//先清空
			$("#userlist").html(``);
			var list = data.onlineUsers;
			console.log(list)
			for(var i=0;i<list.length;i++){
				$("#userlist").append(`<li style="cursor:pointer;" class="list-group-item" onclick="friend(this)" values="`+list[i]+`">`+list[i]+`</li>`);
			}
		}
		//更新content的内容(更新用户群发消息)
		if(data.messageType=="4"){
			// console.log(data);
			$("#content").append(`<span style="width: 100%;height: 30px;line-height: 30px;font-size: 14px;">`+data.username+`说:`+data.textMessage+`</span><br>`);
		}
		
	}
 
	//选择用户
	function friend(e){
		console.log(e);
		$("#message").val("@ "+e.innerHTML+" ");
		var data = e.innerHTML;
		console.log(data);
		tousername = data;
	}
 
    //连接关闭的回调方法
    websocket.onclose = function(){
        console.log("关闭连接");
    }
 
    //监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
    window.onbeforeunload = function(){
		alert("已关闭连接");
        websocket.close();
    }
 
	//发送按钮
	$(".fasong").click(function(){
		
		console.log("发送消息")
		var message = $("#message").val();
		//判断是群发还是私发
		console.log(message);
		//获取发送对象
		tousername = message.split(' ')[1];
		//获取发送消息
		tomessage = message.split(' ')[2];
		console.log(tomessage);
		console.log(tousername);
		if(message.indexOf("@")!=-1){
			//私发
			console.log("私发")
			var param = {};
			param['username'] = username;
			param['message'] = tomessage;
			param['type'] = '私发';
			param['tousername'] = tousername;
		}
		else{
			//群发
			console.log("群发")
			var param = {};
			param['username'] = username;
			param['message'] = message;
			param['type'] = '群发';
			param['tousername'] = '';
		}
		//发送消息到后端
		websocket.send(JSON.stringify(param));
	})
	
</script>
</html>

下面介绍各部分代码:

1、html代码

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        这部分代码没什么说的,我为了方便直接使用的bootstrap框架 。

2、js代码

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16        为了简便,又为了每个websocket的用户名唯一,我直接使用的随机数,在新建websocket实例里面,新增一个username参数的传递。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        接收到消息的回调方法,先使用JSON.parse()方法解析一下数据格式,再通过判断传来的数据类型type,分别进行处理。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        新增一个用户列表点击功能,点击时,将输入框显示如下,便于私聊:watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        发送按钮,获取要发送的数据,将数据包装好,调用websocket的send方法发送到后端,后端通过OnMessage注解的方法进行处理。

完毕!

第三步:演示

        此处我跑了四个websocket实例,如下:

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        可见,通知上线实现正常,接下来关闭实例4,如下:

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        下线通知正常,下面展示发送消息

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16 watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

 watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        可以看到群发成功,点击用户列表的某一用户,展示私发。

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

        可以看到,私发只有选择的那个人可以收到消息。

        到此,整合完毕。

        本期整合到此完毕,接下来会继续更新加强整合,尽情期待。

        客户端访问地址:http://localhost:8090/swagger-ui.html或者http://localhost:8090/doc.html

修改(2021/10/9)

        上面的代码忘记实现用户下线时更新用户列表

        修改一下onClose注解注解的onClose方法,如下:

 //前端关闭时一个websocket时
    @OnClose
    public void onClose() throws IOException {
        //从集合中移除当前对象
        webSocketSet.remove(this);
        //在线用户数减少
        userNumber--;

        //通知下线
        Map<String, Object> map1 = new HashMap();
        //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
        map1.put("messageType", 2);
        //所有在线用户
        map1.put("onlineUsers", this.webSocketSet);
        //下线用户的用户名
        map1.put("username", this.userName);
        //返回在线人数
        map1.put("number", userNumber);
        //发送信息,所有人,通知谁下线了
        sendMessageAll(JSON.toJSONString(map1),this.userName);

        //通知修改用户列表
        // 更新在线人数(给所有人)
        Map<String, Object> map2 = new HashMap();
        //获得所有的用户
        Set<String> userLists = new TreeSet<>();
        for (WebSocket webSocket : webSocketSet) {
            userLists.add(webSocket.userName);
        }
        //messageType 1代表上线 2代表下线 3代表在线名单 4代表普通消息
        map2.put("messageType", 3);
        //把所有用户放入map2
        map2.put("onlineUsers", userLists);
        //返回在线人数
        map2.put("number", this.userNumber);
        // 消息发送指定人(所有的在线用户信息)
        sendMessageAll(JSON.toJSONString(map2),this.userName);
        log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size());
    }

        新增部分代码如下:

watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBA5bCPeuKZgA==,size_20,color_FFFFFF,t_70,g_se,x_16

  • 107
    点赞
  • 471
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 35
    评论
### 回答1: Spring Boot是一个用于快速构建基于Spring框架的Java应用程序的开源框架。它简化了Spring应用程序的开发过程,并提供了许多内置的功能和插件,使得开发人员可以更加专注于业务逻辑的实现WebSocket是一种在Web浏览器和Web服务器之间建立持久连接的通信协议,能够实现实时双向通信。 要实现聊天软件的功能,可以使用Spring Boot来快速搭建项目结构和配置。首先,需要在pom.xml文件中添加WebSocket的依赖,例如使用SpringSpring WebSocket库: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency> ``` 然后,需要创建一个WebSocket配置类来配置WebSocket的相关信息,例如定义访问WebSocket的端点、配置消息传输方式等。可以继承Spring提供的AbstractWebSocketMessageBrokerConfigurer类,并重写相关方法: ```java @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/chat").withSockJS(); } @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic"); registry.setApplicationDestinationPrefixes("/app"); } } ``` 在上述配置类中,使用"/chat"作为WebSocket的端点,并启用了基于内存的消息代理(SimpleBroker),其中"/topic"为消息主题的前缀,"/app"为应用程序请求的前缀。 接下来,可以创建一个WebSocket处理器类来处理WebSocket的连接、关闭和消息等事件。可以实现SpringWebSocketHandler接口,并重写相关方法: ```java @Component public class ChatHandler extends TextWebSocketHandler { private static final List<WebSocketSession> sessions = new ArrayList<>(); @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { sessions.add(session); } @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { sessions.remove(session); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { for (WebSocketSession s : sessions) { s.sendMessage(message); } } } ``` 上述处理器类中,使用一个静态List来保存所有连接的WebSocketSession,以便将消息发送给所有已连接的客户端。 最后,在需要使用WebSocket的控制器或服务中,可以使用@Autowired注解将ChatHandler注入,并使用它来发送消息。 总结来说,通过以上的步骤,我们可以使用Spring Boot整合WebSocket实现聊天软件的功能。当有新的WebSocket连接建立时,我们将其保存在一个静态List中,并在收到消息时将消息发送给所有的连接。通过Spring Boot的简化开发流程和WebSocket的实时双向通信特性,实现了一个简单的聊天软件。 ### 回答2: Spring Boot是一个用于开发Java应用程序的框架,它能够帮助开发人员更快速、更简洁地构建应用程序。WebSocket是HTML5新增的一种协议,它能够在客户端与服务器之间建立持久的双向通信连接,实时地传输数据。 要实现聊天软件的功能,首先需要导入Spring Boot和WebSocket的相关依赖。在pom.xml文件中添加Spring Boot和WebSocket的依赖项。 在Spring Boot的主类中,使用@EnableWebSocket注解启用WebSocket的支持。编写一个WebSocket处理器类,继承自TextWebSocketHandler,并重写其中的方法。在onTextMessage方法中处理接收到的文本消息,在sendMessage方法中处理发送消息。 配置WebSocket的映射路径和处理器,使用@Configuration注解和实现WebSocketConfigurer接口。重写registerWebSocketHandlers方法,设置WebSocket的映射路径和处理器。 在前端界面中,使用JavaScript代码连接WebSocket服务器,并处理接收消息和发送消息的逻辑。通过WebSocket对象的onmessage方法处理接收到的消息,并将消息显示在聊天界面上。通过WebSocket对象的send方法发送消息给服务器。 通过以上步骤,就可以实现Spring Boot和WebSocket整合,从而实现聊天软件的功能。开发人员可以根据具体的需求,进一步完善聊天软件的功能,例如用户名的验证、消息的存储和管理等。 总结起来,使用Spring Boot和WebSocket可以快速、简洁地实现聊天软件。借助Spring Boot的开发效率和WebSocket的实时通信功能,开发人员能够轻松地构建出高效、稳定的聊天软件。 ### 回答3: Spring Boot 是一个基于 Spring 框架的开源服务端开发框架,提供了快速开发和方便部署的特性。WebSocket 是一种基于TCP协议的双向通信协议,通过浏览器与服务器建立持久连接,实现实时通信。 使用 Spring Boot 整合 WebSocket 实现聊天软件的步骤如下: 1. 创建一个 Spring Boot 项目,引入 WebSocket 依赖包。 2. 在配置类上添加 `@EnableWebSocket` 注解以启用 WebSocket 功能。 3. 创建一个 WebSocket 处理器类,继承自 `TextWebSocketHandler`,覆写其中的方法,如 `handleTextMessage()` 和 `afterConnectionEstablished()`。 4. 在 `handleTextMessage()` 方法中,获取客户端发送的消息,处理后将消息发送给所有连接到服务器的客户端。 5. 在 `afterConnectionEstablished()` 方法中,可以处理客户端连接成功后的逻辑。 6. 创建一个控制器类,处理客户端与服务器的交互,如发送消息、接收消息等。 7. 在控制器类中,使用 `@Autowired` 注入 WebSocket 处理器类的对象,并通过该对象发送消息给客户端。 8. 在前端页面中使用 JavaScript 创建 WebSocket 连接,并实现相应的回调函数,实现与服务器的实时通信。 通过以上步骤,可以实现一个简单的聊天软件。用户在页面上发送消息,消息通过 WebSocket 连接发送到服务器,服务器将消息广播给所有客户端,实现实时聊天的功能。 总之,借助 Spring Boot 提供的便利性和 WebSocket 协议的实时通信特性,可以快速实现一个聊天软件。不仅可以在浏览器上实现聊天功能,还可以通过移动端等其他客户端实现跨平台的聊天应用。
评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小z♂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值