首先是pom
<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.5.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<groupId>com.baidu.websocket</groupId>
<artifactId>websocket</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>websocket</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>RELEASE</version>
</dependency>
<!-- 进行页面跳转 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.1.0</version>
</dependency>
<!-- 热部署 -->
<!-- devtools可以实现页面热部署(即页面修改后会立即生效,
这个可以直接在application.properties文件中配置spring.thymeleaf.cache=false来实现) -->
<!-- 实现类文件热部署(类文件修改后不会立即生效),实现对属性文件的热部署。 -->
<!-- 即devtools会监听classpath下的文件变动,并且会立即重启应用(发生在保存时机),
注意:因为其采用的虚拟机机制,该项重启是很快的 -->
<!-- (1)base classloader (Base类加载器):加载不改变的Class,例如:第三方提供的jar包。 -->
<!-- (2)restart classloader(Restart类加载器):加载正在开发的Class。 -->
<!-- 为什么重启很快,因为重启的时候只是加载了在开发的Class,没有重新加载第三方的jar包。 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<!-- optional=true, 依赖不会传递, 该项目依赖devtools;
之后依赖boot项目的项目如果想要使用devtools, 需要重新引入 -->
<optional>true</optional>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
接下来是配置文件sockjs的配置文件
package com.baidu.websocket.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.AbstractWebSocketMessageBrokerConfigurer;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
/**
* 配置WebSocket
*/
@Configuration
//注解开启使用STOMP协议来传输基于代理(message broker)的消息,这时控制器支持使用@MessageMapping,就像使用@RequestMapping一样
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer{
@Override
//注册STOMP协议的节点(endpoint),并映射指定的url
public void registerStompEndpoints(StompEndpointRegistry registry) {
//注册一个STOMP的endpoint,并指定使用SockJS协议
registry.addEndpoint("/endpointOyzc").setAllowedOrigins("*").withSockJS();
}
@Override
//配置消息代理(Message Broker)
public void configureMessageBroker(MessageBrokerRegistry registry) {
//点对点应配置一个/user消息代理,广播式应配置一个/topic消息代理,群发(mass),单独聊天(alone)
registry.enableSimpleBroker("/topic","/user","/mass","/alone");
//点对点使用的订阅前缀(客户端订阅路径上会体现出来),不设置的话,默认也是/user/
registry.setUserDestinationPrefix("/user");
}
}
接下来是Controller
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import com.baidu.websocket.model.ChatRoomRequest;
import com.baidu.websocket.model.ChatRoomResponse;
@Controller
public class qunfacontroller {
@Autowired
private SimpMessagingTemplate template;
//websocket前端向后端发送的地址
@MessageMapping("/qunfamassage")
//websocket后端向前端发送的地址
@SendTo("/topic/getResponse")
public ChatRoomResponse mass(ChatRoomRequest chatRoomRequest){
//方法用于群发测试
System.out.println("姓名是 = " + chatRoomRequest.getName());
System.out.println("消息是 = " + chatRoomRequest.getChatValue());
ChatRoomResponse response=new ChatRoomResponse();
response.setName(chatRoomRequest.getName());
response.setChatValue(chatRoomRequest.getChatValue());
return response;
}
}
接下来是ChatRoomResponse类
public class ChatRoomResponse {
private String userId;
private String name;
private String chatValue;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getChatValue() {
return chatValue;
}
public void setChatValue(String chatValue) {
this.chatValue = chatValue;
}
}
接下来是ChatRoomRequest类
public class ChatRoomRequest {
private String userId;
private String name;
private String chatValue;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getChatValue() {
return chatValue;
}
public void setChatValue(String chatValue) {
this.chatValue = chatValue;
}
}
接下来写前端
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>这是一个群发的Message</title>
<style type="text/css">
* {
margin: 0;
padding: 0;
}
#top {
text-align: center;
margin-top: 10px;
}
#left {
width: 700px;
height: 600px;
float: left;
background: #dddddd;
border: 1px solid #a1a1a1;;
border-radius: 25px;
margin-left: 30px;
margin-top: 30px;
}
#right {
width: 700px;
height: 600px;
float: right;
background: #dddddd;
border: 1px solid #a1a1a1;;
border-radius: 25px;
margin-right: 30px;
margin-top: 30px;
}
#selectuser {
text-align: center;
margin-top: 10px;
}
#sendChatValue {
width: 90%;
height: 400px;
margin-top: 20px;
margin-right: 20px;
margin-left: 20px;
margin-bottom: 20px;
}
#input {
text-align: center;
}
#message {
margin-top: 20px;
margin-left: 20px;
}
input {
font-size: 15px;
height: 30px;
width: 50px;
border-radius: 4px;
border: 2px solid #c8cccf;
color: #6a6f77;
}
select {
font-size: 15px;
height: 30px;
border-radius: 4px;
border: 2px solid #c8cccf;
color: #6a6f77;
}
</style>
</head>
<body>
<!-- 头部 -->
<div id="top">
<h1>这是一个群发的Message</h1>
</div>
<div id="left">
<div id="selectuser">
<select id="selectName">
<option value="1">请选择发送用户</option>
<option value="张三">张三</option>
<option value="李四">李四</option>
<option value="王五">王五</option>
<option value="小六">小六</option>
</select>
</div>
<div>
<textarea name="sendChatValue" id="sendChatValue"
class="sendChatValue"></textarea>
<div id="input">
<input type="button" name="sendMessage" id="sendMessage"
class="btn btn-default" onclick="sendMassMessage()" value="发送">
</div>
</div>
</div>
<div id="right">
<div id="message"></div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.slim.js"></script>
<script type="text/javascript" src="js/qunfa.js" charset="utf-8"></script>
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script src="https://cdn.bootcss.com/stomp.js/2.3.3/stomp.min.js"></script>
</body>
</html>
接下来写qunfa.js
var stompClient = null;
//加载完浏览器后 调用connect(),打开双通道
$(function(){
//打开双通道
connect()
})
//强制关闭浏览器 调用websocket.close(),进行正常关闭
window.onunload = function() {
disconnect()
}
//打开双通道
function connect(){
var socket = new SockJS('/endpointOyzc'); //连接SockJS的endpoint名称为"endpointAric"
stompClient = Stomp.over(socket);//使用STMOP子协议的WebSocket客户端
stompClient.connect({},function(frame){//连接WebSocket服务端
console.log('Connected:' + frame);
//广播接收信息
console.log('开始接受消息...');
stompTopic();
console.log('消息接受完毕');
});
}
//关闭双通道
function disconnect(){
if(stompClient != null) {
stompClient.disconnect();
}
console.log("Disconnected");
}
//广播(一对多)
function stompTopic(){
console.log('进入广播接受模式...');
//通过stompClient.subscribe订阅/topic/getResponse 目标(destination)发送的消息(广播接收信息)
stompClient.subscribe('/topic/getResponse',function(response){
var message=JSON.parse(response.body);
//展示广播的接收的内容接收
var response = $("#message");
response.append("<p>发消息的人是:<span style='color:#F00'>"+message.name+" </span>发送的信息是:<span style='color:#F00'>"+message.chatValue+"</span></p>");
});
}
//群发消息
function sendMassMessage(){
var postValue={};
var chatValue=$("#sendChatValue");
var userName=$("#selectName").val();
postValue.name=userName;
postValue.chatValue=chatValue.val();
if(userName==1||userName==null){
alert("请选择你是谁!");
return;
}
if(chatValue==""||userName==null){
alert("不能发送空消息!");
return;
}
stompClient.send("/qunfamassage",{},JSON.stringify(postValue));
chatValue.val("");
console.log('消息已发出');
}