SpringBoot-集成 webSocket
1. WebSocket 简介
2. springboot 集成 javax 注解方式
- pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
- 配置类
/* * * * * blog.coder4j.cn * * Copyright (C) 2016-2019 All Rights Reserved. * */ package cn.coder4j.study.example.websocket.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.config.annotation.EnableWebSocket; import org.springframework.web.socket.server.standard.ServerEndpointExporter; /** * @author buhao * @version WebSocketConfig.java, v 0.1 2019-10-18 15:45 buhao */ @Configuration @EnableWebSocket public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpoint() { return new ServerEndpointExporter(); } }
这个配置类很简单,通过这个配置 spring boot 才能去扫描后面的关于 websocket 的注解
- 定义一个 WebSocket
/* * * * * blog.coder4j.cn * * Copyright (C) 2016-2019 All Rights Reserved. * */ package cn.coder4j.study.example.websocket.ws; 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.io.IOException; import java.util.HashMap; import java.util.Map; /** * @author buhao * @version WsServerEndpoint.java, v 0.1 2019-10-18 16:06 buhao */ @ServerEndpoint("/myWs") @Component public class WsServerEndpoint { /** * 连接成功 * * @param session */ @OnOpen public void onOpen(Session session) { System.out.println("连接成功"); } /** * 连接关闭 * * @param session */ @OnClose public void onClose(Session session) { System.out.println("连接关闭"); } /** * 接收到消息 * * @param text */ @OnMessage public String onMsg(String text) throws IOException { return "servet 发送:" + text; } }
这里有几个注解需要注意一下,首先是他们的包都在 **javax.websocket **下。并不是 spring 提供的,而 jdk 自带的,下面是他们的具体作用。
另外一点就是服务端如何发送消息给客户端,服务端发送消息必须通过上面说的 Session 类,通常是在@OnOpen 方法中,当连接成功后把 session 存入 Map 的 value,key 是与 session 对应的用户标识,当要发送的时候通过 key 获得 session 再发送,这里可以通过 session.getBasicRemote().sendText() 来对客户端发送消息。
3. Spring 封装的版本
- pom
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
- 定义一个 SocketService
@Component public class SocketService { //用来存放所有客户端连接 private ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<String, WebSocketSession>(); //添加连接 public void add(String key, WebSocketSession session){ sessions.put(key, session); } //删除链接 public WebSocketSession remove(String key){ return sessions.remove(key); } //删除并关闭链接 public void removeAndClose(String key){ WebSocketSession removeSession = remove(key); if(removeSession != null){ try { removeSession.close(); } catch (IOException e) { e.printStackTrace(); } } } //获取 session public WebSocketSession get(String key){ return sessions.get(key); } //向客户端发送消息 private void sendMessage(ComparisonSocketVo key, TextMessage textMessage){ List<WebSocketSession> webSocketSessions = sessions.get(key); if(webSocketSessions != null) { webSocketSessions.forEach(ws -> { try { //测试的 ws.sendMessage(textMessage); } catch (IOException e) { e.printStackTrace(); } }); } } }
这个不是必要的,用来配合我们的业务,将客户端 session 连接管理起来,key 具体存什么
- 定义一个处理器
@Component public class MyMessageHandler extends TextWebSocketHandler { @Autowired private SocketService socketService; //建立连接成功事件 @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { System.out.println("连接成功"); socketService.add(session.getId(), session); } //关闭连接成功事件,客户端主动关闭 @Override public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception { System.out.println("关闭成功"); socketService.remove(session.getId()); } @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { System.out.println(message.toString()); } }
相当于 @Open 等注解。
- 定义拦截器
@Component public class MyInterceptor implements HandshakeInterceptor { public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { System.out.println("握手开始。。。。"); return true; } public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception exception) { System.out.println("握手结束。。。。"); } }
通过实现 HandshakeInterceptor 接口来定义握手拦截器,注意这里与上面 Handler 的事件是不同的,这里是建立握手时的事件,分为握手前与握手后,而 Handler 的事件是在握手成功后的基础上建立 socket 的连接。所以在如果把认证放在这个步骤相对来说最节省服务器资源。它主要有两个方法 beforeHandshake 与 **afterHandshake **,顾名思义一个在握手前触发,一个在握手后触发。
- 配置文件
@Configuration public class WebSocketConfig implements WebSocketConfigurer { @Autowired private MyInterceptor myInterceptor; @Autowired private MyMessageHandler myMessageHandler; public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myMessageHandler, "/test1") .addInterceptors(myInterceptor) .setAllowedOrigins("*"); } }
将对应的 handler 配置成一个 webSocket 路径,类似 http 接口的 url。
- 启动类
@SpringBootApplication @EnableWebSocket public class SocketDemoMain { public static void main(String[] args) { SpringApplication.run(SocketDemoMain.class, args); } }
- 问题
WebSocketSession.sendMessage() 方法
,实际是调用 AbstractWebSocketSession.sendMessage()
方法
@Override public final void sendMessage(WebSocketMessage<?> message) throws IOException { checkNativeSessionInitialized(); if (logger.isTraceEnabled()) { logger.trace("Sending " + message + ", " + this); } if (message instanceof TextMessage) { sendTextMessage((TextMessage) message); } else if (message instanceof BinaryMessage) { sendBinaryMessage((BinaryMessage) message); } else if (message instanceof PingMessage) { sendPingMessage((PingMessage) message); } else if (message instanceof PongMessage) { sendPongMessage((PongMessage) message); } else { throw new IllegalStateException("Unexpected WebSocketMessage type: " + message); } }
由源码可见,我们只能用这几种消息。如果需要发送一个 Object 类的数据,需要转换成 json 字符串,然后封装成 TextMessage 发出去。
public static TextMessage errMsg(String message){ CompareSocketMsg msg = new CompareSocketMsg(); msg.type = 0; msg.code = 500; msg.message = message; return new TextMessage(JSON.toJSONString(msg)); }
参考文件
本文作者:primaryC
本文链接:https://www.cnblogs.com/cnff/p/18305584
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步