1、创建项目,添加依赖
<!--Web Socket 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>webjars-locator-core</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>sockjs-client</artifactId>
<version>1.1.2</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>stomp-websocket</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
spring-boot-starter websocket
依赖是 Web Socket 相关依赖,其他的都是前端库,使用 jar 包的形式对这些前端库进行统一管理,使用 webjar 添加到项目中的前端库,在 Spring Boot 项目中已经默认添加了静态资源过滤,因 可以直接使用。
2、配置 WebSocket
Spring 框架提供了基于 WebSocket 的 STOMP 支持, STOMP 是一个简单的可互操作的协议,通常被用于通过中间服务器在客户端之间进行异步消息传递。 WebSocket 配置如下:
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
/**
* 功能描述:自定义类配置 WebSocket
* @author wi-gang
* @date 2022/2/10 11:01 上午
*/
@Configuration
//开启 WebSocket 消息代理
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
//定义一个前缀为"/chat"的 endpoint,并开启sockjs支持
//sockjs可以解决浏览器对 WebSocket 的兼容性问题,客户端通过这里配置的URL来建立 WebSocket 连接
registry.addEndpoint("/chat").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
//设置消息代理的前缀,即如果消息的前缀是"/topic",就会将消息转发给消息代理(broker),再由消息代理将消息广播给当前连接的客户端。
registry.enableSimpleBroker("/topic");
//配置一个或者多个前缀,通过这些前缀过滤出需要被注解方法处理的消息
//例如:前缀为"/app"的 destination 可以通过@MessageMapping注解的方法处理,而其他destination(例如"topic","/queue")将被直接交给broker处理。
registry.setApplicationDestinationPrefixes("/app");
}
}
3、定义 Controller
@RestController
public class TestController {
@MessageMapping("/hello")
@SendTo("/topic/greetings")
public Message greeting(Message message){
return message;
}
}
class Message{
private String name;
private String content;
//省略get/set方法
}
@MessageMapping("/hello")
注解的方法将用来接收/app/hello
路径发送来的消息,在注解方法中对消息进行处理后,再将消息转发到@SendTo
定义的路径上,而@SendTo
路径是一个前缀为/topic
的路径,因此该消息将被交给消息代理 broker ,再由 broker 进行广播。
4、构建聊天页面
在 resources/static
目录下创建chat.html
页面作为聊天页面,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>群聊</title>
<!--引入外部的 JS 库,这些 JS 库在 pom.xml 文件中通过依赖加入进来-->
<script src="/webjars/jquery/jquery.min.js"></script>
<script src="/webjars/sockjs-client/sockjs.min.js"></script>
<script src="/webjars/stomp-websocket/stomp.min.js"></script>
<!--自定义js-->
<script src="/app.js"></script>
</head>
<body>
<div>
<label for="name">请输入用户名:</label>
<input type="text" id="name" placeholder="用户名">
</div>
<div>
<button id="connect" type="button">连接</button>
<button id="disconnect" type="button" disabled="disabled">断开连接</button>
</div>
<div id="chat" style="display: none;">
<div>
<label for="name">请输入聊天内容:</label>
<input type="text" id="content" placeholder="聊天内容">
</div>
<button id="send" type="button">发送</button>
<div id="greetings">
<div id="conversation" style="display: none;">群聊进行中....</div>
</div>
</div>
</body>
</html>
在resources/static/
目下新建app.js
var stompClient = null;
function setConnected(connected) {
$("#connect").prop("disabled", connected);
$("#disconnect").prop("disabled", !connected);
console.log("--->",connected)
if (connected) {
$("#conversation").show();
$("#chat").show();
} else {
$("#conversation").hide();
$("#chat").hide();
}
$("#greetings").html("");
}
//建立一个 WebSocket 连接,在建立 WebSocket 连接时,用户必须先输入用户名,然后才能建立连接
function connect() {
if (!$("#name").val()) {
return;
}
//使用 SockJS 建立连接,然后创建一个 STOMP 实例发起连接请求 在连接成功的回调方法中,
// 首先调用 setConnected(true);方法进行页面的设置,然后调用 STOMP 中的 subscribe 方法订阅服务端发送回来的消息,并将服务端发送来的消息展示出来(使用 showGreeting 方法)
var socket = new SockJS('/chat');
stompClient = Stomp.over(socket);
stompClient.connect({}, function (frame) {
setConnected(true);
stompClient.subscribe('/topic/greetings', function (greeting) {
showGreeting(JSON.parse(greeting.body));
});
})
}
// 断开一个 WebSocket 连接
function disconnect() {
if (stompClient !== null) {
stompClient.disconnect();
}
setConnected(false);
}
function sendName() {
stompClient.send("/app/hello", {},
JSON.stringify({
'name': $("#name").val(), 'content': $("#content").val()
}));
}
function showGreeting(message) {
console.log("message--->",message)
$("#greetings").append("<div>" + message.name + ":" + message.content + "</div>");
}
$(function () {
$("#connect").click(function () {
connect();
});
$("#disconnect").click(function () {
disconnect();
});
$("#send").click(function () {
sendName();
});
})
5、测试
接下来启动 Spring Boot 项目进行测试,在浏览器中输入http://localhost:8080/chat.html
,显示如下:
用户首先输入用户名,然后单击 “连接”按钮,结果如图所示
然后换个浏览器,或者使用 Chrome 浏览器的多用户(注意不是多窗口),重复刚才的步骤,这样就有两个用户连接上了,接下来就可以开始群聊了(当然也可以有更多的用户连接上来),如:
@SendTo
注解将方法处理过的消息转发到broker ,再由 broker 进行消息广播。除了@SendTo 注解外, Spring 还提供了 SimpMessagingTemplate
类来让开发者更加灵活地发送消息。可以在TestController
中引入SimpMessagingTemplate
。效果与上面一样。
@RestController
public class TestController {
@Autowired
private SimpMessagingTemplate simpMessagingTemplate;
// @MessageMapping("/hello")
// @SendTo("/topic/greetings")
// public Message greeting(Message message){
// return message;
// }
@MessageMapping("/hello")
public void greeting(Message message){
simpMessagingTemplate . convertAndSend ("/topic/greetings", message) ;
}
}