问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

springboot集成websocket(springboot集成websocket原理)

发布网友 发布时间:2024-09-29 10:51

我来回答

1个回答

热心网友 时间:2024-09-29 12:45

SpringBoot-WebSocket

websocket是一种网络通信协议,类似http协议

Http协议有一个缺陷:通信只能由客户端发起

在某种场景下,例如,在外卖场景下,骑手位置更新时,服务器端向客户端发送骑手位置。如果使用http协议,那么就只能轮询了,由客户端不停地向服务器端发送请求,获取骑手的位置。

轮询的效率低下,有一定的延迟性,并且频繁的发送请求也会造成资源的浪费。

使用WebSocket协议可以实现由服务器端主动向客户端推送消息,当然客户端也可以向服务器端发送消息。

这里仅介绍利用Spring框架使用WebSocket的方式,原因:Spring使用WebSocket简便且易于扩展。

SpringBoot使用WebSocket非常方便,依赖上仅需要添加相应的Starter即可。

先给出概要的开发步骤:

其实到这里,基础的websocket服务已经搭建好了,剩下的可以自己在handler与interceptor中写自己的业务逻辑了

前端页面:

先启动服务器端SpringBoot应用,再使用前端页面点击测试一下就ok了

SpringBoot整合Websocket实现即时聊天功能

近期,公司需要新增即时聊天的业务,于是用websocket整合到Springboot完成业务的实现。

一、我们来简单的介绍下websocket的交互原理:

1.客户端先服务端发起websocket请求;

2.服务端接收到请求之后,把请求响应返回给客户端;

3.客户端与服务端只需要一次握手即可完成交互通道;

?二、webscoket支持的协议:基于TCP协议下,http协议和https协议;

?http协议springboot不需要做任何的配置?

?https协议则需要配置nignx代理,注意证书有效的问题?---在这不做详细说明

?三、开始我们的实现java后端的实现

?1.添加依赖

?!--websocket--

????dependency

??????groupIdorg.springframework.boot/groupId

??????artifactIdspring-boot-starter-websocket/artifactId

????/dependency

????dependency

??????groupIdorg.springframework/groupId

??????artifactIdspring-websocket/artifactId

??????version${spring.version}/version

????/dependency

????dependency

??????groupIdorg.springframework/groupId

??????artifactIdspring-messaging/artifactId

??????version${spring.version}/version

????/dependency

????!--WebSocket--

?2.配置config

@ConditionalOnWebApplication

@Configuration

@EnableWebSocketMessageBroker

