最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot+WebSocket實現(xiàn)即時通訊功能(Spring方式)

 更新時間:2023年10月30日 08:44:31   作者:晚上睡不著_  
今天給大家分享一個SpringBoot+WebSocket實現(xiàn)即時通訊功能(Spring方式),WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議,文章通過代碼示例給大家介紹的非常詳細,需要的朋友可以參考下

什么是websocket?

WebSocket是一種在單個TCP連接上進行全雙工通信的協(xié)議。WebSocket通信協(xié)議于2011年被IETF定為標準RFC 6455,并由RFC7936補充規(guī)范。WebSocket API也被W3C定為標準。
WebSocket使得客戶端和服務(wù)器之間的數(shù)據(jù)交換變得更加簡單,允許服務(wù)端主動向客戶端推送數(shù)據(jù)。在WebSocket API中,瀏覽器和服務(wù)器只需要完成一次握手,兩者之間就直接可以創(chuàng)建持久性的連接,并進行雙向數(shù)據(jù)傳輸。

為什么有了HTTP協(xié)議還要WebSocket

HTTP協(xié)議采用的是客戶端(瀏覽器)輪詢的方式,即客戶端發(fā)送請求,服務(wù)端做出響應(yīng),為了獲取最新的數(shù)據(jù),需要不斷的輪詢發(fā)出HTTP請求,占用大量帶寬。
WebSocket采用了一些特殊的報頭,使得瀏覽器和服務(wù)器只需要通過“握手”建立一條連接通道后,此鏈接保持活躍狀態(tài),之后的客戶端和服務(wù)器的通信都使用這個連接,解決了Web實時性的問題,相比于HTTP有一下好處:

一個Web客戶端只建立一個TCP連接
WebSocket服務(wù)端可以主動推送(push)數(shù)據(jù)到Web客戶端
有更加輕量級的頭,減少了數(shù)據(jù)傳輸量

特點

  • 建立在TCP協(xié)議只上,服務(wù)端比較容易實現(xiàn)
  • 于HTTP協(xié)議有良好的兼容性,默認端口也是80和443,握手階段使用HTTP協(xié)議,因此握手時不容易屏蔽,能通過各種HTTP代理服務(wù)器
  • 數(shù)據(jù)格式輕量,通信高效且節(jié)省帶寬
  • 支持傳輸文本數(shù)據(jù)和二進制數(shù)據(jù)
  • 沒有同源限制,客戶端可以與任意服務(wù)器通信
  • 也支持加密傳輸,WS+SSL,URL形如wss://

技術(shù)

  • jdk8
  • maven
  • SpringBoot2.7.4
  • thmeleaf
  • websocket

實現(xiàn)(簡易websocket聊天室)

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.4</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>websocket</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>websocket</name>
    <description>websocket</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</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-websocket</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

websocketHandler.java

package com.example.websocket.handler;


import org.springframework.stereotype.Component;
import org.springframework.web.socket.*;

import java.io.IOException;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class WebsocketHandler implements WebSocketHandler {

    private static final Map<String, WebSocketSession> SESSIONS = new ConcurrentHashMap<>();
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        System.out.println("連接成功"+session.getId());
        SESSIONS.put(session.getId(), session);
        System.out.println("當前在線人數(shù):"+SESSIONS.size());
    }

    @Override
    public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception {
        System.out.println("接收消息"+session.getId());
        String msg = message.getPayload().toString();
        System.out.println(msg);
//        session.sendMessage(message);
        sendMessageToAllUsers(session.getId()+":"+msg);
    }

    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.out.println("連接出錯"+session.getId());
        if (!session.isOpen()) {
            SESSIONS.remove(session.getId());
            session.close();
        }
    }

    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception {
        System.out.println("關(guān)閉連接"+session.getId());
        if(!session.isOpen()){
            SESSIONS.remove(session.getId());
            System.out.println("當前在線人數(shù):"+SESSIONS.size());
        }
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }

    /**
     * sendMessageToUser:發(fā)給指定用戶
     *
     */
    public void sendMessageToUser(String userId, String contents) {
        WebSocketSession session = SESSIONS.get(userId);
        if (session != null && session.isOpen()) {
            try {
                TextMessage message = new TextMessage(contents);
                session.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * sendMessageToAllUsers:發(fā)給所有的用戶
     *
     */
    public void sendMessageToAllUsers(String contents) {
        Set<String> userIds = SESSIONS.keySet();
        for (String userId : userIds) {
            this.sendMessageToUser(userId, contents);
        }
    }
}

WebsocketInterceptor.java

package com.example.websocket.interceptor;

import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.server.HandshakeInterceptor;

import java.util.Map;

@Component
public class WebsocketInterceptor implements HandshakeInterceptor {
    @Override
    public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception {
        System.out.println("前置攔截");
        return true;
    }

    @Override
    public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) {
        System.out.println("后置攔截");
    }
}

WebsocketConfig.java

package com.example.websocket.config;

import com.example.websocket.handler.WebsocketHandler;
import com.example.websocket.interceptor.WebsocketInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;

@Component
@EnableWebSocket
public class WebsocketConfig implements WebSocketConfigurer {
    @Autowired
    private  WebsocketHandler websocketHandler;
    @Autowired
    private WebsocketInterceptor websocketInterceptor;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(websocketHandler, "/ws").setAllowedOrigins("*").addInterceptors(websocketInterceptor);
    }
}

