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
@ConfigurationpublicclassWebSocketConfig{@BeanpublicServerEndpointExporterserverEndpointExporter(){returnnewServerEndpointExporter();}}
- 编写websocket服务监听程序及处理逻辑
packagecom.houdehong.wsserver.controller;importlombok.extern.slf4j.Slf4j;importorg.springframework.stereotype.Component;importjavax.websocket.*;importjavax.websocket.server.PathParam;importjavax.websocket.server.ServerEndpoint;importjava.io.IOException;importjava.util.concurrent.ConcurrentHashMap;/** * @Author houdehong * @Date 2024/3/21 14:16 * @Description **/@Component@ServerEndpoint("/api/ws/{sid}")@Slf4jpublicclassWebSocketServer{privateString sid;privatestaticfinalConcurrentHashMap<String,Session>SESSION_MAP=newConcurrentHashMap<>();/** * 连接成功 */@OnOpenpublicvoidonOpen(Session session,@PathParam("sid")String sid){this.sid = sid;SESSION_MAP.put(sid, session); log.info("有新连接:sid:{},sessionId:{},当前连接数:{}", sid, session.getId(),SESSION_MAP.size());}/** * 连接关闭 */@OnClosepublicvoidonClose(Session session){SESSION_MAP.remove(this.sid); log.info("连接关闭,sid:{},session id:{}!当前连接数:{}",this.sid, session.getId(),SESSION_MAP.size());}/** * 收到消息 */@OnMessagepublicvoidonMessage(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);}}/** * 连接错误 */@OnErrorpublicvoidonError(Session session,Throwable error){ log.error("{} 发生错误", session.getId(), error);}/** * 群发消息 */publicvoidsendMeasureDataInfo(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 */privatevoidsendMeasureDataInfoExcludeSelf(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,重写方法,加入自己的逻辑
@Slf4jpublicclassMyWebSocketClientextendsWebSocketClient{publicMyWebSocketClient(URI serverUri){super(serverUri);}@OverridepublicvoidonOpen(ServerHandshake arg0){ log.info("------ WebSocketClient onOpen ------");}@OverridepublicvoidonClose(int arg0,String arg1,boolean arg2){ log.info("------ WebSocket onClose ------{}",arg1);}@OverridepublicvoidonError(Exception arg0){ log.error("------ WebSocket onError ------{}",arg0);}@OverridepublicvoidonMessage(String response){ log.info("-------- 接收到服务端数据: "+ response +"--------");}}
- 获取websocketClient实例在这里我写的wsServerUrl即为上面websocket作为服务端的地址
@ComponentpublicclassWebSocketClientConfigurer{privatefinalString wsServerUrl ="ws://127.0.0.1:8081/api/ws/123wer";@BeanpublicWebSocketClientwebSocketClient(){try{MyWebSocketClient webSocketClient =newMyWebSocketClient(newURI(wsServerUrl)); webSocketClient.connect();return webSocketClient;}catch(URISyntaxException e){ e.printStackTrace();}returnnull;}}
- 为了好演示我加了一个controller来进行调用
@RestController@RequestMapping("ws-client")publicclassWebsocketClient{@ResourceprivateMyWebSocketClient webSocketClient;@GetMapping("send/{message}")publicvoidsendRequest(@PathVariableString message){ webSocketClient.send(message);}}
3. 测试
至此,我们已经搭好了一个websocket的服务器和一个websocket的客户端,我们可以同时把这两个服务跑起来,做一个调用。
注意:需要先启动服务端,再启动客户端,客户端会无法创建连接,报空指针异常。
服务端启动:
客户端启动:
现在我们向客户端的controller请求一个消息:
你可以用postman或者其他api工具,我现在图简单直接在浏览器发起:
客户端控制台日志:
服务端控制台日志:
OK,大功告成。
整套源码包地址
版权归原作者 侯德红 所有, 如有侵权,请联系我们删除。