SpringBoot整合WebSocket实现三种模式发送消息

1. 简介

  WebSocket是HTML5开始提供的一种在单个TCP连接上进行全双工通讯的协议。
  WebSocket的出现是为了解决Http协议只能在客户端发送请求后服务端响应请求的问题,它允许服务端主动向客户端发送请求。在WebSocket API中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
  在大多数情况下,为了实现消息推送,往往采用Ajax轮询方式,它遵循的是Http协议,在特定的时间内向服务端发送请求,Http协议的请求头较长,可能仅仅需要获取较小的数据而需要携带较多的数据,而且对于消息不是特别频繁的时候,大部分的轮询都是无意的,造成了极大的资源浪费。
  HTML5定义的WebSocket协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。

2. 本文简要

  本文基于SpringBoot框架整合WebSocket,实现三种模式发送消息:

  • 自己给自己发送消息
  • 自己给其他用户发送消息
  • 自己给指定用户发送消息

3. 示例代码

  • 创建工程
  • 修改pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.c3stones</groupId>
	<artifactId>spring-boot-websocket-demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring-boot-websocket-demo</name>
	<description>Spring Boot WebSocket Demo</description>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.8.RELEASE</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-all</artifactId>
			<version>5.4.1</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-websocket</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
  • 创建配置文件
      在resources目录下创建application.yml。
server:
  port: 8080
  
spring:
  thymeleaf:
    prefix: classpath:/view/
    suffix: .html
    encoding: UTF-8
    servlet:
      content-type: text/html
    # 生产环境设置true
    cache: false  
  • 添加WebSocket配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;

/**
 * WebSocket配置类
 * 
 * @author CL
 *
 */
@Configuration
public class WebSocketConfig {

	/**
	 * 注入ServerEndpointExporter
	 * <p>
	 * 该Bean会自动注册添加@ServerEndpoint注解的WebSocket端点
	 * </p>
	 * 
	 * @return
	 */
	@Bean
	public ServerEndpointExporter serverEndpointExporter() {
		return new ServerEndpointExporter();
	}

}
  • 创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 启动类
 * 
 * @author CL
 *
 */
@SpringBootApplication
public class Application {

	public static void main(String[] args) {
		SpringApplication.run(Application.class, args);
	}

}

3.1 自己给自己发送消息
  • 创建服务端点
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * <b style="color: blue"> 自己给自己发送消息 </b>
 * 
 * @author CL
 *
 */
@Slf4j
@Component
@ServerEndpoint(value = "/selfToSelf")
public class SelfToSelfServer {

	/**
	 * 在线数
	 * <p>
	 * 多线程环境下,为了保证线程安全
	 * </p>
	 */
	private static AtomicInteger online = new AtomicInteger(0);

