目的:websocket做弹幕
用到的技术:springboot +websocket +uniapp (只写了后台)
菜鸟:https://www.runoob.com/html/html5-websocket.html
这是最后结果的展示:
WebSocket是什么?为什么用它?
全双工通信的协议。允许服务端主动向客户端推送数据。
后台代码:
第一步:依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
第二步:配置
@Configuration public class webSocketCfg { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
第三步:WebSocketServer 这里是重点
群发
@ServerEndpoint("/socketServer/{userId}") @Component @Slf4j public class BatchWebSocketServer { //静态变量,用来记录当前在线连接数。应该把它设计成线程安全的。 private static int onlineCount = 0; //concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。 private static CopyOnWriteArraySet<BatchWebSocketServer> webSocketSet = new CopyOnWriteArraySet<BatchWebSocketServer>(); //与某个客户端的连接会话,需要通过它来给客户端发送数据 private Session session; //接收userId private String userId=""; /** * 连接建立成功调用的方法*/ @OnOpen public void onOpen(Session session,@PathParam("userId") String userId) { this.session = session; webSocketSet.add(this); //加入set中 addOnlineCount(); //在线数+1 log.info("用户:"+userId+",当前在线人数为" + getOnlineCount()); this.userId=userId; try { sendMessage("连接成功"); } catch (IOException e) { log.error("IO异常"); } } /** * 连接关闭调用的方法 */ @OnClose public void onClose() { webSocketSet.remove(this); //从set中删除 subOnlineCount(); //在线数-1 log.info("有一连接关闭!当前在线人数为" + getOnlineCount()); } /** * 收到客户端消息后调用的方法 * @param message 接收消息*/ @OnMessage public void onMessage(String message, Session session) { log.info("收到来自窗口"+userId+"的信息:"+message); //群发消息 for (BatchWebSocketServer 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"); error.printStackTrace(); } /** * 实现服务器主动推送 */ public void sendMessage(String message) throws IOException { this.session.getBasicRemote().sendText(message); } /** * 群发消息 * */ public static void sendInfo(String message,@PathParam("userId") String userId){ log.info("推送消息"+userId+",报文:"+message); for (BatchWebSocketServer item : webSocketSet) { try { item.sendMessage(message); } catch (IOException e) { continue; } } } public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { BatchWebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { BatchWebSocketServer.onlineCount--; } }
前台参考 : uniapp ,这里不写太详细了。
https://uniapp.dcloud.io/api/request/websocket
做个参考:
import base from '@/config/baseUrl'; import store from '@/store'; class socket { constructor(options) { //地址 this.socketUrl = base.socketUrl; this.socketStart = false; this.monitorSocketError(); this.monitorSocketClose(); this.socketReceive(); } init(callback) { const _this = this; if (base.socketUrl) { if(this.socketStart){ console.log('webSocket已经启动了'); }else{ uni.connectSocket({ url: this.socketUrl, method: 'GET' }); uni.onSocketOpen((res) => { this.socketStart = true; callback && callback(); console.log('WebSocket连接已打开!'); }); /* setTimeout(() => { _this.getHeartbeat(); }, 5000); */ } }else{ console.log('config/baseUrl socketUrl为空'); } } //Socket给服务器发送消息 send(data, callback) { const _this = this; if (store.state.userInfo.uid) { data.userUid = store.state.userInfo.uid; } console.log(data); uni.sendSocketMessage({ data: JSON.stringify(data), success: () => { callback && callback(true); }, fail: () => { callback && callback(false); } }); } //Socket接收服务器发送过来的消息 socketReceive() { const _this = this; uni.onSocketMessage(function(res) { let data = JSON.parse(res.data); console.log('收到服务器内容:', data.type); _this.acceptMessage && _this.acceptMessage(data.type); }); } //关闭Socket closeSocket() { uni.closeSocket(); _this.socketStart = false; } //监听Socket关闭 monitorSocketClose() { const _this = this; uni.onSocketClose(function(res) { console.log('WebSocket 已关闭!'); _this.socketStart = false; setTimeout(function() { _this.init(); }, 3000); }); } //监听Socket错误 monitorSocketError() { const _this = this; uni.onSocketError(function(res) { _this.socketStart = false; console.log('WebSocket连接打开失败,请检查!'); }); } //心跳 getHeartbeat() { const _this = this; this.send({ type: "心跳", userUid: store.state.userInfo.userUid }, (val) => { setTimeout(() => { if (val) { _this.getHeartbeat(); } else { _this.init(); } }, 10000); }); } }; const mySocket = new socket(); export default mySocket;
@