SpringBoot整合WebSocket
1.简介
在WebSocket之前想要实现即时的通信效果,往往采用定时轮询AJAX发送HTTP请求来实现的,这种方式会导致网络带宽的浪费,多次请求的实时性也不高,频繁的建立和断开连接也会占用CPU资源,造成不必要的浪费
WebSocket的出现解决了上述问题,WebSocket是一个基于TCP实现的一个全双工通信协议,通过一次请求建立一个长效的连接
- 头部数据较少,可以节省带宽
- 通过建立一个长连接来实现是即时通信
2.应用场景
- 体育实况更新
- 视频弹幕
- 定位软件
- 股票大屏
- 协同编辑
3.maven坐标
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
4.整合
首先创建一个配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
接着,开始写websocket的处理逻辑
@Component
@Slf4j
@ServerEndpoint("/websocket/{userId}")
public class WsService {
//与某个客户端的连接会话,通过session向客户端发送数据
private Session session;
//当前在线用户数量
private static int onlineCount = 0;
private String userId;
//concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。
private static CopyOnWriteArraySet<WsService> webSockets =new CopyOnWriteArraySet<>();
// 用来存在线连接用户信息
private static ConcurrentHashMap<String,WsService> webSocketMap = new ConcurrentHashMap<String,WsService>();
/*
* 建立连接调用的方法
* */
@OnOpen
public void onOpen(Session session,@PathParam("userId") String userId) throws IOException {
this.session=session;
this.userId=userId;
if (!webSocketMap.containsKey(userId)){
webSocketMap.put(userId,this);
addOnlineCount();
}
log.info("用户连接:"+userId+",当前在线人数为:"+getOnlineCount());
sendMessage("连接成功");
}
/*
* 连接关闭调用的方法
* */
@OnClose
public void onClose(){
if (webSocketMap.containsKey(userId)){
webSocketMap.remove(userId);
subOnlineCount();
}
log.info("用户退出:"+userId+",当前在线人数为:"+getOnlineCount());
}
/*
* 收到客户端消息调用的方法
* */
@OnMessage
public void onMessage(String message,Session session){
log.info("【webSocket消息】收到客户端发来的消息:{}",message);
}
@OnError
public void onError(Session session,Throwable error){
log.error("用户错误:"+userId+",原因:"+error.getMessage());
error.printStackTrace();
}
/*
* 服务端主动发送消息
* */
public void sendMessage(String message) throws IOException {
this.session.getBasicRemote().sendText(message);
}
/*
* 发送自定义消息
* */
public static void sendInfo(String message,@PathParam("userId") String userId) throws IOException {
log.info("发送消息到:"+userId+",报文:"+message);
if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)){
webSocketMap.get(userId).sendMessage(message);
}else {
log.error("用户:"+userId+",不在线!");
}
}
public static synchronized void addOnlineCount(){
onlineCount++;
}
public static synchronized int getOnlineCount(){
return onlineCount;
}
public static synchronized void subOnlineCount(){
onlineCount--;
}
}
tOnlineCount(){
return onlineCount;
}
public static synchronized void subOnlineCount(){
onlineCount--;
}
}