	/**
	 * 建立连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnOpen
	public void onOpen(Session session) {
		// 在线数加1
		online.incrementAndGet();
		log.info("客户端连接建立成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 接收客户端消息
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("服务端接收消息成功,Session ID:{},消息内容:{}", session.getId(), message);

		// 处理消息,并响应给客户端
		this.sendMessage(message, session);
	}

	/**
	 * 处理消息,并响应给客户端
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	private void sendMessage(String message, Session session) {
		try {
			String response = "Server Response ==> " + message;
			session.getBasicRemote().sendText(response);

			log.info("服务端响应消息成功,接收的Session ID:{},响应内容:{}", session.getId(), response);
		} catch (IOException e) {
			log.error("服务端响应消息异常:{}", e.getMessage());
		}
	}

	/**
	 * 关闭连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnClose
	public void onClose(Session session) {
		// 在线数减1
		online.decrementAndGet();
		log.info("客户端连接关闭成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 连接异常
	 * 
	 * @param session 客户端连接对象
	 * @param error   异常
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("连接异常:{}", error);
	}

}
  • 创建测试页面
      在resource下创建views文件夹,并创建测试页面selfToSelfClient.html:
<!DOCTYPE HTML>
<html>
<head>
	<title>WebSocket - Self To Self</title>
</head>
<body>
	<input id="message" type="text" />
    <button onclick="sendMessage()">发送</button>
    <button onclick="closeWebSocket()">关闭</button>
    <hr/>
    <div id="response"></div>
</body>
<script type="text/javascript">
	var websocket = null;
	
	// 判断当前浏览器是否支持WebSocket
	if ('WebSocket' in window) {
	    websocket = new WebSocket("ws://localhost:8080/selfToSelf");
	} else {
	    alert("当前浏览器不支持WebSocket");
	}
	
	// 建立连接成功时的回调方法
    websocket.onopen = function (event) {
    	printMessage("green", "建立连接成功!!!");
    }
	
	// 连接异常时的回调方法
    websocket.onerror = function (event) {
    	printMessage("red", "连接异常!!!");
    };

    // 客户端接收消息时的回调方法
    websocket.onmessage = function (event) {
    	printMessage("blue", event.data);
    }

    // 关闭连接时的回调方法
    websocket.onclose = function() {
    	printMessage("yellow", "关闭连接成功!!!");
    }

    // 监听窗口关闭事件,当窗口关闭时,主动关闭连接,防止连接未断开时关闭窗口,服务端抛出异常
    window.onbeforeunload = function() {
        websocket.close();
    }
    
    // 发送消息
    function sendMessage() {
    	if (websocket.readyState != 1) {
    		printMessage("red", "未建立连接或者连接已处于关闭状态!");
    	} else {
    		 var message = document.getElementById('message').value;
    	     websocket.send(message);
    	}
    }
    
 	// 关闭连接
    function closeWebSocket() {
        websocket.close();
    }
 	
  	// 打印消息
    function printMessage(color, text) {
        document.getElementById("response").innerHTML += "<font color='" + color +"'>" + text + "</font><br/>";
    }
</script>
</html>
  • 创建跳转页面Controller
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 页面视图Controller
 * 
 * @author CL
 *
 */
@Controller
public class ViewController {

	/**
	 * 跳转到<b> 自己给自己发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToSelf")
	public String selfToSelf() {
		return "selfToSelfClient";
	}

}
  • 测试
    2020-12-29 19:21:39.916  INFO 1096 --- [nio-8080-exec-2] com.c3stones.server.SelfToSelfServer     : 客户端连接建立成功,Session ID:0,当前在线数:1
    2020-12-29 19:21:43.564  INFO 1096 --- [nio-8080-exec-3] com.c3stones.server.SelfToSelfServer     : 服务端接收消息成功,Session ID:0,消息内容:测试1
    2020-12-29 19:21:43.583  INFO 1096 --- [nio-8080-exec-3] com.c3stones.server.SelfToSelfServer     : 服务端响应消息成功,接收的Session ID:0,响应内容:Server Response ==> 测试1
    2020-12-29 19:21:45.290  INFO 1096 --- [nio-8080-exec-4] com.c3stones.server.SelfToSelfServer     : 客户端连接关闭成功,Session ID:0,当前在线数:0    
    
    • 浏览器截图
3.2 自己给其他用户发送消息
  • 创建服务端点
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * <b style="color: blue"> 自己给其他用户发送消息 </b>
 * 
 * @author CL
 *
 */
@Slf4j
@Component
@ServerEndpoint(value = "/selfToOther")
public class SelfToOtherServer {

	/**
	 * 在线数
	 * <p>
	 * 多线程环境下,为了保证线程安全
	 * </p>
	 */
	private static AtomicInteger online = new AtomicInteger(0);

	/**
	 * 在线客户端连接集合
	 * <p>
	 * 多线程环境下,为了保证线程安全
	 * </p>
	 */
	private static Map<String, Session> onlineMap = new ConcurrentHashMap<>();

