目录
-
- 后端
- 前端
- 效果展示
- 报错解决方法
-
- [1、vue3 使用SockJS报错 ReferenceError: global is not defined](#1、vue3 使用SockJS报错 ReferenceError: global is not defined)
- 后面将继续完善,待更新...
后端
pom.xml
java
<!-- Spring Boot WebSocket-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<!-- Spring Boot 数据库支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Thymeleaf(如果你使用了模板) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- Spring Boot Web 支持 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Config配置类
注意:允许源根据自己项目修改
java
import lombok.extern.slf4j.Slf4j;
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;
@Configuration
@EnableWebSocketMessageBroker
@Slf4j
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/queue", "/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/ws")
.setAllowedOrigins("http://127.0.0.1:8889", "http://localhost:8889", "http://localhost:8888", "http://127.0.0.1:8888", "http://localhost:8000")
.withSockJS(); // 添加 SockJS 支持
}
}
Controller类
java
import com.tianwen.user.dtos.MessageDTO;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.SendTo;
import org.springframework.stereotype.Controller;
@Controller
public class ChatController {
@MessageMapping("/chat.sendMessage")
@SendTo("/topic/messages")
public MessageDTO sendMessage(MessageDTO messageDTO) throws Exception {
System.out.println("接收到的message:"+messageDTO);
// 可以在这里进行私信存储到数据库操作
return messageDTO;
}
}
DTO
java
import lombok.Data;
@Data
public class MessageDTO {
private Integer senderId;
private Integer receiverId;
private String content;
}
前端
安装相关依赖
javascript
npm install sockjs-client@latest
npm install @stomp/stompjs sockjs-client
npm install global
npm i --save-dev @types/sockjs-client
websocketService.js接口
注意:服务器地址根据自己的修改(application.yml)
javascript
// websocketService.js
import { Stomp } from "@stomp/stompjs";
import SockJS from "sockjs-client/dist/sockjs.min.js";
export default {
connect(onMessageReceived) {
const socket = new SockJS("http://localhost:8000/ws"); // 使用 SockJS 连接
const stompClient = Stomp.over(socket);
stompClient.connect({}, () => {
stompClient.subscribe("/topic/messages", (messageOutput) => {
onMessageReceived(JSON.parse(messageOutput.body));
});
});
},
sendMessage(message) {
const socket = new SockJS("http://localhost:8000/ws"); // 使用 SockJS 连接
const stompClient = Stomp.over(socket);
stompClient.connect({}, () => {
stompClient.send("/app/chat.sendMessage", {}, JSON.stringify(message));
});
},
};
javascript
javascript
<script setup lang="ts">
import '@wangeditor/editor/dist/css/style.css' // 引入 css
import { onBeforeUnmount, ref, shallowRef, onMounted } from 'vue'
import { Editor, Toolbar } from '@wangeditor/editor-for-vue'
import type { IToolbarConfig, IEditorConfig } from "@wangeditor/editor";
const editorRef = shallowRef();
import websocketService from "@/api/websocketService.js";
import {
ref,
onMounted,
} from "vue";
import websocketService from "@/api/websocketService.js";
const receiverIdAnswer = ref();
const sendPrivateMessage = () => {
dialogVisible.value = true;
};
const sendPrivateMessage = async (userId) => {
receiverIdAnswer.value = userId;
dialogVisible.value = true;
const response = await getAuthorDetailsByUserId(userId);
console.log("response", userId);
privateMessagesUser.value = response.data;
console.log("privateMessagesUser", privateMessagesUser.value);
};
const dialogVisible = ref(false);
interface Message {
id: string;
senderId: string;
receiverId: string;
content: string;
}
const messages = ref<Message[]>([]); // 明确指定消息数组的类型
const newMessage = ref("");
onMounted(() => {
websocketService.connect((message: Message) => {
// 明确指定回调函数的参数类型
messages.value.push(message);
});
});
const sendMessage = () => {
if (newMessage.value.trim()) {
const message: Message = {
// 明确声明消息类型
id: Date.now().toString(), // 使用当前时间戳作为唯一 ID
senderId: userInfo.value.id, // Example sender
receiverId: receiverIdAnswer.value, // Example receiver
content: newMessage.value,
};
websocketService.sendMessage(message);
newMessage.value = "";
}
};
const editorConfig: Partial<IEditorConfig> = {
placeholder: "请输入...",
MENU_CONF: {},
};
const handleCreated = (editor) => {
editorRef.value = editor;
};
// 排除富文本的菜单项
const toolbarConfigPrivateMessages: Partial<IToolbarConfig> = {
// toolbar 配置
excludeKeys: [
"headerSelect",
"blockquote",
"|",
"bold",
"underline",
"italic",
"group-more-style", // 排除菜单组,写菜单组 key 的值即可
"color",
"bgColor",
"|",
"fontSize",
"fontFamily",
"lineHeight",
"bulletedList",
"numberedList",
"todo",
"group-justify",
"group-indent",
"insertLink",
"group-video",
"insertTable",
"codeBlock",
"divider",
"undo",
"redo",
"fullScreen",
],
};
</script>
html
html
<!-- 私信聊天框 -->
<el-dialog v-model="dialogVisible">
<template #title>
<div style="text-align: center; font-weight: bold">
{{ privateMessagesUser.username }}
</div>
<hr class="line" />
</template>
<div class="chat-container">
<div class="messages" ref="messagesContainer">
<div
v-for="message in messages"
:key="message.id"
:class="{
'my-message': message.senderId === userInfo.id,
'other-message': message.senderId !== userInfo.id,
}"
>
<div style="display: flex; flex-direction: row">
<div>
<el-image
:src="userInfo.avatarUrl"
style="width: 45px; border-radius: 50%"
></el-image>
</div>
<div style="margin-top: 5px; margin-left: 10px">
<div>
<strong>{{ userInfo.username }}</strong>
</div>
<div
class="message-bubble message-green"
v-html="message.content"
></div>
</div>
</div>
</div>
</div>
</div>
<div style="border: 1px solid #ccc">
<Toolbar
style="border-bottom: 1px solid #ccc"
:editor="editorRef"
:defaultConfig="toolbarConfigPrivateMessages"
mode="default"
/>
<Editor
style="height: 200px; overflow-y: hidden"
v-model="newMessage"
@keyup.enter="sendMessage"
:defaultConfig="editorConfig"
mode="default"
@onCreated="handleCreated"
/>
</div>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="sendMessage">发送</el-button>
</template>
</el-dialog>
CSS
css
<style scoped>
/* 私信样式 */
/* 标题居中 */
/* .private-message-dialog {
} */
.line {
border-top: 1px solid #ccc; /* 直线的样式,可以修改颜色 */
}
/* 聊天框滚动 */
.chat-container {
display: flex;
flex-direction: column;
height: 300px;
overflow-y: auto;
box-sizing: border-box; /* 让 padding 和 border 包含在宽度和高度内 */
}
.chat-container > * {
width: 100%; /* 确保所有子元素不会超出容器宽度 */
box-sizing: border-box; /* 确保子元素的宽度计算不受 padding 和 border 影响 */
}
/* 消息容器 */
.messages {
display: flex;
flex-direction: column;
gap: 10px;
padding: 10px;
max-height: 250px;
overflow-y: auto;
}
/* 发送方和接收方的消息样式 */
.my-message {
/* text-align: right; */
border-radius: 10px;
height: auto;
/* padding: 5px 10px; */
}
.other-message {
/* text-align: left; */
border-radius: 10px;
/* padding: 5px 10px; */
}
.message-bubble {
/* max-width: 70%; */
padding: 0px 10px;
border-radius: 10px;
/* height: 30px; */
/* margin: 0px 0px 0px 0px; */
/* word-wrap: break-word; */
/* line-height: 1.4; */
font-size: 14px;
display: flex;
align-items: center;
justify-content: center;
}
.message-green {
background-color: #57c457; /* 微信消息绿色 */
color: white;
align-self: flex-end; /* 让气泡靠右显示 */
}
</style>
效果展示
简单测试连接:
报错解决方法
1、vue3 使用SockJS报错 ReferenceError: global is not defined
解:
import SockJS from "sockjs-client";
修改为:
import SockJS from "sockjs-client/dist/sockjs.min.js";
并安装依赖
npm i --save-dev @types/sockjs-client