websocket介绍:
websocket是一种在单个tcp连接上进行全双工通信的协议,允许服务端和客户端之间进行实时、双向的数据传输。
- 长连接:websocket建立连接后,只要不关闭,会一直保持连接状态,使得服务器可以主动向客户端推送数据。
- 双向通信:与http请求-响应模式不同,websocket支持双向通信,即客户端和服务端都可以发送或接收数据。
使用场景:
在需要实时交互的场景中使用,例如聊天应用,实时数据推送,内容流式输出等。可实现实时向客户端进行数据推送。
1、springboot集成websocket作为服务端
在前后端分离的项目中,前端作为websocket的客户端,后端服务作为websocket的服务端。
实现步骤:
-
添加websocket整合包
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-websocket</artifactid> </dependency>
-
编写websocket配置类,暴露websocket
@configuration public class websocketconfig { @bean public serverendpointexporter serverendpointexporter() { return new serverendpointexporter(); } }
-
编写websocket服务监听程序及处理逻辑
package com.houdehong.wsserver.controller; import lombok.extern.slf4j.slf4j; import org.springframework.stereotype.component; import javax.websocket.*; import javax.websocket.server.pathparam; import javax.websocket.server.serverendpoint; import java.io.ioexception; import java.util.concurrent.concurrenthashmap; /** * @author houdehong * @date 2024/3/21 14:16 * @description **/ @component @serverendpoint("/api/ws/{sid}") @slf4j public class websocketserver { private string sid; private static final concurrenthashmap<string, session> session_map = new concurrenthashmap<>(); /** * 连接成功 */ @onopen public void onopen(session session, @pathparam("sid") string sid) { this.sid = sid; session_map.put(sid, session); log.info("有新连接:sid:{},sessionid:{},当前连接数:{}", sid, session.getid(), session_map.size()); } /** * 连接关闭 */ @onclose public void onclose(session session) { session_map.remove(this.sid); log.info("连接关闭,sid:{},session id:{}!当前连接数:{}", this.sid, session.getid(), session_map.size()); } /** * 收到消息 */ @onmessage public void onmessage(string message, session session) { log.info("收到消息:{},内容:{}", sid, message); if("ping".equals(message)){ try { session.getbasicremote().sendtext("pong"); } catch (ioexception e) { log.error("onmessage 推送消息失败:{},内容:{}", sid, message); } }else{ // 排除自己 // sendmeasuredatainfoexcludeself(message, sid); // 发给所有客户端包括自己 sendmeasuredatainfo(message); } } /** * 连接错误 */ @onerror public void onerror(session session, throwable error) { log.error("{} 发生错误", session.getid(), error); } /** * 群发消息 */ public void sendmeasuredatainfo(string message) { for (string sid : session_map.keyset()) { session session = session_map.get(sid); try { session.getbasicremote().sendtext(message); } catch (ioexception e) { log.error("推送消息失败:{},内容:{}", sid, message); } log.info("推送消息:{},内容:{}", sid, message); } } /** * 群发消息,排除消息发起者 * @param message * @param sidself */ private void sendmeasuredatainfoexcludeself(string message, string sidself){ for(string sid : session_map.keyset()){ if(sidself.equals(sid)){ continue; } session session = session_map.get(sid); try { session.getbasicremote().sendtext(message); } catch (ioexception e) { log.error("sendmeasuredatainfoexcludeself 推送消息失败:{},内容:{}", sid, message); } log.info("sendmeasuredatainfoexcludeself 推送消息:{},内容:{}", sid, message); } } }
-
测试
至此,springboot整合websocket作为服务就搭建完成了,我们可以随便百度打开一个在线的websocket测试工具,请求一下试试,请求地址是ws://ip:port/api/ws/{sid}, 其中sid可以随便指定一个字符串,这里的sid主要是用来区分客户端,实际场景下可以在前端生成全局唯一的标识。
图片:
控制台打印信息:
2、springboot集成websocket作为客户端
有时,我们需要调用第三方的websocket服务,然后将接收到的数据处理之后,或持久化到数据库,或是需要解析数据重新封装为前端需要的数据结构,这个时候我们就需要作为客户端来进行使用。
实现步骤:
-
添加springboot服务作为客户端的依赖
<dependency> <groupid>org.java-websocket</groupid> <artifactid>java-websocket</artifactid> <version>1.3.8</version> </dependency>
-
继承websocketclient,重写方法,加入自己的逻辑
@slf4j public class mywebsocketclient extends websocketclient { public mywebsocketclient(uri serveruri) { super(serveruri); } @override public void onopen(serverhandshake arg0) { log.info("------ websocketclient onopen ------"); } @override public void onclose(int arg0, string arg1, boolean arg2) { log.info("------ websocket onclose ------{}",arg1); } @override public void onerror(exception arg0) { log.error("------ websocket onerror ------{}",arg0); } @override public void onmessage(string response) { log.info("-------- 接收到服务端数据: " + response + "--------"); } }
-
获取websocketclient实例
在这里我写的wsserverurl即为上面websocket作为服务端的地址
@component public class websocketclientconfigurer { private final string wsserverurl = "ws://127.0.0.1:8081/api/ws/123wer"; @bean public websocketclient websocketclient() { try { mywebsocketclient websocketclient = new mywebsocketclient(new uri(wsserverurl)); websocketclient.connect(); return websocketclient; } catch (urisyntaxexception e) { e.printstacktrace(); } return null; } }
-
为了好演示我加了一个controller来进行调用
@restcontroller @requestmapping("ws-client") public class websocketclient { @resource private mywebsocketclient websocketclient; @getmapping("send/{message}") public void sendrequest(@pathvariable string message){ websocketclient.send(message); } }
3. 测试
至此,我们已经搭好了一个websocket的服务器和一个websocket的客户端,我们可以同时把这两个服务跑起来,做一个调用。
注意:需要先启动服务端,再启动客户端,客户端会无法创建连接,报空指针异常。
服务端启动:
客户端启动:
现在我们向客户端的controller请求一个消息:
你可以用postman或者其他api工具,我现在图简单直接在浏览器发起:
客户端控制台日志:
服务端控制台日志:
ok,大功告成。
发表评论