	/**
	 * 建立连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnOpen
	public void onOpen(Session session) {
		// 在线数加1
		online.incrementAndGet();
		// 存放客户端连接
		onlineMap.put(session.getId(), session);
		log.info("客户端连接建立成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 接收客户端消息
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("服务端接收消息成功,Session ID:{},消息内容:{}", session.getId(), message);

		// 处理消息,并响应给客户端
		this.sendMessage(message, session);
	}

	/**
	 * 处理消息,并响应给客户端
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	private void sendMessage(String message, Session session) {
		String response = "Server Response ==> " + message;
		for (Map.Entry<String, Session> sessionEntry : onlineMap.entrySet()) {
			Session s = sessionEntry.getValue();
			// 过滤自己
			if (!(session.getId()).equals(s.getId())) {
				log.info("服务端响应消息成功,接收的Session ID:{},响应内容:{}", s.getId(), response);
				s.getAsyncRemote().sendText(response);
			}
		}
	}

	/**
	 * 关闭连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnClose
	public void onClose(Session session) {
		// 在线数减1
		online.decrementAndGet();
		// 移除关闭的客户端连接
		onlineMap.remove(session.getId());
		log.info("客户端连接关闭成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 连接异常
	 * 
	 * @param session 客户端连接对象
	 * @param error   异常
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("连接异常:{}", error);
	}

}
  • 创建测试页面
      在resource下的views文件夹创建测试页面selfToOtherClient.html:
<!DOCTYPE HTML>
<html>
<head>
	<title>WebSocket - Self To Other</title>
</head>
<body>
	<input id="message" type="text" />
    <button onclick="sendMessage()">发送</button>
    <button onclick="closeWebSocket()">关闭</button>
    <hr/>
    <div id="response"></div>
</body>
<script type="text/javascript">
	var websocket = null;
	
	// 判断当前浏览器是否支持WebSocket
	if ('WebSocket' in window) {
	    websocket = new WebSocket("ws://localhost:8080/selfToOther");
	} else {
	    alert("当前浏览器不支持WebSocket");
	}
	
	// 建立连接成功时的回调方法
    websocket.onopen = function (event) {
    	printMessage("green", "建立连接成功!!!");
    }
	
	// 连接异常时的回调方法
    websocket.onerror = function (event) {
    	printMessage("red", "连接异常!!!");
    };

    // 客户端接收消息时的回调方法
    websocket.onmessage = function (event) {
    	printMessage("blue", event.data);
    }

    // 关闭连接时的回调方法
    websocket.onclose = function() {
    	printMessage("yellow", "关闭连接成功!!!");
    }

    // 监听窗口关闭事件,当窗口关闭时,主动关闭连接,防止连接未断开时关闭窗口,服务端抛出异常
    window.onbeforeunload = function() {
        websocket.close();
    }
    
    // 发送消息
    function sendMessage() {
    	if (websocket.readyState != 1) {
    		printMessage("red", "未建立连接或者连接已处于关闭状态!");
    	} else {
    		 var message = document.getElementById('message').value;
    	     websocket.send(message);
    	}
    }
    
 	// 关闭连接
    function closeWebSocket() {
        websocket.close();
    }
 	
  	// 打印消息
    function printMessage(color, text) {
        document.getElementById("response").innerHTML += "<font color='" + color +"'>" + text + "</font><br/>";
    }
</script>
</html>
  • 添加跳转页面方法
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 页面视图Controller
 * 
 * @author CL
 *
 */
@Controller
public class ViewController {

