WebSocket库与其使用方法(JAVA)
消息推送常见方式
轮询
浏览器以指定的间隔发送HTTP请求,服务器实时返回数据给浏览器,即时相应,如果没有数据会返回空数据
缺点:有延迟
长轮询
服务器发出ajax请求,服务器接收到请求之后,会阻塞请求,直到有数据或请求超时才会返回数据
SSE-服务器发送事件
在服务器->浏览器间打开一个单向通道,服务器相应的不再是数据包,而是text/event-stream类型的数据流信息,因此数据会被实时发送给客户端
Web-Socket
基于TCP连接的全双工通信的协议
连接流程
客户端向服务器发送UpGreade:websocket(此时仍然是HTTP协议)
服务端回复:101 switching protocols
—->切换为websocket协议
Web-Socket API
客户端API
创建
1 2 3 4
| let ws=new WebSocket(URL); ws.onopen=this.onopen; ws.onmessage=this.onmessage; ws.onclose=this.onclose;
|
事件
事件 |
事件处理程序 |
描述 |
open |
ws.onopen |
连接建立时触发 |
message |
ws.onmessage |
客户端接收到服务器发送的数据时触发 |
close |
ws.onclose |
连接关闭时触发 |
方法
send:发送数据给服务端
服务端API
JAVA WebSocket应用由一系列的Endpoint组成,Endpoint是一个java对象,代表websocket的一端
定义方法
- 继承javax.websocket.Endpoint并实现其方法
- 定义一个POJO,添加@ServerEndpoint(“访问路径”)注解
运行逻辑
Endpoint实例在WebSocket握手时创建,在服务端和客户端保持连接的过程中持续有效,最后在连接关闭的时候结束
方法 |
描述 |
注解 |
onMessage() |
服务端接收到客户端信息时调用 |
@onMessage |
onError() |
当连接过程异常时调用 |
@OnError |
onOpen() |
开启一个新的会话时调用 |
@OnOpen |
onCLose() |
会话关闭时调用 |
@OnClose |
接收客户端发送的数据
- 添加MessageHandler消息处理器接收消息
- 定义EndPoint时通过@OnMessage注解指定接收消息的方法
推送给客户端
由RemoteEndpoint完成,实例由Session维护,通过
- 通过session.getBasicRemote获取同步消息发送的实例,通过其SendXxx()方法发送信息
- 通过session.getBasicRemote获取异步消息发送的实例,通过其SendXxx()方法发送信息
这里的Session是WebSocket会话的Session,不是HTTP的Sessioin
消息格式
通过json进行数据传输,信息格式可以自己设计
编码指南
引入依赖
1 2 3 4 5 6
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <version>3.1.0</version> </dependency>
|
编写配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Configuration public class WebSocketConfig{ @Bean public ServerEndpointExporter serverEndpointExporter(){ return new ServerEndpointExporter(); } }
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator { 3 usages @Override public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request,HandshakeResponse response) { HttpSession httpSession = (HttpSession) request.getHttpSession(); sec.getUserProperties().put(HttpSession.class.getName() ,httpSession); } }
@ServerEndpoint(value="路径",configurator=GetHttpSessionConfig.class)
|
WebSocket类编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| @ServletEndpoint("/chat",configurator=GetHttpSessionConfig.class) @Componenet public class ChatEndpoint{ private static final Map<String,Session> onlineUsers=new ConcurrentHashMap<>(); HttpSession httpSession; @OnOpen public void onOpen(Session session, EndpointConfig config){ this.httpSession = config.getUserProperties().get(HttpSession.class.getName()); String user=(String)this.httpSession.getAttribute("user"); onlineUsers.put(user,session); broadcastAllUsers(MessageUtils.getMessage(True,"system",getFriends())); }
private Set getFriends(){ return onlineUsers.keySet(); }
private void broadcastAllUsers(String Message){ try{ Set<Map.Entry<String,Session>> entires=onlineUsers.entrySet(); for(Map.Entry<String,Session> entry:entires){ Session session=entry.getValue(); session.getBasicRemote().sendText(message); } }catch(Exception e){ e.printStackTrace(); } }
@OnMessage public void onMessage(String message){ try{ String user=(String)this.httpSession.getAttribute("user"); Message msg=JSON.parseObject(message,Message.class); String toName=msg.getToName(); String mess=msg.getMessage(); Session session=onlineUsers.get(toName); String toSendMsg=MessageUtils.getMessage(false,user,mess); session.getBasicRemote().sendText(toSendMsg); }catch(Exception e){ e.printStack(); } } @OnClose public void onClose(Session session){ String user=(String)this.httpSession.getAttribute("user"); onlineUsers.remove(user); broadcastAllUsers(MessageUtils.getMessage(True,"system",getFriends())); } }
|
消息工具类的编写