publicclassWebSocketConfigextendsAbstractSessionWebSocketMessageBrokerConfigurer{

??@Bean

??publicServerEndpointExporterserverEndpointExporter(){

????return?newServerEndpointExporter();

??}

??@Bean

??publicCustomSpringConfiguratorcustomSpringConfigurator(){

????returnnewCustomSpringConfigurator();

??}

??@Override

??protectedvoidconfigureStompEndpoints(StompEndpointRegistryregistry){

????registry.addEndpoint("/websocket").setAllowedOrigins("*")

????????.addInterceptors(newHttpSessionHandshakeInterceptor()).withSockJS();

??}

publicclassCustomSpringConfiguratorextendsServerEndpointConfig.ConfiguratorimplementsApplicationContextAware{

??privatestaticvolatileBeanFactorycontext;

??@Override

??publicTTgetEndpointInstance(ClassTclazz)throwsInstantiationException{

????returncontext.getBean(clazz);

??}

??@Override

??publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{

????CustomSpringConfigurator.context=applicationContext;

??}

??@Override

??publicvoidmodifyHandshake(ServerEndpointConfigsec,

????????????????HandshakeRequestrequest,HandshakeResponseresponse){

????super.modifyHandshake(sec,request,response);

????HttpSessionhttpSession=(HttpSession)request.getHttpSession();

????if(httpSession!=null){

??????sec.getUserProperties().put(HttpSession.class.getName(),httpSession);

????}

??}

}

@SpringBootApplication

@EnableCaching

@ComponentScan("com")

@EnableWebSocket

publicclassApplicationextendsSpringBootServletInitializer{

staticfinalLoggerlogger=LoggerFactory.getLogger(Application.class);

??@Override

??protectedSpringApplicationBuilderconfigure(SpringApplicationBuilderapplication){

????returnapplication.sources(Application.class);

??}

需要注意的是:@EnableWebSocket?一定要加在启动类上,不然springboot无法对其扫描进行管理;

@SeverEndpoint--将目标类定义成一个websocket服务端,注解对应的值将用于监听用户连接的终端访问地址,客户端可以通过URL来连接到websocket服务端。

四、设计思路:用map房间id,用户set来保存房间对应的用户连接列表,当有用户进入一个房间的时候,就会先检测房间是否存在,如果不存在那就新建一个空的用户set,再加入本身到这个set中,确保不同房间号里的用户session不串通!

/**

*Createbywushuyu

*on2020/4/3013:24

*

*/

@ServerEndpoint(value="/websocket/{roomName}",configurator=CustomSpringConfigurator.class)

@Component

publicclassWebSocketRoom{

??//连接超时--一天

??privatestaticfinallongMAX_TIME_OUT=24*60*60*1000;

??//key为房间号,value为该房间号的用户session

??privatestaticfinalMapString,SetSessionrooms=newConcurrentHashMap();

??//将用户的信息存储在一个map集合里

??privatestaticfinalMapString,Objectusers=newConcurrentHashMap();

/**

*{roomName}使用通用跳转,实现动态获取房间号和用户信息?格式:roomId|xx|xx

*/

??@OnOpen?

??publicvoidconnect(@PathParam("roomName")StringroomName,Sessionsession){

????StringroomId=roomName.split("[|]")[0];

????Stringnickname=roomName.split("[|]")[1];

????StringloginId=roomName.split("[|]")[2];

????//设置连接超时时间

??????session.setMaxIdleTimeout(MAX_TIME_OUT);

????try{

?????//可实现业务逻辑

??????}

??????//将session按照房间名来存储,将各个房间的用户隔离

??????if(!rooms.containsKey(roomId)){

????????//创建房间不存在时,创建房间

????????SetSessionroom=newHashSet();

????????//添加用户

????????room.add(session);

????????rooms.put(roomId,room);

??????}else{//房间已存在,直接添加用户到相应的房间???????

????????if(rooms.values().contains(session)){//如果房间里有此session直接不做操作

????????}else{//不存在则添加

??????????rooms.get(roomId).add(session);

????????}

??????}

??????JSONObjectjsonObject=newJSONObject();

??????-----

??????//根据自身业务情况实现业务

??????-----

??????users.put(session.getId(),jsonObject);

??????//向在线的人发送当前在线的人的列表??-------------可有可无,看业务需求

??????ListChatMessageuserList=newLinkedList();

??????rooms.get(roomId)

??????????.stream()

??????????.map(Session::getId)

??????????.forEach(s-{

????????????ChatMessagechatMessage=newChatMessage();

????????????chatMessage.setDate(newDate());

????????????chatMessage.setStatus(1);

????????????chatMessage.setChatContent(users.get(s));

????????????chatMessage.setMessage("");

????????????userList.add(chatMessage);

??????????});

//????session.getBasicRemote().sendText(JSON.toJSONString(userList));

??????//向房间的所有人群发谁上线了

??????ChatMessagechatMessage=newChatMessage();?----将聊天信息封装起来。

??????chatMessage.setDate(newDate());

??????chatMessage.setStatus(1);

??????chatMessage.setChatContent(users.get(session.getId()));

??????chatMessage.setMessage("");

??????broadcast(roomId,JSON.toJSONString(chatMessage));

??????broadcast(roomId,JSON.toJSONString(userList));

????}catch(Exceptione){

??????e.printStackTrace();

????}

??}

??@OnClose

??publicvoiddisConnect(@PathParam("roomName")StringroomName,Sessionsession){

????StringroomId=roomName.split("[|]")[0];

????StringloginId=roomName.split("[|]")[2];

????try{

??????rooms.get(roomId).remove(session);

??????ChatMessagechatMessage=newChatMessage();

??????chatMessage.setDate(newDate());

??????chatMessage.setUserName(user.getRealname());

??????chatMessage.setStatus(0);

??????chatMessage.setChatContent(users.get(session.getId()));

??????chatMessage.setMessage("");

??????users.remove(session.getId());

??????//向在线的人发送当前在线的人的列表?----可有可无,根据业务要求

??????ListChatMessageuserList=newLinkedList();

??????rooms.get(roomId)

??????????.stream()

??????????.map(Session::getId)

??????????.forEach(s-{

????????????ChatMessagechatMessage1=newChatMessage();

????????????chatMessage1.setDate(newDate());

????????????chatMessage1.setUserName(user.getRealname());

????????????chatMessage1.setStatus(1);

????????????chatMessage1.setChatContent(users.get(s));

????????????chatMessage1.setMessage("");

????????????userList.add(chatMessage1);

??????????});

??????broadcast(roomId,JSON.toJSONString(chatMessage));

??????broadcast(roomId,JSON.toJSONString(userList));

????}catch(Exceptione){

??????e.printStackTrace();

????}

??}

??@OnMessage

??publicvoidreceiveMsg(Stringmsg,Sessionsession){

????try{

????????ChatMessagechatMessage=newChatMessage();

????????chatMessage.setUserName(user.getRealname());

????????chatMessage.setStatus(2);

????????chatMessage.setChatContent(users.get(session.getId()));

????????chatMessage.setMessage(msg);

????????//按房间群发消息

????????broadcast(roomId,JSON.toJSONString(chatMessage));

??????}

????}catch(IOExceptione){

??????e.printStackTrace();

????}

??}

??//按照房间名进行群发消息

??privatevoidbroadcast(StringroomId,Stringmsg){

????rooms.get(roomId).forEach(s-{

??????try{

????????s.getBasicRemote().sendText(msg);?-----此还有一个getAsyncRemote()?

??????}catch(IOExceptione){

????????e.printStackTrace();

??????}

????});

??}

??@OnError

??publicvoidonError(Throwableerror){

????error.printStackTrace();

??}

}

