1. 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2. 配置类
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter(){
return new ServerEndpointExporter();
}
}
3. 服务类
@ServerEndpoint("/socket/{id}")
@Component
public class WebSocketServer {
private static Log log = LogFactory.get(WebSocketServer.class);
// 当前客户端对应的会话
private Session session;
// 当前客户端对应的id
private String id;
// 存放每个客户端对应的WebSocket对象
private static ConcurrentHashMap<String,WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
// 当前连接数
private static int onlineCount = 0;
@OnOpen
public void onOpen(Session session, @PathParam("id") String id) {
this.session = session;
this.id = id;
if(webSocketMap.containsKey(id)){
webSocketMap.remove(id);
webSocketMap.put(id, this);
}else{
webSocketMap.put(id, this);
addOnlineCount();
}
log.info("用户连接:"+id+",当前在线人数为:" + getOnlineCount());
sendMessage("连接成功");
}
@OnClose
public void onClose() {
if(webSocketMap.containsKey(this.id)){
webSocketMap.remove(this.id);
subOnlineCount();
}
log.info("用户退出:"+ this.id +",当前在线人数为:" + getOnlineCount());
}
@OnMessage
public void onMessage(Session session, String msg) {
log.info("用户消息:"+ this.id +", 报文:"+msg);
System.out.println(msg);
}
@OnError
public void onError(Session session, Throwable error){
log.error("用户错误:"+ this.id +",原因:"+ error.getMessage());
error.printStackTrace();
}
/**
* 推送消息,抽取的公共方法,只在本类内部使用
* @param msg
*/
private void sendMessage(String msg){
try {
this.session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
log.error("用户:"+ this.id +",网络异常!!!!!!");
}
}
/**
* 主动推送消息
* @param msg
* @param id
*/
public static void pushMessage(String msg, String id){
if(StringUtils.isNotBlank(id) && webSocketMap.containsKey(id)){
webSocketMap.get(id).sendMessage(msg);
}else{
log.error("用户"+id+",不在线!");
}
}
/**
* 主动广播消息
* @param msg
*/
public static void broadcastMessage(String msg){
webSocketMap.forEach((k, v) -> {
v.sendMessage(msg);
log.info("广播到用户ID:" + k + ",消息内容:" + msg);
});
}
public static synchronized int getOnlineCount() {
return onlineCount;
}
public static synchronized void addOnlineCount() {
WebSocketServer.onlineCount++;
}
public static synchronized void subOnlineCount() {
WebSocketServer.onlineCount--;
}
}
4. 业务处理
// 推送到前端
WebSocketServer.pushMessage("msg", "1001");
// 广播到前端
WebSocketServer.broadcastMessage("msg");
5. 前端展示
5.1 目录说明
两个前端页面,模拟两个客户端
-| js
-| wevsocket.js
-| view
-| client1.html
-| client2.html
5.2 wevsocket.js
function openWebSocket(id){
var socket;
if(typeof(WebSocket) == "undefined") {
console.log("您的浏览器不支持WebSocket");
}else{
//实例化WebSocket对象,指定要连接的服务器地址与端口 建立连接
var socketUrl = "http://127.0.0.1:8082/api/socket/" + id;
socketUrl = socketUrl.replace("https","ws").replace("http","ws");
console.log(socketUrl);
if(socket != null){
socket.close();
socket = null;
}
socket = new WebSocket(socketUrl);
socket.onopen = function() {
console.log("websocket已打开");
};
socket.onmessage = function(msg) {
console.log(id + " - 消息收到:" + msg.data);
};
socket.onclose = function() {
console.log("websocket已关闭");
};
socket.onerror = function() {
console.log("websocket发生了错误");
}
}
}
5.3 client1.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="../js/websocket.js"></script>
</head>
<body>
<p>【SocketId】:<input id="id" name="id" type="text" value="0000" disabled></p>
</body>
<script>
$(function(){
openWebSocket($("#id").val());
})
</script>
</html>
5.4 client2.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
<script src="../js/websocket.js"></script>
</head>
<body>
<p>【SocketId】:<input id="id" name="id" type="text" value="1111" disabled></p>
</body>
<script>
$(function(){
openWebSocket($("#id").val());
})
</script>
</html>