拿到“基于SpringBoot文档协作系统”这个题目时,很多人第一反应是:这不就是一个带用户管理的CRUD系统吗?等真正动手才发现,文档协作和普通的增删改查完全是两个世界——多用户同时操作同一篇文档时的权限边界、保存版本时的快照策略、多人协同编辑的数据一致性问题,还有部署上线时前后端纠缠不清的关系。任何一环没设计好,后面全是返工。
这篇文章是我从需求分析、模块设计、核心实现、论文PPT准备到服务器部署的完整复盘,目标读者是正在做同类毕设或真实项目的同学。我会把关键的技术决策、踩过的坑、答辩演示时容易被追问的细节都摊开讲。你看完应该能少走很多弯路。
1. 文档协作系统的需求拆解与技术选型逻辑
1.1 从题目要求倒推核心模块
先别急着写代码,第一步一定是把“文档协作”四个字拆开。我当时的思路是:协作的前提是文档存在,文档的前提是用户存在,所以整个系统至少要包含三层。
第一层是用户与权限层。注册登录是标配,但协作系统里光有登录不够,你还得想清楚:A 用户创建的文档,B 用户能不能看?能不能改?能不能分享给第三方?这就是典型的权限管理问题。我当时直接采用了 RBAC(基于角色的访问控制)模型,把用户、角色、权限分成三张表,再用中间表关联起来。刚开始觉得有点麻烦,但后来发现文档的分享操作、管理员的用户管理操作、不同角色的菜单展示,全都依赖这套模型,前期多花的两个小时非常值得。
第二层是文档管理层。文档要有分类、有列表、有编辑器、有保存逻辑。这里最容易被低估的是“版本管理”。很多人做到文档能增删改查就以为完事了,但协作系统的核心恰恰是“改错了能回去”。所以我在设计表的时候直接预留了文档版本表,每次保存正文都生成一条快照。这个设计在答辩时是个加分项,因为评委一听就知道你考虑了真实场景中的数据回溯问题。
第三层是协作层。多人编辑、评论、@通知、最近编辑人列表,这些都属于协作层的功能。我当时的取舍是:先实现评论和“正在编辑”状态提示,因为这个用 WebSocket 最自然。多人实时同时修改同一段落(类似腾讯文档那种 OT 算法实时同步)在毕设阶段不建议做,时间成本太高,而且答辩时很难说清楚算法细节。做个“保存时冲突检测”就够了——两个人都改了同一篇文档,后保存的人会看到提示并可选基于最新版本再改,这在工程上是可接受的方案。
1.2 技术栈取舍:为什么 SpringBoot 是合理答案
做毕设或中小型项目,技术选型的第一原则不是“最炫”,而是“最小闭环”。SpringBoot 在这个场景下的优势非常明显:
- 开发效率高:不需要像 SSM 那样手动配置一堆 XML,一个
@SpringBootApplication就能跑起来,能把精力集中在业务逻辑上。 - 生态完善:配合 Spring Security、MyBatis-Plus、Redis、WebSocket 这些常用组件都有现成 starter,集成成本极低。
- 部署简单:打包成可执行 jar 就能直接运行。配合前端打包进 SpringBoot 的静态资源目录,连独立部署前端服务器的步骤都省了。
- 答辩话题多:SpringBoot 本身就是高频关键词,自动配置原理、starter 机制、内嵌 Tomcat 原理都能延伸出很多答辩问题。
前端我建议用 Vue 3 + Element Plus。不推荐纯 JSP 或者 Thymeleaf 服务端渲染,原因是文档编辑器和权限控制这些交互逻辑用前后端分离做起来更清晰,而且 Vue 打包后放进 SpringBoot 的resources/static目录就能一起部署,不会增加额外的运维负担。如果你只做后端,那也要至少写一个能调通的简单前端页面,否则答辩演示时会很尴尬。
1.3 单体架构的边界:什么阶段不要碰微服务
看到 SpringBoot 的第一反应可能是“要不要用微服务?”。我的建议是:文档协作系统这个规模,单体架构就是最优解。微服务增加的是通信成本、分布式事务成本、部署成本,而这些在毕设阶段只会拖慢你的进度。我见过有同学硬搞了三个微服务模块,结果答辩时自己都解释不清服务间调用失败的问题,这是典型的过度设计。
甚至数据库连接池、Redis 缓存这些,初期也可以后置。我初期连 Redis 都没用,后来为了性能优化加了一个缓存用户登录状态的简单场景,效果立竿见影。记住一个原则,技术永远跟着真实业务痛点走,而不是为了用而用。
2. 数据库设计与权限模型:多用户协作的基石
2.1 表结构设计:直接照着抄都不会出错的版本
数据库设计我建议先画 ER 图再写表。不要一上来就写 SQL,先用纸笔理清实体之间的关系。我当时最终落地的表结构如下,你完全可以参考:
| 表名 | 关键字段 | 作用 |
|---|---|---|
user | id, username, password, nickname, email, status | 用户基础信息,密码用 BCrypt 加密 |
role | id, role_name, role_code | 角色定义,如 ADMIN、USER |
user_role | id, user_id, role_id | 用户角色关联 |
category | id, user_id, name, parent_id, sort | 文档分类,树形结构 |
document | id, title, content, type, category_id, owner_id, status | 文档主表,content 存 LONGTEXT |
doc_share | id, doc_id, user_id, permission_type | 文档分享权限记录,如只读/可编辑 |
doc_version | id, doc_id, version_no, content, operator_id, create_time | 文档版本快照 |
doc_comment | id, doc_id, user_id, content, parent_id, create_time | 评论,支持楼中楼 |
notification | id, user_id, from_user_id, doc_id, type, is_read | 系统通知,如@提醒、分享提醒 |
有几个细节我想单独解释一下:
document.content存 LONGTEXT,不要把文档内容存成文件路径。毕设阶段没有必要上 MinIO 或 FastDFS,数据库里存文本速度快、备份方便、实现简单。图片附件可以上传到本地目录,然后在正文里用/upload/xxx.jpg引用。doc_version为什么单独建表:因为版本号要随每次保存递增,而且回滚时需要拿到某一版本的历史内容。如果你只删旧插新,就丢失了历史。- 评论和通知分开建表。评论是业务数据,通知是消息数据,两者生命周期不同。评论删除后通知可以保留,混在一张表里会出很多逻辑 bug。
2.2 权限模型:从登录到操作鉴权的完整链路
权限模型我用了经典的 RBAC 加上文档级权限控制,两层叠加。
RBAC 层处理的是“你能进哪个页面、能用哪些功能”,比如管理员能看用户管理菜单,普通用户不能。实现方式是 Spring Security + JWT,登录成功后返回 token,前端每次请求带上,后端用拦截器解析 token 判断用户身份。角色菜单放在数据库里,前端根据当前用户的角色动态生成菜单。
文档级权限层处理的是“你能对这篇文档做什么”。我把操作权限分成了四类:
OWNER(创建者本人):可查看、可编辑、可删除、可分享、可设置权限EDITOR(被分享且允许编辑):可查看、可编辑、但不可删除VIEWER(分享为只读):仅可查看- 无权限:不可见
实现时我用了 AOP + 自定义注解的方式。先定义@DocAuth(action = "edit")注解,然后写一个切面,在方法执行前根据请求参数里的 docId 去查询当前用户对该文档的权限。如果权限不足,直接抛异常,由全局异常处理器统一返回 JSON 提示。这样做的好处是业务代码里不用反复写权限判断逻辑,一个注解就搞定。
这里有同学会问:为什么不直接用拦截器统一处理?因为拦截器拿不到方法参数里的 docId,它只能处理 URL 和 Header 层面的校验。想要方法级别的精细控制,必须用 AOP。这两个东西的分工是:拦截器管“你是谁”,AOP 管“你能干什么”。
2.3 分享链接与取消分享的隐藏逻辑
分享功能的设计有个容易踩坑的地方:分享是一种动态关系。用户 A 给用户 B 分享了文档 D 的编辑权限,那么 B 打开文档时需要先确认这个分享关系还在不在。如果 A 取消了分享,B 是否还能看到文档?
我当时的做法是:用户 B 的“分享给我”列表,查询时关联doc_share表,permission_type大于 0 的记录才展示。当取消分享时直接删除对应记录,前端的文档列表刷新后就会消失。这个逻辑很简单,但容易被忽略的是“缓存”问题——如果你给分享列表加了 Redis 缓存,取消分享后必须同步删除缓存,否则权限已经变了,列表还是旧的。我在测试时就遇到过取消分享后对方列表里依然能看到文档的 bug,排查半天发现是缓存没清干净。
3. 文档编辑、版本快照与协同冲突处理
3.1 编辑器选型:富文本和 Markdown 的取舍
文档正文的输入方式我建议二选一:富文本编辑器或者 Markdown 编辑器。我当时选的是富文本,用的是一个开源的轻量级编辑器,支持图片上传、表格、代码块。如果你平时习惯写 Markdown,也可以选带实时预览的 Markdown 编辑器。
无论选哪个,核心点在于编辑器内部的数据结构与存储格式的统一。富文本编辑器输出的是 HTML 文本,里面可能有样式标签、图片 base64 数据、表格结构。Base64 图片会导致文档体积膨胀得很厉害,我踩过这个坑:粘贴一张 2MB 截图,正文立刻变成 3MB 字符串,接口响应慢到怀疑人生。
解决办法是:编辑器在上传图片前先把图片截出来,走后端的上传接口存到服务器静态目录,然后在正文里替换成 URL。这样数据库里存的永远是干净的 HTML,图片只是引用链接。这一步一定要在数据进库前跑完,而不是存完正文再异步替换,否则并发操作时容易出问题。
3.2 版本快照与回滚的实现:一个最关键的技术决策
版本控制的实现我前后改过两版。第一版是每次保存都记录完整快照,结果数据量涨得很快,而且对比时很费劲。第二版我只记录“每次保存时的完整内容”作为快照,但增加了版本号字段。每次保存时版本号加一,同时把最新内容写入doc_version表。
回滚的逻辑很简单:找到目标版本号的记录,把正文内容复制回去,覆盖当前文档的 content,同时生成一个新的回滚版本并标记版本号继续递增。注意,回滚不是“回到过去”,而是“把过去的内容作为新版本保存下来”。这个细节在论文测试用例和答辩中都可以拿出来讲,说明你理解的是“操作可追溯”,而不是简单的覆盖。
版本对比这个功能,我做了两版:纯文本对比和逐字 diff。纯文本对比只能看出“第几版改过哪些字”,而逐字 diff 需要引入官方的 diff-match-patch 算法库。建议你用现成的 diff 库生成增删差异,展示效果很好,答辩时可以直接演示两个版本之间的差异高亮,是一个不错的亮点。
3.3 并发编辑冲突:从“静默覆盖”到“保存冲突提示”
多人协作最核心的问题就是冲突。真实场景是:我和同事同时打开同一篇文档,我改了第一段,他改了第二段,然后我们都点了保存。
如果系统是“后保存者覆盖”,那么先保存的人改的内容就丢失了,这是最糟糕的体验。我的处理方案分两步:
- 保存时带上版本号。前端在保存请求中提交当前文档的 version。后端收到后先查一下数据库里的最新版本。如果前端提交的 version 小于最新版本,说明文档已经被其他人改过了。
- 返回冲突提示。此时后端不直接覆盖保存,而是返回
DOC_MODIFIED之类的状态码,前端弹窗提示“文档已有人更新过,请基于最新版本重新编辑”。用户可以点击“查看最新内容”,然后把修改内容手动合并进去。
我没有做自动合并,因为这个逻辑非常复杂:同一段文字两个人改了不同位置,怎么合并?虽然业界有 OT 算法和 CRDT 算法可以解决,但实现成本高、边界情况多,毕设阶段不建议碰。但你要能在论文里说清楚这个取舍——你知道业界方案是什么,也知道为什么当前系统选择了更稳妥的提示式合并。这种“认知边界”的展示,在答辩时非常加分。
3.4 “正在编辑”状态提示:WebSocket 的轻量引入
为了体现“协作感”,我加了一个功能:打开文档时,如果当前有其他人也在编辑这篇文档,右侧栏会显示他们的头像和昵称。
实现方案是 WebSocket。在用户打开编辑页面时建立连接,通过消息类型区分与会话:进入文档、正在输入、离开文档。版本号固定在SOCKET_ENTER_DOC、SOCKET_EXIT_DOC、SOCKET_EDITING三种。后端收到SOCKET_EDITING就广播给当前文档的所有连接用户。前端收到后更新“正在编辑”列表。
这里有个细节:用户离开页面时应主动发送SOCKET_EXIT_DOC,同时在前端的beforeunload事件里兜底,防止用户直接关掉标签页导致后端以为他还在编辑。后端还需要定期清理超过 30 秒没有心跳的连接。这些细节不写出来,你就只能在测试时发现“人走了头像还在”的尴尬问题。
4. 从写代码到写论文、做 PPT:一套可以通用的方法
4.1 论文结构:不是流水账,而是围绕工程闭环展开
标题里带了“lw+ppt”,说明这是一套完整交付。我见过太多人代码写完了,论文和 PPT 却憋不出来。核心原因在于:论文不是代码的翻译,而是工程问题的解决过程记录。
我当时论文的章节是这样组织的:
- 摘要:写清楚“本文构建了一个基于 SpringBoot 的文档协作系统,解决了多用户文档集中管理与共享编辑问题,核心功能包括……”
- 绪论:行业背景和同类系统对比。这里不要写空话,直接说当前中小型团队缺乏轻量级协作工具,自己这个系统定位就是低成本、快部署。
- 相关技术介绍:只写系统里真正用到而且能讲清楚的技术。比如 Spring Boot 核心特性、Vue 前端框架、JWT 认证机制、WebSocket 通信协议。不要写大模型、微服务这些你没用到的。
- 需求分析:用用例图 + 用例表,列出每个角色能做什么操作。
- 系统设计:重点画架构图、ER 图,讲清楚模块划分和数据表设计。这里建议每一张表都配一段设计说明,强调关键字段的用途。
- 系统实现:按模块展示核心代码和界面截图。代码不要贴大段业务代码,贴核心算法的关键片段并附图说明。
- 系统测试:写功能测试用例表,覆盖正常流程、异常流程、边界值。例如重复用户名注册、删除已被分享的文档、版本回滚后的权限变化等。
- 总结:写当前系统的不足和未来优化方向。这里可以说“当前版本未实现实时多人协同编辑,后续可以引入 OT 算法”之类。
4.2 PPT 的逻辑线:别按论文顺序讲,按故事线讲
答辩 PPT 切忌把论文目录念一遍。正确的逻辑线是:
- 痛点:团队内部文档分散在个人电脑 / 微信中,版本混乱,无法协作。
- 思路:做一个基于浏览器的文档协作系统,集中存储、支持权限分享和版本回溯。
- 技术选型:为什么选 SpringBoot?为什么选 Vue?各有什么优势。
- 核心功能演示:创建文档 → 分享给同事 → 对方编辑 → 产生版本 → 回滚。这是全场最关键的两到三分钟,声音要稳,操作要慢,提前把数据准备好。
- 方案取舍:当前做了什么,为什么没做什么。比如“考虑到 OT 算法复杂度与时间成本,当前采用冲突提示而非自动合并,未来将作为优化方向”。
- 测试结果:用表格展示功能测试通过率、并发保存场景的处理结果。
我个人的经验是:PPT 上文字越少越好,放一张抓眼球的架构图,配上三个关键词,然后全部用口头讲解。评委更喜欢看到你能脱稿、能举例子、能回答追问的状态。
4.3 答辩追问与回答准备
答辩时评委最容易追问的方向,一定要提前准备:
- 为什么用 JWT 而不用 Session?JWT 的 token 过期了怎么处理?主动退出时 token 失效是怎么实现的?
- 为什么采用乐观锁而不是悲观锁?并发场景下你怎么保证数据一致?
- 版本表的数据量增长很快,如何优化?能不能加索引或分表?
- 如果用户 A 取消了对 B 的分享,B 已经打开的编辑页面还能继续保存吗?你的后端有没有二次校验?
答这些问题的核心思路是:先讲当前方案做了什么,再讲边界,再讲改进空间。不要硬撑着说没有漏洞,诚恳地说并补充改进方案,比强辩更得分。
5. 从本地到服务器:部署讲解全流程
5.1 部署架构与前端打包策略
部署这一块,我推荐一套最省心、答辩也讲得清楚的方案:前端 Vue 打包进 SpringBoot,后端 jar + MySQL + Redis 跑在 Linux 服务器上,用 Nginx 做反向代理统一入口。
具体流程是:
- 前端执行
npm run build,生成dist目录。 - 把
dist目录里的内容复制到后端项目的src/main/resources/static目录。 - 后端执行
mvn clean package -DskipTests,打包得到doc-collab-0.0.1-SNAPSHOT.jar。
启动时用java -jar运行即可。访问http://服务器IP:8080就能直接看到前端页面,而前端页面的接口请求会走到/api开头的路径,由后端自己的 Controller 处理。这就是“前后端一体化部署”的方案,好处是不用维护两个服务,坏处是前端每次更新都要重新打包 jar。对于毕设和中小型项目,这个坏处完全可接受。
5.2 Linux 服务器环境准备清单
如果是在云服务器上部署,我用的是 CentOS 7,环境准备建议按照这个清单来:
| 组件 | 安装方式 | 关键点 |
|---|---|---|
| JDK 8 或 JDK 17 | yum install或手动解压 | 设置 JAVA_HOME 环境变量 |
| MySQL 5.7/8.0 | yum仓库安装 | 初始化 root 密码,创建数据库并设置 utf8mb4 |
| Redis 6.x | make && make install或直接用包管理器 | 在配置里绑定本地地址关闭外网访问 |
| Nginx 1.20+ | 包管理器安装 | 配置反向代理和静态资源缓存 |
数据库初始化时要注意字符集统一。前端页面中文乱码问题,十有八九是数据库库表字符集不是utf8mb4导致的。建库语句建议写成:
CREATE DATABASE doc_collab DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;然后通过application.yml里指定连接参数:
spring: datasource: url: jdbc:mysql://localhost:3306/doc_collab?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai username: root password: yourpassword5.3 部署步骤讲清楚:启动、验证与日志排查
我在部署时的操作步骤,你可以直接照着执行:
- 上传 jar 包到服务器:使用
scp或直接在终端工具里上传到/opt/doc-collab/目录。 - 启动服务:
nohup java -jar doc-collab-0.0.1-SNAPSHOT.jar > logs/app.log 2>&1 &- 查看日志确认启动成功:
tail -f /opt/doc-collab/logs/app.log看到Started Application in X.XX seconds就说明启动正常。我还看到过“端口被占用”的报错:
netstat -tlnp | grep 8080 # 或者 lsof -i:8080找到 PID 后用kill -9 PID清理,再重新启动。
- 验证接口是否通:在浏览器访问
http://你的服务器IP:8080/api/ping,如果配置了全局返回工具类,应该能看到{"code":200, ...}之类的 JSON 响应。接口通说明后端没问题,前端静态资源也正常加载。如果首页能打开但接口 404,多半是请求路径里的 context-path 不一致,检查server.servlet.context-path配置。
5.4 用 Nginx 处理端口与静态资源的几个细节
虽然一体化部署后 8080 端口直接可访问,但我还是配了 Nginx。理由很简单:大学生云服务器的 80 端口通常是默认开放,而 8080 不一定放行,而且 8080 直接被公网裸奔不够规范。
Nginx 配置建议这样写:
server { listen 80; server_name your_domain_or_ip; location / { proxy_pass http://127.0.0.1:8080; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }如果你把前端 dist 直接放进了 SpringBoot 静态目录,那上面的配置就够了,Nginx 纯做反向代理。如果你选择前端独立部署到 Nginx 的html目录,那需要把请求/api/单独转发到后端,其余静态资源直接读取本地文件。前端独立部署的好处是改前端不用重新打包 jar,坏处是跨域问题需要额外处理。如果你要走这条路,SpringBoot 里需要加跨域配置:
@Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/api/**") .allowedOrigins("http://your-frontend-domain") .allowedMethods("GET", "POST", "PUT", "DELETE"); } }5.5 部署时最容易踩的四个坑
部署阶段我记录了自己踩过的坑,每个都是真实发生的:
第一个坑:MySQL 密码策略过于严格。如果 MySQL 是 8.0,默认密码校验插件是caching_sha2_password,我用的旧版本驱动连不上。一定要把驱动版本升级到8.0.33及以上,并在 JDBC 连接串里加上allowPublicKeyRetrieval=true&useSSL=false。
第二个坑:Redis 没设密码导致连接超时。如果你的系统里用了 Redis 缓存登录 token,部署到云服务器后必须给 Redis 设置密码并只绑定本地访问。我当时忘了改配置文件,服务器被扫描工具刷了几万条未授权访问日志,被迫清理重装。这种教训很惨痛,你应该引以为戒。
第三个坑:前端打包时把 HTTP 请求地址写死了。用了axios的baseURL写成了http://localhost:8080/api,部署到服务器后所有请求全部指向本地,白白排查了一整晚。正确做法是在前端项目创建.env.production和.env.development文件,分别配置各自环境的后端地址,打包时自动切换。
第四个坑:部署后上传的图片刷新后丢失。本地开发时图片传到resources/static/upload没问题,但 jar 包启动后这个目录在临时路径里,重启就没了。正确做法是在application.yml里配置一个绝对路径的上传目录,例如/opt/doc-collab/upload,并通过 WebMvc 配置映射为/upload/**静态访问路径。不然每次重启服务,用户头像和文档插图全丢,你会在演示当天崩溃。
6. 实际开发中踩过的坑与优化建议
6.1 那些没写在需求文档里的坑
开发过程中最让我抓狂的问题来自编辑器粘贴图片。富文本编辑器把剪贴板里的图片自动转成 base64,导致每个文档动辄几 MB。我后来在前端加了一步:监听粘贴事件,检测到图片文件就调用后台上传接口,等返回 URL 后再插入编辑器。这样数据库里存的是 URL,上传的图片走本地磁盘,文档体积控制在合理范围内。
另一个坑是关于 XSS 攻击的。富文本编辑器如果直接保存 HTML,用户完全可以在内容里写一段<script>标签,然后分享给其他人,其他人的浏览器里就会执行这段脚本。这是经典的存储型 XSS。虽然毕设阶段不要求做安全加固,但答辩时会问到。我的处理办法是使用后台清理组件,把<script>标签和onclick、onerror这类事件属性剥离掉,保留正常的排版标签。如果你不知道怎么实现,直接搜“HTML 白名单过滤器”,有很多现成方案可以参考。
6.2 性能优化:按“发生了问题再处理”的原则来
我系统里的性能优化只做了三件事,每件事都是被真实问题逼出来的:
- 用户列表和文档列表加 Redis 缓存:文档列表每次打开页面都查库,数据量大了以后响应速度明显变慢。加入缓存后,列表接口快了一倍。但要注意更新文档后必须同步删除缓存,否则出现“刚保存内容不显示”的诡异现象。
- 登录 token 放 Redis 并设置过期时间:用了
@PreAuthorize注解后,每次请求都要解析 token。把 token 的校验和 Redis 绑定,可以让“修改密码后旧 token 立刻失效”这个功能变得非常简单。从安全角度讲,也解决了我上面提到的“用户已退出登录,token 依然有效”问题。 - 数据库大字段延迟加载:
document表的content字段体积很大,如果每次列表查询都把正文加载出来,接口会明显变慢。MyBatis 支持字段级 lazy loading,把 content 设置成懒加载,列表页面只查标题和元数据,只有进入详情页才查正文。这在我文档数量过千后效果极其明显。
6.3 测试用例设计:别只会“点一点看看能不能跑”
写论文的测试章节是要有表有数据的。我当时设计了以下测试方向,你可以照着补充:
- 功能测试用例表:注册重名、密码错误、越权访问他人文档、取消分享后访问、版本回滚后内容正确性。
- 并发测试:用一个模拟脚本同时向同一文档提交不同版本号的保存请求,验证冲突提示是否触发。
- 性能试测:用 Jmeter 对文档列表接口做 100 个线程的并发请求,看响应时间是否在可接受范围内。
- 兼容性测试:Chrome、Edge、手机端浏览器都能正常打开页面并编辑文档。
这些测试不复杂,但能证明你有完整的测试思维,评委很看重这个。
6.4 扩展方向与后续优化思路
虽然当前系统功能能跑通,但有几块地方我很清楚是短板,如实记录下来对你有参考价值:
- 当前未实现 WebSocket 的断线重连与消息持久化。掉线重连后,之前广播的“正在编辑”状态会丢失,需要重新推送一次用户列表。
- 评论没有做富文本支持,纯文本在长文案展示时比较单调。
- 版本内容没有做压缩存储。长期使用后
doc_version表的数据量会增长很快,可以考虑引入数据压缩或只保存差异版本(增量快照),不过这会增加回滚时的计算复杂度。 - 文档回收站目前只能恢复一级,深层目录文件恢复时还没做完整测试。
这些内容写进论文的“总结与展望”章节,评委会认为你真的在认真反思,而不是抄模板。
7. 写在最后:关于这套项目,我的真实体会
整套项目做下来,回过头看,真正让系统立住的反而不是某个炫酷的技术点,而是几个朴素的工程决策:权限模型前面想清楚了,后面所有接口都顺;版本表从第一天就设计了,才有了后面回滚功能的从容;部署时把前端打包进 jar 一体运行,才让我在答辩现场能从零开始演示,不停机不报错。
如果你正在做类似的题目,我给你一个最实用的建议:先花一晚上把 ER 图画完,再开始写代码。这个晚上省下来的时间,至少是三天起。表设计错了,勉强写了代码也是漏洞百出,最后改来改去还不如重来。
还有一个小技巧,答辩演示前,一定准备两套环境。一套被你反复摸过、数据零散但展示点清晰的测试环境,一套刚完成部署、从注册用户开始的完整演示环境。前者用来应对流畅的讲解,后者用来应对评委要求“现场新用户走一遍完整流程”。
先做到这些,再谈后面的多人在线实时协同、OT 算法这些进阶方向。项目是一步一个脚印做出来的,论文和答辩也自然水到渠成。