因为 HTTP 协议有一个缺陷:通信只能由客户端发起,HTTP 协议做不到服务器主动向客户端推送信息。
WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端
org.springframework.boot
spring-boot-starter-websocket
WebSocketConfig启用WebSocket的支持
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
WebSocketServer
因为WebSocket是类似客户端服务端的形式(采用ws协议),那么这里的WebSocketServer其实就相当于一个ws协议的Controller
直接@ServerEndpoint("/imserver/{userId}") 、@Component启用即可,然后在里面实现@OnOpen开启连接,@onClose关闭连接,@onMessage接收消息等方法。
新建一个ConcurrentHashMap webSocketMap 用于接收当前userId的WebSocket,方便IM之间对userId进行推送消息。单机版实现到这里就可以。
集群版(多个ws节点)还需要借助mysql或者redis等进行处理,改造对应的sendMessage方法即可。
@ServerEndpoint("/imserver/{userId}")
@Component
public class WebSocketService {
private static ConcurrentHashMap webSocketMap = new ConcurrentHashMap<>();
private Session session;
private String userId = "";
@OnOpen
public void onOpen(Session session, @PathParam("userId") String userId) {
this.session = session;
this.userId = userId;
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
webSocketMap.put(userId, this);
//加入set中
} else {
webSocketMap.put(userId, this);
//加入set中
}
//服务端向客户端发送信息
sendMessage("用户" + userId + "上线了,当前在线人数为:" + webSocketMap.size() + "。");
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
public void sendMessage(String message) {
try {
this.session.getBasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public static void sendInfo(String message, String userId, String toUserId) {
//log.info("发送消息到:"+userId+",报文:"+message);
if (StringUtils.isNotBlank(toUserId) && webSocketMap.containsKey(toUserId)) {
webSocketMap.get(toUserId).sendMessage(message);
} else {
webSocketMap.get(userId).sendMessage(toUserId + "已经下线。");
}
}
public static void close(String userId) {
if (webSocketMap.containsKey(userId)) {
webSocketMap.remove(userId);
}
}
public static Map getOnlineUser() {
return webSocketMap;
}
}
controller 对外提供发送 关闭websocket方法
@RestController
public class DemoController {
@PostMapping("/push")
public ResponseEntity pushToWeb(String message, String toUserId,String userId) throws IOException {
WebSocketService.sendInfo(message,userId,toUserId);
return ResponseEntity.ok("MSG SEND SUCCESS");
}
@GetMapping("/close")
public String close(String userId){
WebSocketService.close(userId);
return "ok";
}
@GetMapping("/getOnlineUser")
public Map getOnlineUser(){
return WebSocketService.getOnlineUser();
}
}
html 前端页面
websocket通讯
【内容】:
【当前用户】:
【发送用户】:
【发送的内容】:
【操作】:
【操作】:
【操作】:



