您好!欢迎来到北极熊

北极熊

热门搜索: 任正非传    神雕侠侣    红楼梦   

SpringBoot如何添加WebSocket

分类:技术交流 时间:2020-10-29 12:19 浏览:278
概述
SpringBoot+WebSocket一、WebSocket介绍二、WebSocket运行机制三、WebSocket实现一、WebSocket介绍网站上的即时通讯是很常见的,比如网页的QQ,聊天系统等。按照以往的技术能力通常是采用轮询、Comet技术解决。HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器
内容

SpringBoot+WebSocket

  • 一、WebSocket介绍

  • 二、WebSocket运行机制

  • 三、WebSocket实现



一、WebSocket介绍

网站上的即时通讯是很常见的,比如网页的QQ,聊天系统等。按照以往的技术能力通常是采用轮询、Comet技术解决。
HTTP协议是非持久化的,单向的网络协议,在建立连接后只允许浏览器向服务器发出请求后,服务器才能返回相应的数据。当需要即时通讯时,通过轮询在特定的时间间隔(如1秒),由浏览器向服务器发送Request请求,然后将最新的数据返回给浏览器。这样的方法最明显的缺点就是需要不断的发送请求,而且通常HTTP request的Header是非常长的,为了传输一个很小的数据 需要付出巨大的代价,是很不合算的,占用了很多的宽带。
缺点:会导致过多不必要的请求,浪费流量和服务器资源,每一次请求、应答,都浪费了一定流量在相同的头部信息上
然而WebSocket的出现可以弥补这一缺点。在WebSocket中,只需要服务器和浏览器通过HTTP协议进行一个握手的动作,然后单独建立一条TCP的通信通道进行数据的传送。

二、WebSocket运行机制

WebSocket 是 HTML5 一种新的协议,也是一个典型的应用层协议。它实现了浏览器与服务器全双工通信,能更好的节省服务器资源和带宽并达到实时通讯,它建立在 TCP 之上,同 HTTP 一样通过 TCP 来传输数据,但是它和 HTTP 最大不同是:
WebSocket 是一种双向通信协议,在建立连接后,WebSocket 服务器和 Browser/Client Agent 都能主动的向对方发送或接收数据,就像 Socket 一样;
WebSocket 需要类似 TCP 的客户端和服务器端通过握手连接,连接成功后才能相互通信。
非 WebSocket 模式传统 HTTP 客户端与服务器的交互如下图所示:

使用 WebSocket 模式客户端与服务器的交互如下图:
在这里插入图片描述

三、WebSocket实现

这里通过一个简单的聊天例程,实现spring boot +websocket代码的演示。
引入maven

 <!-- websocket -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
            <version>2.3.4.RELEASE</version>
        </dependency>123456

配置类WebConfig

package org.antry.config;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.web.socket.server.standard.ServerEndpointExporter;/**
 * @ClassName WebSocketConfig
 * @Description TODO
 * @Autor TT
 * @Date 2020/10/9 23:00
 * @Version 1.0
 */@Configurationpublic class WebSocketConfig {

    @Bean    public ServerEndpointExporter serverEndpointExporter() {
        return new ServerEndpointExporter();
    }}12345678910111213141516171819202122

WebSocket类
在这个类里,有一个集合,用来存放所有连接。
当有新的连接进来时,在onOpen()方法中,我们每个连接都会存下对应id作为标识。假设这个id已经存过,则会关闭此连接,防止同一个id多处登录。
连接断开时,在onClose()方法中,将此连接移出集合。
当有新的消息发送过来时,会去遍历连接,找到对应接收人id的连接,然后把消息推送给接收人。

