开发者

SpringBoot整合WebSocket实现聊天室流程全解

开发者 https://www.devze.com 2023-01-04 10:38 出处:网络 作者: 欲无缘
目录什么是WebSocket WebSocket通信模型为什么需要WebSocketWebsocket与http的关系SpringBoot集成WebSocket什么是WebSocket 
目录
  • 什么是WebSocket 
  • WebSocket通信模型
  • 为什么需要WebSocket
  • Websocket与http的关系
  • SpringBoot集成WebSocket

什么是WebSocket 

WebSocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。

WebSocket通信模型

SpringBoot整合WebSocket实现聊天室流程全解

为什么需要WebSocket

http 通信是单向的,发送请求获取响应,没有请求也就没有响应。

简单理解:

  • HTTP 打电话:客户端问一句服务端答一句
  • WebSocket 打电话:双向对话

SpringBoot整合WebSocket实现聊天室流程全解

Websocket与http的关系

SpringBoot整合WebSocket实现聊天室流程全解

相同点:

  • 都是基于tcp的,都是可靠性传输协议
  • 都是应用层协议

不同点:

  • WebSocket是双向通信协议,模拟SocOlvJVZZngyket协议,可以双向发送或接受信息
  • HTTP是单向的
  • WebSocket是需要浏览器和服务器握手进行建立连接的而http是浏览器发起向服务器的连接,服务器预先并不知道这个连接。

SpringBoot集成WebSocket

maven依赖

		<dependency>  
           <groupId>org.springframework.boot</groupId>  
           <artifactId>spring-boot-starter-websocket</artifactId>  
       </dependency> 

WebSocketConfig

@Configuration  
public class WebSocketConfig {  
    @Bean  
    public ServerEndpointExporter serverEndpointExporter() {  
        return new ServerEndpointExporter();  
    }  
}

WebSocketService

@Slf4j
@Service
@ServerEndpoint(value = "/myService/{userId}")
public class WebSocketService {
    /**
     * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
     */
    private static AtomicInteger onlineCount = new AtomicInteger(0);;
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
     */
    private static ConcurrentHashMap<String,WebSocketService> webSocketMap = new ConcurrentHashMap<>();
    /**
     * concurrent包的线程安全Set,用来存放每个客户端对应的session对象。
     */
    private static ConcurrentHashMap<String,Session> sessionMap = new ConcurrentHashMap<>();
    /**
     * 与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;
    private String userId = "";
    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session,@PathParam("userId") String userId) {
        this.session = session;
        this.userId = userId;
        if(webSocketMap.containsKey(userId) && sessionMap.containsKey(userId)){
            webSocketMap.remove(userId);
            sessionMap.remove(userId);
            sessionMap.put(userId,session);
            webSocketMap.put(userId,this);
        }else{
            webSocketMap.put(userId,this);
            sessionMap.put(userId,session);
            addOnlineCount();
        }
        log.info("用户连接:"+userId+",当前在线人数为:" + getOnlineCount());
    }
    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        if(webSocketMap.containsKey(userId)){
            webSocketMap.remove(userId);
            subOnlineCount();
        }
        log.info("用户退出:"+userId+",当前在线人数为:" + getOnlineCount());
    }
    /**
     * 收到客户端消息后调用的方法
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        this.session = session;
        log.info("收到客户端消息 -> {}",message);
        //服务端收到客户端的消息并推送给客户端
        sendMessage(message);开发者_Python入门
    }
    /**
     * 发生错误时调用
     */
    @OnError
    public void onError(Session session, Throwable error) {
       log.error(error.getMessage());
    }
    /**
     * 实现服务器主动推送   可以通过controller调用此方法实现主动推送
     */
    public void sendMessage(String message){
        try {
            Set<Map.Entry<String, Session>> entries = sessionMap.entrySet();
            for (Map.Entry<String, Session> next : entries) {
                Session session = next.getValue();
                session.getBasicRemote().sendText(this.userId + "说" + message);
            }
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }
    public static synchronized int getOnlineCount() {
        return onlineCount.get();
    }
    public static synchronized void addOnlineCount() {
        WebSocketService.onlineCount.getAndIncrement();
    }
    public static synchronized void subOnlineCount() {
        WebSocketService.onlineCount.getAndDecrement();
    }
}

WebSocket.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>websocket通讯</title>
</head>
<body>
	<p>userId:<input id="userId" name="userId" type="text" value="10"></p>
	<p>msg:<inpuandroidt id="contentText" name="contentText" type="text" value="hello websocket"></p&ghttp://www.devze.comt;
	<p>操作:<button onclick="openSocket()">开启socket</button></p>
	<p>操作:<button onclick="sendMessage()">发送消息</button></p>
</body>
<script type="application/jwww.devze.comavascript">
    let socket;
    function openSocket() {
        if(socket != null){
            socket.close();
            socket = null;
        }
        let userId = document.getElementById('userId').value
        socket = new WebSocket("ws://localhost:9000/myService/"+userId);
        //打开事件
        socket.onopen = function() {
            console.log("websocket已打开");
        };
        //获得消息事件
        socket.onmessage = function(msg) {
            console.log(msg.data);
        };
        //关闭事件
        socket.onclose = function() {
            console.log("websocket已关闭");编程
        };
        //发生了错误事件
        socket.onerror = function() {
            console.log("websocket发生了错误");
        }
    }
    function sendMessage() {
        let contentText = document.getElementById('contentText').value
        socket.send(contentText);
    }
</script>
</html>

测试

SpringBoot整合WebSocket实现聊天室流程全解

到此这篇关于SpringBoot整合WebSocket实现聊天室流程全解的文章就介绍到这了,更多相关SpringBoot WebSocket聊天室内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号