1. 1. 消息推送常见方式
    1. 1.1. 轮询
    2. 1.2. 长轮询
    3. 1.3. SSE-服务器发送事件
    4. 1.4. Web-Socket
  2. 2. Web-Socket API
    1. 2.1. 客户端API
      1. 2.1.1. 创建
      2. 2.1.2. 事件
      3. 2.1.3. 方法
    2. 2.2. 服务端API
      1. 2.2.1. 定义方法
      2. 2.2.2. 运行逻辑
      3. 2.2.3. 接收客户端发送的数据
      4. 2.2.4. 推送给客户端
    3. 2.3. 消息格式
  3. 3. 编码指南
    1. 3.1. 引入依赖
    2. 3.2. 编写配置类
    3. 3.3. WebSocket类编写
    4. 3.4. 消息工具类的编写

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的一端

定义方法

  1. 继承javax.websocket.Endpoint并实现其方法
  2. 定义一个POJO,添加@ServerEndpoint(“访问路径”)注解

运行逻辑

Endpoint实例在WebSocket握手时创建,在服务端和客户端保持连接的过程中持续有效,最后在连接关闭的时候结束

方法 描述 注解
onMessage() 服务端接收到客户端信息时调用 @onMessage
onError() 当连接过程异常时调用 @OnError
onOpen() 开启一个新的会话时调用 @OnOpen
onCLose() 会话关闭时调用 @OnClose

接收客户端发送的数据

  1. 添加MessageHandler消息处理器接收消息
  2. 定义EndPoint时通过@OnMessage注解指定接收消息的方法

推送给客户端

由RemoteEndpoint完成,实例由Session维护,通过

  1. 通过session.getBasicRemote获取同步消息发送的实例,通过其SendXxx()方法发送信息
  2. 通过session.getBasicRemote获取异步消息发送的实例,通过其SendXxx()方法发送信息
    这里的Session是WebSocket会话的Session,不是HTTP的Sessioin

消息格式

通过json进行数据传输,信息格式可以自己设计

编码指南

引入依赖

1
2
3
4
5
6
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-websocket -->
<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
//扫描具有@ServletEndpoint的Bean
@Configuration
public class WebSocketConfig{
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
//获取HttpSession对象
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {
3 usages
@Override
public void modifyHandshake(ServerEndpointConfig sec,HandshakeRequest request,HandshakeResponse response) {
HttpSession httpSession = (HttpSession) request.getHttpSession();
//将httpSession对象存储到配置对象中
sec.getUserProperties().put(HttpSession.class.getName() ,httpSession);
}
}
//在ServerEndpoint注解中引入配置器
@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;
//一个线程安全的Map
@OnOpen
public void onOpen(Session session, EndpointConfig config){//自动导入configurator中的类
//保存Session
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 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");
//解析JSON
Message msg=JSON.parseObject(message,Message.class);
//获取接收方用户名
String toName=msg.getToName();
String mess=msg.getMessage();
//获取消息接收方用户对应的session对象
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){
//从onlineUsers删除session对象
String user=(String)this.httpSession.getAttribute("user");
onlineUsers.remove(user);
//通知所有用户该用户下线了
broadcastAllUsers(MessageUtils.getMessage(True,"system",getFriends()));
}
}

消息工具类的编写

1