WebsocketController.java

package com.example.websocket.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class WebsocketController {

    @GetMapping("/")
    public String init() {
        return "websocket";
    }

    @GetMapping("/chat")
    public String chat() {
        return "chatRoom";
    }
}

WebsocketApplication.java

package com.example.websocket;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class WebsocketApplication {

    public static void main(String[] args) {
        SpringApplication.run(WebsocketApplication.class, args);
    }

}

前端

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>My WebSocket Test</title>
    <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet"  rel="external nofollow"  integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" crossorigin="anonymous">

    <!-- 可選的 Bootstrap 主題文件(一般不用引入) -->
    <link rel="stylesheet"  rel="external nofollow"  integrity="sha384-6pzBo3FDv/PJ8r2KRkGHifhEocL+1X2rVCTTkUfGk7/0pbek5mMa1upzvWbrUbOZ" crossorigin="anonymous">

    <!-- 最新的 Bootstrap 核心 JavaScript 文件 -->
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
</head>
<body>

Welcome<br/>
<div id="message"></div>
<input id="text" type="text" />
<button class="btn btn-primary" onclick="send()">Send</button>
<button class="btn btn-danger"onclick="closeWebSocket()">Close</button>
</body>

<script type="text/javascript">

    var websocket = null;

    //判斷當前瀏覽器是否支持WebSocket
    if('WebSocket' in window){
        websocket = new WebSocket("ws://localhost:8080/ws");
    }
    else{
        alert('Not support websocket')
    }

    //連接發(fā)生錯誤的回調(diào)方法
    websocket.onerror = function(){
        setMessageInnerHTML("error");
    };

    //連接成功建立的回調(diào)方法
    websocket.onopen = function(event){
        setMessageInnerHTML("open");
    }

    //接收到消息的回調(diào)方法
    websocket.onmessage = function(event){
        setMessageInnerHTML(event.data);
    }

    //連接關(guān)閉的回調(diào)方法
    websocket.onclose = function(){
        setMessageInnerHTML("close");
    }

    //監(jiān)聽窗口關(guān)閉事件,當窗口關(guān)閉時,主動去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會拋異常。
    window.onbeforeunload = function(){
        websocket.close();
    }

    //將消息顯示在網(wǎng)頁上
    function setMessageInnerHTML(innerHTML){
        document.getElementById('message').innerHTML += innerHTML + '<br/>';
    }

    //關(guān)閉連接
    function closeWebSocket(){
        websocket.close();
    }

    //發(fā)送消息
    function send(){
        var message = document.getElementById('text').value;
        websocket.send(message);
        message.value("");
    }
</script>
</html>

測試

先啟動服務(wù)

然后我們就可以愉快聊天了

結(jié)尾

