SpringBoot项目中,WebSocket的使用(观察者设计模式)
1.什么是WebSocket(选择至菜鸟教程(点击跳转),观察者模式)
WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。
WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。
2.创建WebSocket连接(被观察者)
这里我们在前端页面向后端页面发出请求,JavaScript中定义了WebSocket
四个事件和两个方法
<script> var websocket = null; if('WebSocket' in window) { websocket = new WebSocket('ws://localhost:8080/sell/webSocket'); }else { alert('该浏览器不支持websocket!'); } websocket.onopen = function (event) { console.log('建立连接'); } websocket.onclose = function (event) { console.log('连接关闭'); } websocket.onmessage = function (event) { console.log('收到消息:' + event.data) //弹窗提醒, $('#myModal').modal('show'); // 播放音乐 document.getElementById('notice').play(); } websocket.onerror = function () { alert('websocket通信发生错误!'); } window.onbeforeunload = function () { websocket.close(); } </script>
3.使用java创建WebSokect连接(观察者)
3.1引入依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
3.2注入ServerEndpointExporter(注入环境)
package com.xiong.sell.config; import org.springframework.context.annotation.Bean; import org.springframework.stereotype.Component; import org.springframework.web.socket.server.standard.ServerEndpointExporter; @Component public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
3.3编写WebSocket类
package com.xiong.sell.service; import lombok.extern.slf4j.Slf4j; 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.ServerEndpoint; import java.util.concurrent.CopyOnWriteArraySet; @Component @ServerEndpoint("/webSocket") @Slf4j public class WebSocket { private Session session; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。若要实现服务端与单一客户端通信的话,可以使用Map来存放,其中Key可以为用户标识 private static CopyOnWriteArraySet<WebSocket> webSocketSet = new CopyOnWriteArraySet<>(); /** * 连接建立成功调用的方法 * @param session 可选的参数。session为与某个客户端的连接会话,需要通过它来给客户端发送数据 */ @OnOpen public void onOpen(Session session) { this.session = session; webSocketSet.add(this); log.info("【websocket消息】有新的连接, 总数:{}", webSocketSet.size()); } /** * 关闭连接调用方法 */ @OnClose public void onClose() { webSocketSet.remove(this); log.info("【websocket消息】连接断开, 总数:{}", webSocketSet.size()); } /** * 收到客户端消息后调用的方法 * @param message 客户端发送过来的消息 */ @OnMessage public void onMessage(String message) { log.info("【websocket消息】收到客户端发来的消息:{}", message); } /** * 自定义的方法,群发参数 * @param message 群发的内容 */ public void sendMessage(String message) { for (WebSocket webSocket: webSocketSet) { log.info("【websocket消息】广播消息, message={}", message); try { webSocket.session.getBasicRemote().sendText(message); } catch (Exception e) { e.printStackTrace(); } } } }
4.测试截图