路途漫漫,行则将至
为什么使用WebSocket
一般来讲,我们传统的前后端分离设计下,前后端通讯一般都是前端发送一个http请求,之后后端处理,然后返回给前端,这样的设计下,其实就是类似于一种单工的通信模式,这种模式下可能无法满足一些特定的场景:
- 比如我们存在一个后台的定时任务,每天晚上检查货物的存储数量,当存储数量低于阈值的时候,需要给业务人员报警,此时我们就需要后端主动发送消息给前端。
- 或者前端发起了一个复杂而庞大的处理任务,后端可能需要一个较长的处理时间(比如五分钟),此时如果前端页面忙等,业务人员很可能会认为页面卡住了,或者浏览器有问题,我们更好的解决方案应该是后端每处理完一定的任务节点就向前端发送一个信号,并展示给用户,如 查找人员中 -> 数据解析中 -> 正在计算大区出货量…
- 也或者我们后端存在一些数据会不定期的变化,而这些数据需要及时发送给前端进行展示。
获取有人会说,轮询也可以解决上述问题,是的,但轮询也存在一定的问题,例如轮询的效率低,非常浪费资源(因为必须不停连接,或者 HTTP 连接始终打开),同时有些消息存在着时间分布不均的情况,例如一些变化数据在早上变化频繁而夜间变化稀疏,如果轮询间隔一直很短,对于夜间而言就是一种资源的浪费。或者我们存在一些数据10秒内变化了三次,但我们轮询时间为15秒,这样的话我们就有可能漏掉一些数据。
什么是WebSocket
WebSocket 协议在2008年诞生,2011年成为国际标准。所有浏览器都已经支持了。
它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。
其他特点包括:
(1)建立在 TCP 协议之上,服务器端的实现比较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端口也是80和443,并且握手阶段采用 HTTP 协议,因此握手时不容易屏蔽,能通过各种 HTTP 代理服务器。
(3)数据格式比较轻量,性能开销小,通信高效。
(4)可以发送文本,也可以发送二进制数据。(一般我们使用Json的形式传递数据)
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws
(如果加密,则为wss
),服务器网址就是 URL。
本系列将从前后端两个方面分别介绍搭建过程,本文主要介绍依赖于java8的后端实现过程,下一篇文章将会整体介绍依赖于vue2与vuex的前端websocket实现。
后端服务部署
依赖搭建
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
配置项管理
config
@Configuration
@EnableWebSocket
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
websocket总线
所有服务目标为myWs
的连接建立请求,都将途径此节点,并进行注册和统一管理,我们可以建立多个总线,甚至我们可以为每一个请求都单独设立一个总线进行分开管理。
但是值得注意的是,我们在总线中进行注册时,需要依据一个唯一标识
来对不同的session进行区分,这个标识可以是用户姓名,也可以是随机数,我们需要对唯一标识进行合理的管理和存储,以防出现广播情况。
不需要的session建议及时关闭。
用户刷新页面时(F5)将会断开所有session
@ServerEndpoint("/myWs")
@Component
public class WsServerEndpoint {
private static Set<Session>sessions= new HashSet<>();
private static Map<Session, String>sessionOwners= new HashMap<>();
private static Map<String, Session>ownerSessions= new HashMap<>();
private static ObjectMapperobjectMapper= new ObjectMapper();
/**
*连接成功
*@paramsession
*/
@OnOpen
public void onOpen(Session session) throws IOException {
sessions.add(session);
String owner = new ArrayList<>(session.getRequestParameterMap().values()).get(0).get(0).trim();
sessionOwners.put(session, owner);
System.out.println("连接成功");
// session.getBasicRemote().sendText("Hello from the server!");
ownerSessions.put(owner, session);
}
/**
*连接关闭
*@paramsession
*/
@OnClose
public void onClose(Session session) {
System.out.println("连接关闭");
sessions.remove(session);
ownerSessions.remove(sessionOwners.get(session));
sessionOwners.remove(session);
}
@OnMessage
public void onMessage(String message) {
// 处理来自WebSocket客户端的消息
System.out.println("Received message: " + message);
}
public static void sendMessage(String message, String owner) {
System.out.println("sendMsg Here");
if (ownerSessions.containsKey(owner)) {
Session session =ownerSessions.get(owner);
session.getAsyncRemote().sendText(message);
}
}
// 发送对象给前端
public static void sendObjectToClient(String owner, Object object) {
Session session = null;
if (ownerSessions.containsKey(owner)) {
session =ownerSessions.get(owner);
} else {
return;
}
try {
String json =objectMapper.writeValueAsString(object);
session.getBasicRemote().sendText(json);
} catch (IOException e) {
e.printStackTrace();
}
}
}
我们在这里发送object时,依旧是使用sendtext,而不是sendobject
很少使用session.getBasicRemote().sendObject()
方法的原因是该方法并不是标准的WebSocket API的一部分。在Java中,WebSocket API提供了session.getBasicRemote().sendText()
和session.getBasicRemote().sendBinary()
方法来发送文本数据和二进制数据。这两个方法是标准的WebSocket API方法,被广泛支持和使用。
另外,
sendObject()
方法要求发送的对象必须是可序列化的,这意味着对象需要实现java.io.Serializable
接口。但并不是所有对象都可以轻松地实现序列化,有些对象可能包含非序列化的成员变量或方法,或者依赖于特定的运行时环境。因此,将对象转换为字符串或其他可序列化的格式,然后使用sendText()
或sendBinary()
方法发送数据更为常见和可靠。
通过将对象转换为字符串或其他可序列化的格式,可以确保发送的数据能够被接收方正确解析和处理。常见的做法是将对象转换为JSON字符串,这样接收方可以方便地解析和处理该字符串。
到这里,我们基本上就已经成功的在我们的后端项目中引入WebSocket功能了,但是这里也只是万里长征第一步,后续我们还需要做很多其他的工作,如session注册,session管理,消息定向发送,消息广播 等等相关的工作。这些的实现都并不复杂也有很多的实现方式,简单的实现只要合理的利用线程安全的Map进行管理即可。
另外,出于规范化的数据管理,推荐在前后端WebSocket通信时,定义标准的通讯类,个人推荐通讯类中应包含 T 泛型对象,String 消息id,Long 时间戳,String 消息类型。这些作为基础数据,并以此扩展。文章来源:https://www.toymoban.com/news/detail-796940.html
本文之中不足之处还请大佬多多指教文章来源地址https://www.toymoban.com/news/detail-796940.html
到了这里,关于WebSocket全栈搭建(Java + Vue2) 上的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!