这里写自定义目录标题
一、消息推送常见方式
1、轮训方式
2、SSE(server-send event)服务器发送事件
3、websocket
二、websocket 是什么?
websocket 是一种基于TCP 连接上进行全双工通信的协议
三、websocket api的介绍
1、客户端 (浏览器)
-
websocket对象创建
-
websocket对象相关事件
-
websocket 对象提供的方法
2、服务端api
Tomcat 的7.0.5版本开始支持 websocket , 并且实现了Java websocket 规范。
Java websocket 应用由一系列的 Endpoint组成。
Endpoint 是一个java对象,代表websocket连接的一段。对于服务端,我们可以视其为处理具体websocket消息的接口。
我们可以通过两种方式定义EndPoint:
编程式,继承类 javax.websocket.Endpoint 并实现其方法
注解式,定义一个pojo,并添加@ServerEndPoint相关注解
-
服务端如何接收客户端发过来的数据呢?
-
编程式
通过添加MessageHandler消息处理器来接收消息 -
注解式
在定义endpoint时,通过@OnMessage 注解指定接收消息的方法
-
-
服务器如何推送消息给客户端
发送消息由RemoteEndpoint完成,其实例由Session维护。
四、实现在线聊天室
1、需求
通过websocket实现在线聊天室
2、聊天室流程分析
3、消息格式
4、代码实现
1) 引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2)编写配置类
扫描所有添加 @ServerEndpoint注解的Bean
@Configuration
public class WebsocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
编写配置类,用于获取 HttpSession 对象
public class GetHttpSessionConfig extends ServerEndpointConfig.Configurator {
/**
* @param sec
* @param request 握手请求
* @param response
*/
@Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
// 获取HttpSession对象
HttpSession httpSession = (HttpSession) request.getHttpSession();
// 将 HttpSession对象保存起来
sec.getUserProperties().put(HttpSession.class.getName(), httpSession);
}
}
在@ServerEndpoint 注解中引入配置器 @ServerEndpoint(value = “/chat”, configurator = GetHttpSessionConfig.class)
@ServerEndpoint(value = "/chat", configurator = GetHttpSessionConfig.class)
@Component
public class ChatEndpoint {
/**
* 使用static
* ChatEndpoint是多例的,多个实例共享一个Map对象
*/
private static final Map<String, Session> onlineUsers = new ConcurrentHashMap<>();
private HttpSession httpSession;
@OnOpen
public void onOpen(Session session, EndpointConfig endpointConfig) {
this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
String userName = (String) httpSession.getAttribute("user");
// 1、将我们的session进行保存
onlineUsers.put(userName, session);
// 2、广播消息,将登录的用户推送给所有的用户
String message = MessageUtils.getMessage(true, null, userName + "上线");
boardcast(message);
// 3、
}
/**
* 广播消息
*/
private void boardcast(String message) {
// 遍历 map 集合
Set<Map.Entry<String, Session>> entries = onlineUsers.entrySet();
for (Map.Entry<String, Session> entry : entries) {
Session session = entry.getValue();
try {
session.getBasicRemote().sendText(message);
} catch (IOException e) {
// 记录日志
}
}
}
/**
* 浏览器发送消息到服务端,该方法会被调用
*/
@OnMessage
public void onMessage(String message, EndpointConfig endpointConfig) {
try {
this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
String fromName = (String) httpSession.getAttribute("user");
// 将消息推送给指定的用户 message : {"toName":"张三","message":"你好"}
ClientMessage message1 = JSON.parseObject(message, ClientMessage.class);
String toName = message1.getToName();
Session session = onlineUsers.get(toName);
String message2 = MessageUtils.getMessage(false, fromName, message1.getMessage());
session.getBasicRemote().sendText(message2);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 当websocket连接断开时,此方法会被处罚
*/
@OnClose
public void onClose(Session session, EndpointConfig endpointConfig) {
// 从在线用户集合中剔除断开连接的用户
this.httpSession = (HttpSession) endpointConfig.getUserProperties().get(HttpSession.class.getName());
String userName = (String) httpSession.getAttribute("user");
onlineUsers.remove(userName);
// 通知其他用户当前用户下线
String message = MessageUtils.getMessage(true, null, userName + "上线");
boardcast(message);
}
}