	/**
	 * 跳转到<b> 自己给自己发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToSelf")
	public String selfToSelf() {
		return "selfToSelfClient";
	}
	
	/**
	 * 跳转到<b> 自己给其他用户发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToOther")
	public String selfToOther() {
		return "selfToOtherClient";
	}

}
  • 测试
    2020-12-29 19:53:52.654  INFO 6420 --- [nio-8080-exec-2] com.c3stones.server.SelfToOtherServer    : 客户端连接建立成功,Session ID:0,当前在线数:1
    2020-12-29 19:54:01.044  INFO 6420 --- [nio-8080-exec-5] com.c3stones.server.SelfToOtherServer    : 客户端连接建立成功,Session ID:1,当前在线数:2
    2020-12-29 19:54:14.494  INFO 6420 --- [nio-8080-exec-8] com.c3stones.server.SelfToOtherServer    : 客户端连接建立成功,Session ID:2,当前在线数:3
    2020-12-29 19:54:27.705  INFO 6420 --- [nio-8080-exec-9] com.c3stones.server.SelfToOtherServer    : 服务端接收消息成功,Session ID:0,消息内容:测试1
    2020-12-29 19:54:27.705  INFO 6420 --- [nio-8080-exec-9] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:1,响应内容:Server Response ==> 测试1
    2020-12-29 19:54:27.753  INFO 6420 --- [nio-8080-exec-9] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:2,响应内容:Server Response ==> 测试1
    2020-12-29 19:54:43.084  INFO 6420 --- [nio-8080-exec-2] com.c3stones.server.SelfToOtherServer    : 服务端接收消息成功,Session ID:1,消息内容:测试2
    2020-12-29 19:54:43.085  INFO 6420 --- [nio-8080-exec-2] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:0,响应内容:Server Response ==> 测试2
    2020-12-29 19:54:43.086  INFO 6420 --- [nio-8080-exec-2] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:2,响应内容:Server Response ==> 测试2
    2020-12-29 19:54:48.474  INFO 6420 --- [nio-8080-exec-5] com.c3stones.server.SelfToOtherServer    : 服务端接收消息成功,Session ID:2,消息内容:测试3
    2020-12-29 19:54:48.474  INFO 6420 --- [nio-8080-exec-5] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:0,响应内容:Server Response ==> 测试3
    2020-12-29 19:54:48.475  INFO 6420 --- [nio-8080-exec-5] com.c3stones.server.SelfToOtherServer    : 服务端响应消息成功,接收的Session ID:1,响应内容:Server Response ==> 测试3
    
    • 浏览器截图


3.3 自己给指定用户发送消息
  • 创建服务端点
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * <b style="color: blue"> 自己给指定用户发送消息 </b>
 * 
 * @author CL
 *
 */
@Slf4j
@Component
@ServerEndpoint(value = "/selfToSpecific")
public class SelfToSpecificServer {

	/**
	 * 在线数
	 * <p>
	 * 多线程环境下,为了保证线程安全
	 * </p>
	 */
	private static AtomicInteger online = new AtomicInteger(0);

	/**
	 * 在线客户端连接集合
	 * <p>
	 * 多线程环境下,为了保证线程安全
	 * </p>
	 */
	private static Map<String, Session> onlineMap = new ConcurrentHashMap<>();

	/**
	 * 建立连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnOpen
	public void onOpen(Session session) {
		// 在线数加1
		online.incrementAndGet();
		// 存放客户端连接
		onlineMap.put(session.getId(), session);
		log.info("客户端连接建立成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 接收客户端消息
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("服务端接收消息成功,Session ID:{},消息内容:{}", session.getId(), message);

		// 解析出指定用户
		JSONObject jsonObj = JSONUtil.parseObj(message);
		if (jsonObj != null) {
			Session s = onlineMap.get(jsonObj.get("sessionId"));
			// 处理消息,并响应给客户端
			this.sendMessage(jsonObj.get("message").toString(), s);
		}
	}

	/**
	 * 处理消息,并响应给客户端
	 * 
	 * @param message 客户端发送的消息内容
	 * @param session 客户端连接对象
	 */
	private void sendMessage(String message, Session session) {
		try {
			String response = "Server Response ==> " + message;
			session.getBasicRemote().sendText(response);

			log.info("服务端响应消息成功,接收的Session ID:{},响应内容:{}", session.getId(), response);
		} catch (IOException e) {
			log.error("服务端响应消息异常:{}", e.getMessage());
		}
	}

	/**
	 * 关闭连接
	 * 
	 * @param session 客户端连接对象
	 */
	@OnClose
	public void onClose(Session session) {
		// 在线数减1
		online.decrementAndGet();
		// 移除关闭的客户端连接
		onlineMap.remove(session.getId());
		log.info("客户端连接关闭成功,Session ID:{},当前在线数:{}", session.getId(), online.get());
	}