package org.antry.websocket;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.List;import java.util.concurrent.CopyOnWriteArrayList;import java.util.concurrent.atomic.AtomicInteger;/**
 * @ClassName MyWebsocket
 * @Description TODO
 * @Autor TT
 * @Date 2020/10/10 11:02
 * @Version 1.0
 */@ServerEndpoint(value = "/websocket/{user}")@Componentpublic class MyWebsocket {
    // 通过类似GET请求方式传递参数的方法(服务端采用第二种方法"WebSocketHandler"实现)//    websocket = new WebSocket("ws://127.0.0.1:18080/testWebsocket?id=23&name=Lebron");
    /**
     * 在线人数
     */
    public static AtomicInteger onlineNumber = new AtomicInteger(0);

    /**
     * 所有的对象,每次连接建立,都会将我们自己定义的MyWebsocket存放到List中,
     */
    public static List<MyWebsocket> webSockets = new CopyOnWriteArrayList<MyWebsocket>();

    /**
     * 会话,与某个客户端的连接会话,需要通过它来给客户端发送数据
     */
    private Session session;

    /**
     * 每个会话的用户
     */
    private String user;
    /**
     * 建立连接
     *
     * @param session
     */
    @OnOpen    public void onOpen(Session session, @PathParam("user") String user) {
        System.err.println(user);
        if (user == null || "".equals(user)) {
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        onlineNumber.incrementAndGet();
        for (MyWebsocket MyWebsocket : webSockets) {
            if (user.equals(MyWebsocket.user)) {
                try {
                    session.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                return;
            }
        }
        this.session = session;
        this.user = user;
        webSockets.add(this);
    }
    /**
     * 连接关闭
     */
    @OnClose    public void onClose() {
        onlineNumber.decrementAndGet();
        webSockets.remove(this);
    }
    /**
     * 收到客户端的消息
     *
     * @param message 消息
     * @param session 会话
     */
    @OnMessage    public void onMessage(String message, Session session, @PathParam("user") String user) {
        System.err.println(message);
        String[] strArr = message.split("~");
        pushMessage(user,strArr[0],strArr[1]);
    }
    /**
     * 发送消息
     *
     * @param message 消息
     */
    public void sendMessage(String message) {
        try {
            session.getBasicRemote().sendText(message);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 消息推送
     *
     * @param message
     * @param uuid    uuid为空则推送全部人员
     */
    public static void pushMessage(String user, String message, String uuid) {

        if (uuid == null || "".equals(uuid)) {
            for (MyWebsocket MyWebsocket : webSockets) {
                MyWebsocket.sendMessage(user + ":" + message);
            }
        } else {
            for (MyWebsocket MyWebsocket : webSockets) {
                if (uuid.equals(MyWebsocket.user)) {
                    MyWebsocket.sendMessage(message);
                }
            }
        }
    }}123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129

两个简单的前端页面,他们的不同是,接收id和发送id不同。
testOne.html

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <title>聊天窗口1</title>

    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="public/dist/lib/uploader/zui.uploader.min.css" rel="stylesheet"></head><body>
    <div>
        <div class="input-group">
            <input type="text" class="form-control" id="msg">
            <span class="input-group-btn">
        <button class="btn btn-default" type="button" onclick="send()">发送</button>
  </span>
        </div>
    </div><script src="public/dist/lib/jquery/jquery.js"></script><script src="public/dist/js/zui.min.js"></script><script src="public/layer/layer.js"></script><script src="public/js/function.js"></script><script src="public/js/testOne.js"></script></body></html>12345678910111213141516171819202122232425262728

testOne.js

var websocket = null;var sendId = 0;var receiveId = 1;//---------------------------/**
 * 初始化websocket
 * @param id
 */doInit(sendId)function doInit(sendId){
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws:localhost:10086/websocket/" + sendId);
    } else {
        alert("浏览器不支持");
    }
    websocket.onopen = function () {
        addMessage("webscoket已经连接成功");
    };
    websocket.onclose = function () {
        addMessage("webscoket连接失败");
    };
    websocket.onmessage = function (event) {
        alert("收到消息:"+event.data);
    };
    websocket.onerror = function () {
        addMessage("webscoket连接失败");
    };}/**
 * 发送一条消息
 */function send(){
    websocket.send(value('msg')+"~"+receiveId);}/**
 * 测试打印调试信息用
 * @param msg
 */function  addMessage(msg) {
    console.log(msg)}1234567891011121314151617181920212223242526272829303132333435363738394041

testTwo.html

<!DOCTYPE html><html lang="en"><head>
    <meta charset="UTF-8">
    <title>聊天窗口2</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="public/dist/lib/uploader/zui.uploader.min.css" rel="stylesheet"></head><body><div>
    <div class="input-group">
        <input type="text" class="form-control" id="msg">
        <span class="input-group-btn">
        <button class="btn btn-default" type="button" onclick="send()">发送</button>
  </span>
    </div></div><script src="public/dist/lib/jquery/jquery.js"></script><script src="public/dist/js/zui.min.js"></script><script src="public/layer/layer.js"></script><script src="public/js/function.js"></script><script src="public/js/testTwo.js"></script></body></html>1234567891011121314151617181920212223242526

testTwo.js

var websocket = null;var sendId = 1;var receiveId = 0;//---------------------------/**
 * 初始化websocket
 * @param id
 */doInit(sendId)function doInit(receiveId){
    if ('WebSocket' in window) {
        websocket = new WebSocket("ws:localhost:10086/websocket/" + sendId);
    } else {
        alert("浏览器不支持");
    }
    websocket.onopen = function () {
        addMessage("webscoket已经连接成功");
    };
    websocket.onclose = function () {
        addMessage("webscoket连接失败");
    };
    websocket.onmessage = function (event) {
        alert("收到消息:"+event.data);
    };
    websocket.onerror = function () {
        addMessage("webscoket连接失败");
    };}/**
 * 发送一条消息
 */function send(){
    websocket.send(value('msg')+"~"+receiveId);}/**
 * 测试打印调试信息用
 * @param msg
 */function  addMessage(msg) {
    console.log(msg)}1234567891011121314151617181920212223242526272829303132333435363738394041

分别用两个浏览器,打开这两个页面进行访问。结果如下
在这里插入图片描述

在这里插入图片描述


评论
资讯正文页右侧广告
联系我们
电话:18936411277
邮箱:1044412291@qq.com
时间:09:00 - 19:00
公众号:北格软件
底部广告