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

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

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

什么是websocket?

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

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

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

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

特點(diǎn)

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

技術(shù)

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

實(shí)現(xiàn)(簡(jiǎ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("當(dāng)前在線人數(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("連接出錯(cuò)"+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("當(dāng)前在線人數(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;

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

    //連接發(fā)生錯(cuò)誤的回調(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)閉事件,當(dāng)窗口關(guān)閉時(shí),主動(dòng)去關(guān)閉websocket連接,防止連接還沒斷開就關(guān)閉窗口,server端會(huì)拋異常。
    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>

測(cè)試

先啟動(dòng)服務(wù)

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

結(jié)尾

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

相關(guān)文章

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

    分析Java中為什么String不可變

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

    Mybatis實(shí)戰(zhàn)之TypeHandler高級(jí)進(jìn)階

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

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

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

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

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

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

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

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

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

    Springboot項(xiàng)目參數(shù)校驗(yàn)方式(Validator)

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

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

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

    教你用Java實(shí)現(xiàn)一個(gè)簡(jiǎn)單的代碼生成器

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

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

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

最新評(píng)論

尼玛县| 松桃| 安福县| 法库县| 长沙市| 阿拉善右旗| 綦江县| 绩溪县| 肃宁县| 梁平县| 定结县| 平定县| 奎屯市| 厦门市| 赤城县| 东平县| 莎车县| 新巴尔虎左旗| 新宾| 桓台县| 黑水县| 安达市| 辰溪县| 平陆县| 新民市| 昌黎县| 临沭县| 乌什县| 冀州市| 易门县| 盈江县| 旅游| 东至县| 含山县| 怀宁县| 杂多县| 噶尔县| 色达县| 安岳县| 余庆县| 曲沃县|