	/**
	 * 连接异常
	 * 
	 * @param session 客户端连接对象
	 * @param error   异常
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("连接异常:{}", error);
	}

}
  • 创建测试页面
      在resource下的views文件夹创建测试页面selfToSpecificClient.html:
<!DOCTYPE HTML>
<html>
<head>
	<title>WebSocket - Self To Specific</title>
</head>
<body>
	消息:<input id="message" type="text" /><br/>
	Session Id:<input id="sessionId" type="text" /><br/>
    <button onclick="sendMessage()">发送</button>
    <button onclick="closeWebSocket()">关闭</button>
    <hr/>
    <div id="response"></div>
</body>
<script type="text/javascript">
	var websocket = null;
	
	// 判断当前浏览器是否支持WebSocket
	if ('WebSocket' in window) {
	    websocket = new WebSocket("ws://localhost:8080/selfToSpecific");
	} else {
	    alert("当前浏览器不支持WebSocket");
	}
	
	// 建立连接成功时的回调方法
    websocket.onopen = function (event) {
    	printMessage("green", "建立连接成功!!!");
    }
	
	// 连接异常时的回调方法
    websocket.onerror = function (event) {
    	printMessage("red", "连接异常!!!");
    };

    // 客户端接收消息时的回调方法
    websocket.onmessage = function (event) {
    	printMessage("blue", event.data);
    }

    // 关闭连接时的回调方法
    websocket.onclose = function() {
    	printMessage("yellow", "关闭连接成功!!!");
    }

    // 监听窗口关闭事件,当窗口关闭时,主动关闭连接,防止连接未断开时关闭窗口,服务端抛出异常
    window.onbeforeunload = function() {
        websocket.close();
    }
    
    // 发送消息
    function sendMessage() {
    	if (websocket.readyState != 1) {
    		printMessage("red", "未建立连接或者连接已处于关闭状态!");
    	} else {
    		 var message = document.getElementById('message').value;
    		 var sessionId = document.getElementById('sessionId').value;
    		 
    		 var obj = new Object();
    		 obj.message = message;
    		 obj.sessionId = sessionId;
    	     websocket.send(JSON.stringify(obj));
    	}
    }
    
 	// 关闭连接
    function closeWebSocket() {
        websocket.close();
    }
 	
  	// 打印消息
    function printMessage(color, text) {
        document.getElementById("response").innerHTML += "<font color='" + color +"'>" + text + "</font><br/>";
    }
</script>
</html>
  • 添加跳转页面方法
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 页面视图Controller
 * 
 * @author CL
 *
 */
@Controller
public class ViewController {

	/**
	 * 跳转到<b> 自己给自己发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToSelf")
	public String selfToSelf() {
		return "selfToSelfClient";
	}

	/**
	 * 跳转到<b> 自己给其他用户发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToOther")
	public String selfToOther() {
		return "selfToOtherClient";
	}

	/**
	 * 跳转到<b> 自己给指定用户发送消息 </b>页面
	 * 
	 * @return
	 */
	@RequestMapping(value = "/selfToSpecific")
	public String selfToSpecific() {
		return "selfToSpecificClient";
	}

}
  • 测试
    2020-12-29 20:27:47.043  INFO 9004 --- [nio-8080-exec-2] c.c3stones.server.SelfToSpecificServer   : 客户端连接建立成功,Session ID:0,当前在线数:1
    2020-12-29 20:27:49.558  INFO 9004 --- [nio-8080-exec-4] c.c3stones.server.SelfToSpecificServer   : 客户端连接建立成功,Session ID:1,当前在线数:2
    2020-12-29 20:27:56.886  INFO 9004 --- [nio-8080-exec-7] c.c3stones.server.SelfToSpecificServer   : 服务端接收消息成功,Session ID:0,消息内容:{"message":"测试1","sessionId":"1"}
    2020-12-29 20:28:06.785  INFO 9004 --- [nio-8080-exec-7] c.c3stones.server.SelfToSpecificServer   : 服务端响应消息成功,接收的Session ID:1,响应内容:Server Response ==> 测试1
    2020-12-29 20:28:19.007  INFO 9004 --- [io-8080-exec-10] c.c3stones.server.SelfToSpecificServer   : 服务端接收消息成功,Session ID:1,消息内容:{"message":"测试2","sessionId":"0"}
    2020-12-29 20:28:19.008  INFO 9004 --- [io-8080-exec-10] c.c3stones.server.SelfToSpecificServer   : 服务端响应消息成功,接收的Session ID:0,响应内容:Server Response ==> 测试2
    
    • 浏览器截图

4. 项目地址

  spring-boot-websocket-demo

posted @ 2020-12-29 20:35  C3Stones  阅读(2677)  评论(0编辑  收藏  举报