友情提示:此session是websocket里的session,并非httpsession;

SpringBoot+Vue+Websocket实现服务器端向客户端主动发送消息

本文通过一个实际的场景来介绍在前后端分离的项目中通过WebSocket来实现服务器端主动向客户端发送消息的应用。主要内容如下

Websocket是一种在单个TCP连接上进行全双工通信的协议。WebSocket连接成功后,服务端与客户端可以双向通信。在需要消息推送的场景,Websocket相对于轮询能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

具体如下特点

在客户端的列表数据中有个status字段,服务器端需要花费较长的时间进行处理,处理完成后才会更新对应数据的status字段值,通过Websocket的处理流程如下:

通过注入ServerEndpointExporter类,用于在项目启动的时候自动将使用了@ServerEndpoint注解声明的Websocketendpoint注册到WebSocketContainer中。

为什么增加一个ServerEndpointExporterBean,并通过在一个类上增加@ServerEndpoint和@Component注解就可以实现服务器端Websocket功能,这里简单解析一下。

java定义了一套javax.servlet-api,一个HttpServlet就是一个HTTP服务。javawebsocket并非基于servlet-api简单扩展,而是新定义了一套javax.websocket-api。

一个websocket服务对应一个Endpoint。与ServletContext对应,websocket-api也定义了WebSocketContainer,而编程方式注册websocket的接口是继承自WebSocketContainer的ServerContainer。

一个websocket可以接受并管理多个连接,因此可被视作一个server。主流servlet容器都支持websocket,如tomcat,jetty等。看ServerContainerapi文档,可从ServletContextattribute找到ServerContainer。

声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
华硕笔记本电脑触摸板怎么开笔记本电脑触摸板怎么开启和关闭_百度知 ... 陕西职务侵占案立案准则 结婚后我的恋情维系了十年,怎么做到的? 玉米仁子饭产自哪里 中国期货交易所的交易品种有哪些? 历史要怎么读,有啥诀窍 高中历史诀窍 年终会活动策划方案 深度解析:第一财经回放,探索财经新风向 逆水寒手游庄园怎么邀请好友同住 明朝有什么地方叫做什么野或者是野什么,除了巨野以外。 司机工作过程中发生交通事故导致的损失由谁来承担 肇事车辆为单位所有,司机履行职务,在工作或生产过程中发生交通事故的... 马丁靴和工装靴一样吗马丁靴怎么保养 梦见自己流血是什么征兆 女性 梦见下面流血怎么回事 徽章银行中国银行怎么选择 中国银行冰雪盛会徽章是哪个工厂生产的? 婚礼电子签到介绍高端时尚的顶级设置 Look!2022最受欢迎的9大电子签到正向你走来…… 计算机系统的开机顺序是 超虐的言情小说 古代现代都行 但要正常的 不要BL这些的 结局要是好的... 求女主角失忆的一本小说 很早之前 曾经在杂志上登过的 求弯矩等效均布荷载Qm,和剪力等效均布荷载Qv? ...梯形荷载和均布荷载共同作用跨中最大弯矩怎么求?要详细过程!急!在 ... 框架结构梁上有矩形均布荷载和梯形均布荷载,跨中弯矩怎么求 北京张一元茶庄传承与发展 京香茶庄在那里 班庄附近有没有食用冰的? 应酬太多了,肚子都像六个月了,有什么好的办法呀!用一生美怎样 WebSocket 鉴权授权方案,WebSocket 协议原理 没有电脑忘记了路由器密码怎样重置密码 电子转移数量的计算 高一化学之电子数问题 番茄todo怎么退出自习室 怎么用手机看中央电视台的新闻? 因不可抗力不能履行的合同损失谁来承担? 不可抗力造成的损失由谁承担呢 请问,我的嘴唇变得很红而且感觉有点干燥是怎么回事儿?有什么解决办法... 为什么我突然感觉我嘴唇边边的皮肤很干燥,后来还有点红? 魔兽世界是最好玩的3D游戏吗? 嘴唇变得很干燥,还很烫,很红是什么回事 已知氧化还原反应:2Cu(IO3)2+24KI+12H2SO4=2CuI↓+13I2+12K2SO 4CuI+Hg===Cu2HgI4+2Cu中I和Cu各是几价? 读摄影专业四年大概多少钱 学摄影费钱吗 我今年25岁 从事了人像摄影和人像后期的工作4年 自从看了电影中的特效... 我要学摄影4:数码单反摄影实战问答内容简介 美国Varaluz照明教你区分色点与色容差 ...最好不要超过3000)左右的手机,能流畅玩王者荣耀和各种游戏的。屏幕... 关于新陈代谢与ATP的问题