springboot快速集成websocket
websocket无非就是能够让我们的浏览器与浏览器之间、浏览器与服务器做到及时交互,
目前来说,我使用到的场景就两个:1.用户与用户的聊天室,2.用户与AI的聊天室
websocket实际用起来比较简单,
从后端来说,以springboot为例,
导入依赖坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
载入配置开启websocket服务
没有正确实现的话,控制台会报错No mapping for get /** 。原因就是spring没有正确识别websocket的路径映射,websocket的路径映射不仅需要@ServerEndpoint注解,还需要spring正确扫描并注册websocket端点。因此我们不仅需要导入websocket的config,还需要确保spring正确管理serverEndpoint
@Configuration @Slf4j @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { log.info("开启websocket配置..."); // 自定义的 WebSocketHandler,可以在这里注册 // registry.addHandler(myWebSocketHandler, "/websocketClient/{userId}"); } }
类的基础形式
@ServerEndpoint(value = "/websocketClient/{userId}")
@Component
@Slf4j
public class WebSocketClient{}
常见成员变量
/** * 静态变量,用来记录当前在线连接数。应该把它设计成线程安全的 */ private static int onlineCount = 0; /** * concurrent包的线程安全Map,用来存放每个客户端对应的MyWebSocket对象 */ private static final ConcurrentHashMap<String, WebSocketClient> webSocketMap = new ConcurrentHashMap<>(); /** * websocket的会话对象,与某个客户端的连接会话,需要通过它来给客户端发送数据 */ private Session session; /** * 用户id 唯一标识 */ private String userId;
常见方法:onOpen(建立成功会调用的方法)、onClose(连接关闭调用的方法)、onMessage(收到客户端消息后调用的方法)、onError(发生错误时调用的方法)、sendMessage(向客户端推送消息)
onOpen方法
@OnOpen public void onOpen(Session session, @PathParam("userId") String userId) { this.session = session; this.userId = userId; //加入map webSocketMap.put(userId, this); log.info("WebSocket客户端{}连接成功,客户端标识:{},当前在线人数:{}", session.getId(), userId, getOnlineCount()); }
onClose方法
@OnClose public void onClose() { //从map中删除 webSocketMap.remove(userId); log.info("WebSocket客户端{}连接断开,客户端标识:{},当前在线人数:{}", session.getId(), userId, getOnlineCount()); }
onMessage方法
@OnMessage public void onMessage(String message, Session session) throws Exception { // 心跳检测响应 if (StringUtils.equalsIgnoreCase("ping", message)) { sendMessage("pong"); log.info("WebSocket服务端已回复客户端{}的心跳检测:pong", session.getId()); return; } //todo 存入mysql之类 }
onError方法
@OnError public void onError(Session session, Throwable error) { log.error("发生错误{}", session.getId(), error); error.printStackTrace(); }
sendMessage方法
public void sendMessage(String message) { try { this.session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); log.error("客户端{}发送消息{{}}失败", session.getId(), message); } }
在sendMessage方法的基础上实现了具体消息的发送:
如果是对具体的用户发送消息,则在websocketMap中取出对应的WebsocketClient再调用sendMessage方法
如果是群发消息,则直接遍历websocketMap并依次发送sendMessage即可
public static void sendMessageByUserId(String userId, String message) throws IOException { log.info("给用户{}发送{}信息", userId, message); if (StrUtil.isNotBlank(userId) && webSocketMap.containsKey(userId)) { webSocketMap.get(userId).sendMessage(message); } }
public static void sendInfo(String message) { for (String item : webSocketMap.keySet()) { webSocketMap.get(item).sendMessage(message); } }

浙公网安备 33010602011771号