前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >WebSocket | 为什么你前后端推送不会用?因为你少了WebSocket的帮忙

WebSocket | 为什么你前后端推送不会用?因为你少了WebSocket的帮忙

作者头像
netkiller old
发布于 2021-01-11 03:01:27
发布于 2021-01-11 03:01:27
83000
代码可运行
举报
文章被收录于专栏:NetkillerNetkiller
运行总次数:0
代码可运行

Hi! 我是小小,今天是本周的第三篇,本篇将会着重的讲解关于WebSocket的相关知识,本篇开始讲解。

什么是WebSocket

WebSocket是一种基于TCP的网络协议,实现了客户端和服务端的全双工通信,即,后端可以推送数据到客户端,客户端可以推送数据到后端。其模型如下所示:

下面开始对SpringBoot进行整合,项目结构如下所示:

使用步骤

添加依赖

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	<dependency>  
           <groupId>org.springframework.boot</groupId>  
           <artifactId>spring-boot-starter-websocket</artifactId>  
    </dependency>

启用SpringBoot对WebSocket的支持

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

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

核心配置,WebSocketServer

WebSocket采用的是ws协议,所以WebSocket Server相当于一个Controller

1. @ServerEndpoint是一个类层次注解,主要是用于定义为WebSocket服务器端,用于获取URL地址,通过地址可以访问WebSocket

2. webSocketMap用于接收当前的userID,方便进行WebSocket的管理。其代码如下所示:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
package cc.mrbird.febs.external.webScoket;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.concurrent.CopyOnWriteArraySet;

@Component
@Slf4j
@Service
@ServerEndpoint("/api/websocket/{sid}")
public class WebSocketServer {
    //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。
    private static int onlineCount = 0;
    //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
    private static CopyOnWriteArraySet<WebSocketServer> webSocketSet = new CopyOnWriteArraySet<WebSocketServer>();

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

    //接收sid
    private String sid = "";

    /**
     * 连接建立成功调用的方法
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("sid") String sid) {
        this.session = session;
        webSocketSet.add(this);     //加入set中
        this.sid = sid;
        addOnlineCount();           //在线数加1
        try {
            sendMessage("conn_success");
            log.info("有新窗口开始监听:" + sid + ",当前在线人数为:" + getOnlineCount());
        } catch (IOException e) {
            log.error("websocket IO Exception");
        }
    }

    /**
     * 连接关闭调用的方法
     */
    @OnClose
    public void onClose() {
        webSocketSet.remove(this);  //从set中删除
        subOnlineCount();           //在线数减1
        //断开连接情况下,更新主板占用情况为释放
        log.info("释放的sid为:"+sid);
        //这里写你 释放的时候,要处理的业务
        log.info("有一连接关闭!当前在线人数为" + getOnlineCount());

    }