到這我們的簡單版的ws長連接聊天室就做好了,以上就是SpringBoot+WebSocket實現(xiàn)即時通訊功能(Spring方式)的詳細內(nèi)容,更多關(guān)于SpringBoot+WebSocket即時通訊的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 分析Java中為什么String不可變

    分析Java中為什么String不可變

    Java中為什么String是不可變性的。今天我們從多角度解析為什么Java把String做成不可變的。
    2021-06-06
  • Mybatis實戰(zhàn)之TypeHandler高級進階

    Mybatis實戰(zhàn)之TypeHandler高級進階

    本文主要介紹了自定義的枚舉TypeHandler的相關(guān)知識,具有很好的參考價值,下面跟著小編一起來看下吧
    2017-02-02
  • 解決出現(xiàn) java.lang.ExceptionInInitializerError錯誤問題

    解決出現(xiàn) java.lang.ExceptionInInitializerError錯誤問題

    這篇文章主要介紹了解決出現(xiàn) java.lang.ExceptionInInitializerError錯誤問題的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • Java如何基于IO流實現(xiàn)同一文件讀寫操作

    Java如何基于IO流實現(xiàn)同一文件讀寫操作

    這篇文章主要介紹了Java如何基于IO流實現(xiàn)文件讀寫操作,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-10-10
  • Java使用easyExcel批量導入數(shù)據(jù)詳解

    Java使用easyExcel批量導入數(shù)據(jù)詳解

    這篇文章主要介紹了Java使用easyExcel批量導入數(shù)據(jù)詳解,通常我們會提供一個模板,此模塊我們可以使用easyExcel導出數(shù)據(jù)生成的一個Excel文件當作模板,提供下載鏈接,用戶在該文件內(nèi)填入規(guī)定的數(shù)據(jù)格式以后可以批量導入數(shù)據(jù)到數(shù)據(jù)庫中,需要的朋友可以參考下
    2023-08-08
  • SpringBoot多環(huán)境配置數(shù)據(jù)讀取方式

    SpringBoot多環(huán)境配置數(shù)據(jù)讀取方式

    SpringBoot通過環(huán)境隔離機制,支持properties/yaml/yml多格式配置,結(jié)合@Value、Environment和@ConfigurationProperties實現(xiàn)靈活配置讀取,下面給大家介紹SpringBoot之多環(huán)境配置全解析,感興趣的朋友一起看看吧
    2025-07-07
  • Springboot項目參數(shù)校驗方式(Validator)

    Springboot項目參數(shù)校驗方式(Validator)

    本文介紹了如何在Spring Boot項目中使用`spring-boot-starter-validation`包和注解來實現(xiàn)請求參數(shù)校驗,主要介紹了校驗注解的使用方法、校驗失敗的異常捕獲以及`@Validated`的分組功能
    2025-02-02
  • SpringCloudStream原理和深入使用小結(jié)

    SpringCloudStream原理和深入使用小結(jié)

    Spring?Cloud?Stream是一個用于構(gòu)建與共享消息傳遞系統(tǒng)連接的高度可擴展的事件驅(qū)動型微服務(wù)的框架,本文給大家介紹SpringCloudStream原理和深入使用,感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • 教你用Java實現(xiàn)一個簡單的代碼生成器

    教你用Java實現(xiàn)一個簡單的代碼生成器

    今天給大家?guī)淼氖顷P(guān)于Java的相關(guān)知識,文章圍繞著如何用Java實現(xiàn)一個簡單的代碼生成器展開,文中有非常詳細的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • 淺談Java中Unicode的編碼和實現(xiàn)

    淺談Java中Unicode的編碼和實現(xiàn)

    這篇文章向大家介紹了Java編程中Unicode編碼及實現(xiàn)的相關(guān)內(nèi)容,列舉了幾個字符不同表達式的比較,以及Unicode平面映射的知識,具有一點點參考價值,需要的朋友可以了解下。
    2017-10-10

最新評論

安溪县| 兴仁县| 霍林郭勒市| 高碑店市| 衡阳县| 泸西县| 彩票| 察隅县| 车致| 交口县| 榆树市| 马鞍山市| 榆中县| 西峡县| 将乐县| 鹤庆县| 南充市| 九寨沟县| 定结县| 鲁甸县| 湟中县| 河东区| 美姑县| 宿松县| 平利县| 库车县| 宾川县| 孟津县| 平泉县| 高唐县| 麦盖提县| 观塘区| 舒兰市| 汉中市| 开封市| 兴业县| 松原市| 江阴市| 柘城县| 潜江市| 墨竹工卡县|