1. 项目介绍
在本文中,我们将介绍如何使用Vue.js和Spring Boot实现一个支持多人实时协同编辑的Web应用。通过WebSocket技术,我们可以实现文档的实时同步,让多个用户同时编辑同一份文档。
2. 技术栈
- 前端:Vue.js 3 + Vuex
- 后端:Spring Boot 2.x
- WebSocket:Spring WebSocket
- 数据库:MySQL
- 其他:operational transformation (OT)算法
3. 后端实现
3.1 添加WebSocket依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
3.2 WebSocket配置
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(documentWebSocketHandler(), "/ws/document")
.setAllowedOrigins("*");
}
@Bean
public DocumentWebSocketHandler documentWebSocketHandler() {
return new DocumentWebSocketHandler();
}
}
3.3 WebSocket处理器
@Component
public class DocumentWebSocketHandler extends TextWebSocketHandler {
private static final Map<String, Set<WebSocketSession>> documentSessions = new ConcurrentHashMap<>();
@Override
public void handleTextMessage(WebSocketSession session, TextMessage message) {
// 处理收到的消息
DocumentOperation operation = parseOperation(message.getPayload());
broadcastChange(operation);
}
private void broadcastChange(DocumentOperation operation) {
// 广播变更给所有相关会话
Set<WebSocketSession> sessions = documentSessions.get(operation.getDocumentId());
if (sessions != null) {
sessions.forEach(session -> {
try {
session.sendMessage(new TextMessage(JSON.toJSONString(operation)));
} catch (IOException e) {
e.printStackTrace();
}
});
}
}
}
4. 前端实现
4.1 WebSocket连接管理
export default {
state: {
socket: null,
connected: false
},
mutations: {
SET_SOCKET(state, socket) {
state.socket = socket;
},
SET_CONNECTED(state, status) {
state.connected = status;
}
},
actions: {
connectWebSocket({ commit }, documentId) {
const socket = new WebSocket(`ws://localhost:8080/ws/document?documentId=${documentId}`);
socket.onopen = () => {
commit('SET_CONNECTED', true);
};
socket.onmessage = (event) => {
const operation = JSON.parse(event.data);
// 处理收到的操作
this.dispatch('handleDocumentOperation', operation);
};
commit('SET_SOCKET', socket);
}
}
}
4.2 编辑器组件
<template>
<div class="editor">
<textarea
v-model="content"
@input="handleInput"
@keyup="handleKeyup"
></textarea>
</div>
</template>
<script>
export default {
name: 'Editor',
data() {
return {
content: '',
version: 0
}
},
methods: {
handleInput(e) {
const operation = {
type: 'update',
content: e.target.value,
version: this.version++,
documentId: this.$route.params.id
};
this.$store.state.websocket.socket.send(JSON.stringify(operation));
}
}
}
</script>
5. 实现冲突解决
为了处理多人同时编辑可能产生的冲突,我们需要实现操作转换(OT)算法:
export function transformOperation(operation1, operation2) {
// 实现操作转换逻辑
if (operation1.version < operation2.version) {
return transformContent(operation1, operation2);
}
return operation1;
}
function transformContent(baseOp, concurrentOp) {
// 根据两个操作的内容和位置进行转换
// 返回转换后的操作
}
6. 主要功能展示
- 实时同步
- 用户A编辑文档时,变更实时推送给其他用户
- 其他用户可以看到文档的实时更新
- 冲突处理
- 多用户同时编辑时自动处理冲突
- 保证所有用户看到的文档内容一致
- 断线重连
- 检测到连接断开时自动重连
- 重连后同步最新文档内容
7. 性能优化
- 消息节流
import { throttle } from 'lodash';
const sendOperation = throttle((operation) => {
socket.send(JSON.stringify(operation));
}, 100);
- 批量处理
@Scheduled(fixedRate = 100)
public void processPendingOperations() {
List<DocumentOperation> operations = pendingOperations.drain();
if (!operations.isEmpty()) {
broadcastChanges(operations);
}
}
8. 总结
通过Vue.js和Spring Boot的结合,我们实现了一个基础的协同编辑功能。关键点包括:
- WebSocket实现实时通信
- OT算法处理并发冲突
- 状态同步和断线重连
- 性能优化
要构建一个生产级别的协同编辑系统,还需要考虑:
- 权限控制
- 历史记录
- 离线支持
- 更复杂的冲突解决策略