    /**
     * 收到客户端消息后调用的方法
     * @ Param message 客户端发送过来的消息
     */
    @OnMessage
    public void onMessage(String message, Session session) {
        log.info("收到来自窗口" + sid + "的信息:" + message);
        //群发消息
        for (WebSocketServer item : webSocketSet) {
            try {
                item.sendMessage(message);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * @ Param session
     * @ Param error
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    public void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    /**
     * 群发自定义消息
     */
    public static void sendInfo(String message, @PathParam("sid") String sid) throws IOException {
        log.info("推送消息到窗口" + sid + ",推送内容:" + message);

        for (WebSocketServer item : webSocketSet) {
            try {
                //这里可以设定只推送给这个sid的,为null则全部推送
                if (sid == null) {
//                    item.sendMessage(message);
                } else if (item.sid.equals(sid)) {
                    item.sendMessage(message);
                }
            } catch (IOException e) {
                continue;
            }
        }
    }

    public static synchronized int getOnlineCount() {
        return onlineCount;
    }

    public static synchronized void addOnlineCount() {
        WebSocketServer.onlineCount++;
    }

    public static synchronized void subOnlineCount() {
        WebSocketServer.onlineCount--;
    }

    public static CopyOnWriteArraySet<WebSocketServer> getWebSocketSet() {
        return webSocketSet;
    }
}

测试Controller

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Controller("web_Scoket_system")
@RequestMapping("/api/socket")
public class SystemController {
    //页面请求
    @GetMapping("/index/{userId}")
    public ModelAndView socket(@PathVariable String userId) {
        ModelAndView mav = new ModelAndView("/socket1");
        mav.addObject("userId", userId);
        return mav;
    }

    //推送数据接口
    @ResponseBody
    @RequestMapping("/socket/push/{cid}")
    public Map pushToWeb(@PathVariable String cid, String message) {
        Map<String,Object> result = new HashMap<>();
        try {
            WebSocketServer.sendInfo(message, cid);
            result.put("code", cid);
            result.put("msg", message);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

测试页面Index.html

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html>

	<head>
		<meta charset="utf-8">
		<title>Java后端WebSocket的Tomcat实现</title>
		<script type="text/javascript" src="js/jquery.min.js"></script>
	</head>

	<body>
		<div id="main" style="width: 1200px;height:800px;"></div>
		Welcome<br/><input id="text" type="text" />
		<button onclick="send()">发送消息</button>
		<hr/>
		<button onclick="closeWebSocket()">关闭WebSocket连接</button>
		<hr/>
		<div id="message"></div>
	</body>
	<script type="text/javascript">
		var websocket = null;
		//判断当前浏览器是否支持WebSocket
		if('WebSocket' in window) {
			//改成你的地址
			websocket = new WebSocket("ws://192.168.100.196:8082/api/websocket/100");
		} else {
			alert('当前浏览器 Not support websocket')
		}

		//连接发生错误的回调方法
		websocket.onerror = function() {
			setMessageInnerHTML("WebSocket连接发生错误");
		};

		//连接成功建立的回调方法
		websocket.onopen = function() {
			setMessageInnerHTML("WebSocket连接成功");
		}
		var U01data, Uidata, Usdata
		//接收到消息的回调方法
		websocket.onmessage = function(event) {
			console.log(event);
			setMessageInnerHTML(event);
			setechart()
		}

		//连接关闭的回调方法
		websocket.onclose = function() {
			setMessageInnerHTML("WebSocket连接关闭");
		}

		//监听窗口关闭事件,当窗口关闭时,主动去关闭websocket连接,防止连接还没断开就关闭窗口,server端会抛异常。
		window.onbeforeunload = function() {
			closeWebSocket();
		}

		//将消息显示在网页上
		function setMessageInnerHTML(innerHTML) {
			document.getElementById('message').innerHTML += innerHTML + '<br/>';
		}

		//关闭WebSocket连接
		function closeWebSocket() {
			websocket.close();
		}

		//发送消息
		function send() {
			var message = document.getElementById('text').value;
			websocket.send('{"msg":"' + message + '"}');
			setMessageInnerHTML(message + "
");
		}
	</script>

</html>

结果

后端的连接信息

前端需要进行连接

关于作者

我是小小,双鱼座的程序猿,我们下期再见~bye

END

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Netkiller 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
图像检索:基于内容的图像检索技术(三)
无论是对于相同物体图像检索还是相同类别图像检索,在大规模图像数据集上,它们具有三个典型的主要特征:图像数据量大、特征维度高以及要求相应时间短。下面对这三个主要特征逐一展开说明:
用户3578099
2020/03/04
2.5K0
图像检索:基于内容的图像检索技术(二)
相同物体图像检索是指对查询图像中的某一物体,从图像库中找出包含有该物体的图像。这里用户感兴趣的是图像中包含的特定物体或目标,并且检索到的图片应该是包含有该物体的那些图片。如1.3图所示,给定一幅”蒙娜丽莎”的画像,相同物体检索的目标就是要从图像库中检索出那些包含有”蒙娜丽莎”人物的图片,在经过相似性度量排序后这些包含有”蒙娜丽莎”人物的图片尽可能的排在检索结果的前面。相似物体检索在英文文献中一般称为物体检索(Object Retrieval),近似样本搜索或检测(Duplicate Search or Detection)也可以归类于相同物体的检索,并且相同物体检索方法可以直接应用到近似样本搜索或检测上。相同物体检索不论是在研究还是在商业图像搜索产业中都具有重大的价值,比如购物应用中搜索衣服鞋子、人脸检索等。
用户3578099
2020/03/04
1.4K0
[文献阅读]用于大规模图像检索的深度哈希网络研究
春恋慕阅读西安电子科技大学陈鹏飞的论文 用于大规模图像检索的深度哈希网络研究 李聪的技术博客
月梦@剑心
2022/09/14
9610
[文献阅读]用于大规模图像检索的深度哈希网络研究
图像检索:基于内容的图像检索技术(四)
基于树结构的最近邻搜索方法和基于哈希的最近邻搜索方法在理论计算机科学、机器学习以及计算机视觉中是一个很活跃的领域,这些方法通过将特征空间划分成很多小的单元,以此减少空间搜索的区域,从而达到次线性的计算复杂度。
用户3578099
2020/03/18
1.6K0
基于内容的图像检索技术:从特征到检索
构建词库是离线操作,主要对目标数据集中的文本进行解析提取词干信息,建立当前数据集的词库,然后基于词库,对数据集中所有文档提取本文特征。构建词库在整个检索系统生命周期开始阶段实施,一般情况仅执行一次,是针对目标检索文本数据集进行的非频繁性操作。
公众号机器学习与AI生成创作
2020/12/08
1.9K0
基于内容的图像检索技术:从特征到检索
图像检索(Image Retrieval)入门
图像检索是一项重要的计算机视觉任务,它旨在根据用户的输入(如图像或关键词),从图像数据库中检索出最相关的图像。图像检索技术在许多领域中有着广泛的应用,如图像搜索引擎、图像版权认证、医学影像分析等。 这篇博客将带您入门图像检索的基本概念、方法和常用的技术。
大盘鸡拌面
2023/10/25
2.1K0
大厂技术实现 | 图像检索及其在淘宝的应用 @计算机视觉系列
图像检索任务指的是,给定查询图像,从图像数据库中找到包含相同或相似实例的图像。典型应用之一就是电商商品检索,如淘宝拍立淘,只需要用户随手拍照即可精准检索,提高了电商购物的体验。本篇我们来看看淘宝拍立淘背后的实现方案和依托的计算机视觉技术。
ShowMeAI
2021/11/24
2.9K0
大厂技术实现 | 图像检索及其在淘宝的应用 @计算机视觉系列
大厂技术实现 | 图像检索及其在高德的应用 @计算机视觉系列
图像检索任务指的是,给定查询图像,从图像数据库中找到包含相同或相似实例的图像。本文研究的是高德地图POI信息更新,即根据自有图像源,将每个新增或调整的POI及时制作成数据。这是非常典型的图像检索垂直应用,整套方便背后也包含大量CV技术。本篇我们结合资深CV工程师章鱼的分享,一起研究『高德地图POI信息更新』这一业务背景中,应用到的计算机视觉技术。
ShowMeAI
2022/01/21
1.2K0
大厂技术实现 | 图像检索及其在高德的应用 @计算机视觉系列
基于内容的图像检索技术综述-CNN方法
传统方法在图像检索技术上一直表现平平。比如传统方法常用的SIFT特征,它对一定程度内的缩放、平移、旋转、视角改变、亮度调整等畸变,都具有不变性,是当时最重要的图像特征提取方法之一。然而SIFT这类算法提取的特征还是有局限性的,在ImageNet ILSVRC比赛的最好结果的错误率也有26%以上,而且常年难以产生突破。而图像检索的发展目标是希望模型又快又准,因此兴起了基于CNN的方法,从原来AlexNet、VGGnet,到体积小一点的Inception、Resnet系列,再到DenseNet系列无不体现出了这一趋势。和传统方法一样,CNN方法也是对图片提取特征,比如CNN网络中的一个feature map就可以看做是一个类似SIFT的向量。
SIGAI学习与实践平台
2018/09/29
1.2K0
基于内容的图像检索技术综述-CNN方法
基于内容的图像检索技术综述-传统经典方法
今天我们来介绍一下图片检索技术,图片检索就是拿一张待识别图片,去从海量的图片库中找到和待识别图片最相近的图片。这种操作在以前依靠图片名搜图的时代是难以想象的,直到出现了CBIR(Content-based image retrieval)技术,依靠图片的内容去搜图。比较常见的图搜平台有百度、谷歌、拍立淘等,有些图搜技术已经能达到非常不错的效果。接下来我们做个测试,给出一个柯基宝宝的图片,分别用三家搜索引擎进行搜索:
SIGAI学习与实践平台
2018/08/07
5260
基于内容的图像检索技术综述-传统经典方法
物体识别技术长篇研究
物体识别是计算机视觉领域中的一项基础研究,它的任务是识别出图像中有什么物体,并报告出这个物体在图像表示的场景中的位置和方向。目前物体识别方法可以归为两类:基于模型的或者基于上下文识别的方法,二维物体识别或者三维物体识别方法。对于物体识别方法的评价标准,Grimson 总结出了大多数研究者主要认可的 4 个标准:健壮性(robustness)、正确性(correctness)、效率(efficiency)和范围(scope)。
放飞人夜
2020/02/06
2.1K0
以图搜图:基于机器学习的反向图像检索
原标题 | Reverse Image Search with Machine Learning
AI研习社
2019/11/06
2.4K0
以图搜图:基于机器学习的反向图像检索
基于内容的图像检索技术综述 传统经典方法
原创声明:本文为 SIGAI 原创文章,仅供个人学习使用,未经允许,不得转载,不能用于商业目的。
SIGAI学习与实践平台
2018/07/28
1.4K0
基于内容的图像检索技术综述 传统经典方法
图片/文字/视频跨模态检索综述
在过去的二十几年里,不同类型的媒体数据如文 本、图像和视频迅速增长。通常,这些不同类型的 数据用于描述相同的事件或主题。例如,网页通常 不仅包含文本描述,还包含与之匹配的图像或视频。这些不同类型的数据被称为多模态数据,表现出模 态间异构特性并具有广泛的应用,如图 1 所示,互 联网与社交媒体涌现的大规模多模态数据可以用于 进行主题检测、信息推荐、检索等。
机器学习AI算法工程
2021/08/06
3.3K0
偷窥了阿里的图像搜索架构,干货分享给你!
👆关注“博文视点Broadview”,获取文末赠书 进入21世纪以来,伴随着互联网的高速发展,通过图像和视频来进行需求表达越来越成为大家的习惯。 图像搜索与识别算法使得图像视频内容得以结构化和数字化,以便可以在各种检索和分析引擎中被最大限度地挖掘和利用。 阿里巴巴研发出的移动端以图搜图应用——拍立淘,使用户可以通过拍摄照片,在手机淘宝上迅速找到同款及相似商品,是图像搜索与识别领域极具代表性的落地产品。 因为拍立淘,我们可以在不知道商品品牌、名字等信息的情况下搜索到想要的同类品。 那么,拍立淘的架构设计是
博文视点Broadview
2023/05/19
5770
偷窥了阿里的图像搜索架构,干货分享给你!
机器学习 | 图像检索开源项目合集
关于更多机器学习、人工智能、增强现实、Unity、Unreal资源和技术干货,可以关注公众号:三次方AIRX
三次方AIRX
2020/12/15
1.9K0
大模型RAG向量检索原理深度解析
常规的知识库检索通常使用的是关键字与词条匹配,随着AGI的爆发,越来越多的知识库检索开始使用向量检索技术,特别是在RAG领域,增强型的生成式问答检索正在大面积应用和推广。
大脚攀爬
2024/04/18
2K0
大模型RAG向量检索原理深度解析
【图像检索】【TPAMI重磅综述】 SIFT与CNN的碰撞:万字长文回顾图像检索任务十年探索历程
基于内容的图像检索任务(CBIR)长期以来一直是计算机视觉领域重要的研究课题,自20世纪90年代早期,研究人员先后采用了图像的全局特征,局部特征,卷积特征的方法对CBIR任务进行研究和探索,并取得了卓越的成果。
keloli
2018/09/10
4.2K0
图像内容的「深度」理解及其应用
本文作者:朱晓龙博士,2015 年毕业于香港大学,主攻计算机视觉和机器学习方向,涉及物体检测,位姿估计,人脸特征点定位,3D 视觉等课题。本科期间参与北京大学智能车环境感知项目,基于 LIDAR 的图像理解工作发表在机器人顶级会议上。2015 年底加入腾讯,在 TEG 内部搜索部工程平台中心参与深度学习平台的开发与应用。长按以下二维码,在腾讯KM上查看本文 Introduction: 交互方式决定未来 云对雨,雪对风,晚照对晴空。——《声律启蒙》 随着设备的迭代,数据的形态也越来越丰富。PC 时代的键
腾讯技术工程官方号
2018/01/26
3.3K0
大规模图像检索的深度哈希方法简介
传统的图像检索过程,先通过人工对图像进行文字标注,再利用关键字来检索图像,这种依据图像描述的字符匹配程度提供检索结果的方法,称为“以字找图”(text-based image retrieval),既耗时又主观多义。如今每一秒都有数百万图片通过各种渠道上传到各种大规模存储设备中。给定一张查询图片,快速从百万量级的图像数据库中通过图像特征来找出内容相近的一定数量的图片,这种任务被称为“基于内容的图像检索”(content-based image retrieval (CBIR)),是目前非常流行的研究方向。
用户1324186
2018/03/06
6.3K0
大规模图像检索的深度哈希方法简介
推荐阅读
相关推荐
图像检索:基于内容的图像检索技术(三)
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验