如果你所在的团队做的是一套基于SpringBoot的后台管理系统那么“在线预览Word、Excel、PPT”这类需求大概率会出现在需求文档里。我今年在项目中实际落地过一套SpringBoot集成ONLYOFFICE的方案前端通过iframe嵌入ONLYOFFICE文档编辑器后端SpringBoot负责文件上传下载、生成配置、接收保存回调文档数据完全自托管社区版免费使用。这篇文章就是基于这次实操整理的完整教程内容覆盖方案选型、Docker部署Document Server、SpringBoot后端集成、强制保存、以及我踩过的各种安装和回调相关的坑适合正在选型在线文档方案、或者已经在ONLYOFFICE集成路上卡住的Java开发同学。我先把结论放在前面ONLYOFFICE这套方案最舒服的地方在于它把“文件编辑能力”完全独立成了Document Server服务SpringBoot只需要管好文件存储、权限、回调这三个事。只要理解清楚浏览器、Document Server、业务服务三者之间的请求链路整个集成的复杂度其实不高。1. 方案选型与整体设计思路1.1 为什么选ONLYOFFICE而不是其他方案在线文档这个领域方案其实不少但我实际对比过后发现各有各的坑。微软Office Online微软家的东西功能很完整但它的私有协议和授权方式对自托管极不友好。你要接入尤其是企业内部使用流程复杂费用也不低。我见过有团队用SharePoint做底层最后维护成本远超收益。Google Docs/Sheet协同体验确实好但是国内访问本身就不稳定数据在别人服务器上企业内部项目很难接受。LibreOffice unoconv这方案只能实现“预览”把文档转成PDF或图片展示完全没法在线编辑。另外转换质量不稳定遇到复杂排版经常乱掉光照文件多了还容易把服务器CPU打满。Collabora Online也可以自托管支持协同编辑但配置复杂中文资料少遇到问题不容易排查。ONLYOFFICE Document Server开源社区版免费自托管提供完整的API和JS SDK界面接近传统Office文档兼容性在同类开源方案里算不错的。部署方式也友好官方Docker镜像一条命令能拉起来。对于SpringBoot项目来说ONLYOFFICE最大的优势是它把“文档处理”独立成了一个可通过HTTP访问的服务后端Java代码只需做配置生成、文件存取、回调处理不需要在业务进程里嵌入任何Office相关的底层库。1.2 集成架构拆解与请求链路很多人在集成ONLYOFFICE时卡壳本质上是没把请求链路捋清楚。整个系统里一共有三端浏览器用户打开你的页面页面引入Document Server的JS SDK创建一个编辑器实例。编辑器实际运行在Document Server上浏览器只是用iframe把编辑界面嵌在你自己的页面里。SpringBoot业务服务负责提供文件列表、文件下载接口、编辑器初始配置、接收Document Server的回调所有业务权限和文件存储都在这一层。Document Server负责文档的解析、渲染、编辑、协同、转换。它本身不存业务文件而是根据config参数去你的业务服务下载文件编辑完成后又通过回调把最新文件推给你。一次正常编辑流程是这样的用户在浏览器里点开一个文档。SpringBoot根据文档ID查数据库生成一份ONLYOFFICE需要使用的config JSON里面包含文件下载地址、回调地址、用户信息等。浏览器拿到config后加载Document Server的api.js在iframe里创建DocsAPI.DocEditor实例。Document Server根据config里的document.url去你的SpringBoot服务下载原始文件。用户在编辑器里做修改Document Server会把修改后的文件内容存到它的临时缓存。用户关闭文档或者点了强制保存Document Server向业务服务发送回调请求。SpringBoot接收到回调后按回调里的url下载最新文件存回自己的存储更新数据库版本号。这里最关键也最容易出问题的是“三端之间的网络可达性”。浏览器要能访问Document Server和你的业务服务SpringBoot要能访问Document Server因为强制保存等操作需要调命令接口Document Server要能访问SpringBoot服务因为它要下载原文件、发起回调。这三条链路的地址配置错了项目就跑不通。我自己在后续章节里会专门讲这些地址应该怎么配才能避免踩坑。2. 环境准备Document Server部署与初始化2.1 Docker方式部署Document ServerDocument Server的部署推荐Docker方式简单、隔离、升级和回滚都很方便。官方镜像名是onlyoffice/documentserver节点资源建议至少2核4G内存低于这个配置启动会很慢多人同时编辑时还会卡。部署命令如下docker run -d \ --name onlyoffice-docserver \ -p 8088:80 \ --restartalways \ -e JWT_ENABLEDtrue \ -e JWT_SECRETyour-very-long-random-secret \ onlyoffice/documentserver:latest参数说明-p 8088:80把容器内部的80端口映射到宿主机的8088端口。如果宿主机80端口空闲可以直接-p 80:80看你的环境怎么方便。-e JWT_ENABLEDtrue开启JWT签名防止别人伪造请求。生产环境必须开除非你只在内网跑且没有安全意识。-e JWT_SECRET...JWT密钥ONLYOFFICE和SpringBoot两端必须保持一致。密钥建议用足够长的随机字符串至少32位以上。容器启动后可以用docker ps确认状态。如果状态不健康先别急着调代码马上看容器日志排查docker logs -f onlyoffice-docserverDocument Server内部还依赖PostgreSQL、RabbitMQ、Redis等组件好消息是这些在官方镜像里都已经配好了不需要你单独部署。只要容器能稳定运行说明内部服务基本正常。2.2 部署验证与JWT密钥确认部署完成后的验证方式很简单浏览器访问http://你的服务器IP:8088/welcome/能看到欢迎页面说明Document Server已经起来了。注意ONLYOFFICE近几个版本欢迎页面做成了后台管理风格的界面不再是一张纯白底文字说明页看到登录弹窗或仪表盘都算正常。接下来要做两件事确认JWT配置、确认服务地址。第一JWT密钥确认。如果你在docker run时通过JWT_SECRET设置了密钥那SpringBoot端直接使用同一个字符串即可。如果忘记设置或者想从容器里反查可以执行docker exec onlyoffice-docserver cat /etc/onlyoffice/documentserver/local.json这个文件里能找到jwt相关配置和secret字段。后面SpringBoot生成签名、验证回调时用的就是它。第二服务地址规划。需要在部署前规划好浏览器、SpringBoot、Document Server互相访问的地址。最简单的做法给Document Server配置一个内网域名或直接使用宿主机IP加端口保证三端都能访问。这里特别提醒一句千万别在config里把Document Server地址写成localhost或127.0.0.1因为请求最终是从用户的浏览器发出的浏览器如果和服务器不在同一台机器这个地址就是无效的。2.3 一个关于字体的经典部署坑网络热词里有“onlyoffice依赖关系不满足fonts-dejavu”说明很多人在安装过程中被字体依赖问题折磨过。这个报错主要出现在用deb包或源码方式安装Document Server的场景因为ONLYOFFICE的文档转换和PDF预览依赖系统中的字体文件其中fonts-dejavu是必需的基础字体包。docker镜像已经把字体集成好了所以遇到这个问题的朋友大概率是用非Docker方式装的。解决方案是手动把字体依赖装齐apt-get update apt-get install -y fonts-dejavu-core fonts-dejavu-extra fontconfig装完后重新启动Document Server服务。这个问题我建议直接绕开既然能用Docker就尽量用Docker省去一堆系统依赖的麻烦。3. SpringBoot后端集成核心实现3.1 项目依赖与基础配置SpringBoot端我用了最常规的spring-boot-starter-web加上JWT生成与校验的jjwt库以及发HTTP请求用的httpclient5。如果你的项目里已经有HTTP工具类也可以用OkHttp或者RestTemplate替代原理都一样。pom.xml中核心依赖如下dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-api/artifactId version0.11.5/version /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-impl/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdio.jsonwebtoken/groupId artifactIdjjwt-jackson/artifactId version0.11.5/version scoperuntime/scope /dependency dependency groupIdorg.apache.httpcomponents.client5/groupId artifactIdhttpclient5/artifactId version5.3.1/version /dependency然后在application.yml里集中管理ONLYOFFICE相关的配置onlyoffice: # Document Server 对外访问地址浏览器需要能访问 document-server-url: http://192.168.1.100:8088 # SpringBoot 自身的访问地址Document Server 需要能访问 callback-url: http://192.168.1.100:8080/onlyoffice/callback # JWT 密钥与 Document Server 保持一致 jwt-secret: your-very-long-random-secret这两个URL是整个集成里最容易被配错的地方。document-server-url是给浏览器用的callback-url是给Document Server用的。如果你只是在本地开发都填localhost没问题一旦部署到服务器就必须填对方真正能访问到的地址。实际项目里我们通常还会把这两个地址独立成环境变量测试环境、生产环境各配一套避免代码里写死。3.2 文件下载接口与资源映射ONLYOFFICE要求config里的document.url必须是Document Server能下载到的文件地址。所以SpringBoot这边要提供一个文件下载接口把业务文件以二进制流输出给Document Server。注意这个接口和普通的浏览器下载有些区别关键点有两个一是必须能被Document Server访问到而不是只对用户可见二是要正确设置Content-Type否则Document Server可能识别不了文件类型。我的实现方式是做一个简单控制器RestController RequestMapping(/api/file) public class FileController { GetMapping(/download/{fileId}) public ResponseEntitybyte[] download(PathVariable Long fileId) throws IOException { // 从本地磁盘、数据库或OSS读取文件字节 byte[] data fileService.loadFileBytes(fileId); String fileName fileService.getFileName(fileId); String contentType FileTypeDetector.getContentType(fileName); return ResponseEntity.ok() .header(HttpHeaders.CONTENT_DISPOSITION, attachment; filename\ URLEncoder.encode(fileName, UTF-8) \) .contentType(MediaType.parseMediaType(contentType)) .body(data); } }如果你是直接把文件放在服务器某个目录下还可以用SpringBoot的资源映射功能减少一个接口的开发量Configuration public class WebConfig implements WebMvcConfigurer { Override public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler(/files/**) .addResourceLocations(file:/data/onlyoffice-files/); } }这样/files/文件名就能直接映射到服务器磁盘目录。但需要注意ONLYOFFICE的document.url是一个完整的URL例如http://192.168.1.100:8080/files/abc.docx而不是相对于Document Server的路径。因为Document Server下载文件时会把整个URL当作地址来请求如果你漏掉域名和端口它就会去自己服务器上找这个路径结果必然404。3.3 生成文档编辑config这是整个集成里最核心的部分。ONLYOFFICE文档编辑器要运行必须拿到一个config对象里面告诉它从哪里下载文件、保存时回调到哪个地址、允许哪些操作等。SpringBoot根据请求参数动态生成这个config返回给前端页面。我项目中生成config的核心方法大致如下public MapString, Object buildConfig(String userId, String userName, FileInfo file) { MapString, Object config new HashMap(); // document 部分告诉 Document Server 下载哪个文件 MapString, Object document new HashMap(); document.put(fileType, file.getFileType()); // docx/xlsx/pptx 等 document.put(key, file.getFileKey()); // 文件版本标识内容变化后必须更新 document.put(title, file.getFileName()); document.put(url, file.getDownloadUrl()); // SpringBoot 提供的下载地址 // documentTypeword / cell / slide config.put(document, document); config.put(documentType, word); // editorConfig回调、语言、模式等 MapString, Object editorConfig new HashMap(); editorConfig.put(callbackUrl, onlyOfficeProperties.getCallbackUrl()); editorConfig.put(lang, zh-CN); editorConfig.put(mode, edit); MapString, Object customization new HashMap(); customization.put(autosave, true); customization.put(forcesave, true); editorConfig.put(customization, customization); MapString, Object user new HashMap(); user.put(id, userId); user.put(name, userName); editorConfig.put(user, user); config.put(editorConfig, editorConfig); // 生成 JWT 签名 config.put(token, JwtUtils.sign(config, onlyOfficeProperties.getJwtSecret())); return config; }几个关键字段必须理解清楚。document.key是ONLYOFFICE识别文档版本的标识。同一个key对应同一份文档内容如果文件内容发生了变化key必须跟着变化否则Document Server会使用缓存的老文件导致你看到的还是旧数据。我习惯用fileId 最后修改时间戳来拼key比如file-123-1700000000。这样能保证文件每次修改后key都不同同时避免无意义的频繁变更。document.url服务地址必须保证Document Server能访问。如果你和Document Server之间有防火墙或者使用了Docker网络隔离一定要确认这个地址在Document Server容器内部能通。我遇到过一个同事的案例他把url填成了http://localhost:8080/files/...结果Document Server一直下载不到文件因为localhost在Document Server容器里指向的是它自己。editorConfig.callbackUrl是保存回调地址同样需要Document Server能访问。它的作用和document.url一样不能填localhost。editorConfig.user用于标识当前编辑用户。协同编辑时不同用户会以不同颜色游标显示。如果用户ID传错会导致多人编辑时身份错乱甚至权限控制失效。3.4 JWT签名生成与校验ONLYOFFICE从7.x版本开始默认开启JWT签名。开启后token不再是可选的装饰而是必须的。Document Server收到config后会验证token字段是否合法Document Server在回调你的接口时也会在Authorization头里带上签名后的token。两边都用同一个secret。生成JWT使用jjwt库实现如下public static String sign(MapString, Object payload, String secret) { SecretKey key Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); return Jwts.builder() .setClaims(payload) .setIssuedAt(new Date()) .setExpiration(new Date(System.currentTimeMillis() 3600_000L)) .signWith(key, SignatureAlgorithm.HS256) .compact(); }校验Document Server回调请求时从Authorization头中取出Bearer token验签public static boolean verify(String token, String secret) { try { SecretKey key Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } catch (Exception e) { return false; } }这里有一个经验JWT密钥不要太短。HS256算法要求至少256位密钥也就是32字节。如果你用一个很短的字符串当secretjjwt会直接抛异常。我在项目里是生成一段64位的随机字符串放到环境变量里代码不硬编码。回调验证还有个细节ONLYOFFICE回调时Authorization头的格式是Bearer xxx解析时需要去掉Bearer前缀再验签否则校验永远失败。3.5 前端页面嵌入前端接入ONLYOFFICE其实不复杂核心就是引入api.js然后调用DocsAPI.DocEditor创建一个编辑器实例挂在某个DOM节点上。下面是一个最简的HTML示例适合前后端不分离的老项目快速验证!DOCTYPE html html langzh-CN head meta charsetUTF-8 title在线文档/title /head body div iddocEditor stylewidth:100%; height:100vh;/div !-- 注意这里的地址必须是 Document Server 的地址 -- script srchttp://192.168.1.100:8088/web-apps/apps/api/documents/api.js/script script // configJson 由 SpringBoot 接口返回 var config JSON.parse({{configJson}}); new DocsAPI.DocEditor(docEditor, config); /script /body /html如果你是Vue或者React项目建议把编辑器封装成组件。有两个点需要特别留意一是组件卸载时要调用editor.destroyEditor()释放资源否则切换页面后编辑器实例仍然存在容易导致内存泄漏和隐藏的DOM冲突。二是api.js加载是异步的如果你在组件初始化时还没等SDK加载完成就调用DocsAPI会报DocsAPI is not defined。稳妥做法是在script.onload回调后再创建编辑器或者用动态脚本加载器。3.6 回调接口实现Document Server在文档保存、关闭、出错等关键节点会向callbackUrl发送HTTP POST请求SpringBoot接口需要接收并处理。最常见的回调JSON长这样{ status: 2, key: file-123-1700000000, url: http://172.17.0.2:80/cache/files/xxx, users: [uid_0] }其中status是关键字段取值列表如下status含义你需要做什么0文档无变更关闭忽略即可1用户正在编辑忽略或更新在线状态2所有编辑者关闭文档已将最新版本准备好下载url指向的新文件并保存3保存时出错记录日志排查原因4文档已关闭忽略或清理缓存6正在强制保存下载url指向的新文件并保存7强制保存出错记录日志排查原因回调接口返回的JSON格式必须固定为{error: 0}表示处理成功。如果返回其他内容非零表示失败Document Server会尝试重试。我的回调Controller在校验JWT后根据status判断是否需要保存文件PostMapping(/onlyoffice/callback) public MapString, Object callback(RequestBody MapString, Object body) { // 1. 从 Authorization 头取 token 并验签防止伪造回调 // 2. 解析 key找到对应的业务文档 // 3. 如果 status 2 或 status 6说明有最新文件 // 用 HTTP 客户端下载 body.url 指向的文件写回存储 // 4. 文件保存成功后更新数据库中的版本号确保下一次 key 变化 // 5. 返回 {error: 0} }注意ONLYOFFICE回调里的url字段指向的是Document Server内部的临时缓存文件。如果Document Server和SpringBoot部署在同一台机器上直接下载通常没问题如果不在同一台机器且你配置Document Server时指定了对外地址那这个url应该是能正常访问的公网地址。实际项目中我们会在Document Server前面加一层Nginx把内部地址映射成可访问的稳定地址这样回调里的url也会随之保持可用。4. 强制保存与其他高级功能4.1 配置级强制保存ONLYOFFICE的编辑器行为里保存机制和传统桌面Office不太一样。默认情况下用户点击保存按钮文档内容会同步到Document Server的缓存里但只有所有编辑者都关闭文档后Document Server才会把最终版本推送到回调接口。也就是说如果用户编辑到一半直接关掉标签页回调接口收到的可能还是旧文件或者干脆没有回调。为了解决“用户还没关页面但我想让他保存后马上拿到最新文件”就要开启强制保存。最简单的方式是在config的customization中设置两个字段customization: { autosave: true, forcesave: true }forcesave开启后用户每次点击“保存”按钮都会触发一次强制保存Document Server会立即生成最新文件并把status6的回调发到你的接口。这样即使文档还没关闭也能把最新文档同步到业务存储。这个方案适合大多数后台管理系统的场景用户保存文档系统马上把最新稿件归档避免丢失。4.2 外部按钮触发强制保存热搜词里有个“onlyoffice 外部按钮触发回调”说的就是这种场景不想依赖编辑器自带的保存按钮而是在自己页面的工具栏里放一个“保存”按钮点击之后要求Document Server强制保存并且把最新文件推给业务系统。这个需求靠config配置做不到需要调用Document Server的文档命令服务。命令服务接口地址是http://DocumentServer地址/coauthoring/CommandService.ashx请求方式是POSTJSON格式常见命令是forcesave{ c: forcesave, key: file-123-1700000000 }注意key必须和当前正在编辑的文档key一致否则命令不会生效。SpringBoot端封装一个方法调用命令服务public MapString, Object forceSave(String fileKey) { HttpClient client HttpClients.createDefault(); HttpPost post new HttpPost(onlyOfficeProperties.getDocumentServerUrl() /coauthoring/CommandService.ashx); post.setHeader(Content-Type, application/json); post.setHeader(Authorization, Bearer JwtUtils.sign(Map.of(c, forcesave, key, fileKey), secret)); String body {\c\:\forcesave\,\key\:\ fileKey \}; post.setEntity(new StringEntity(body, StandardCharsets.UTF_8)); try (CloseableHttpResponse response client.execute(post)) { String result EntityUtils.toString(response.getEntity()); // 解析 result如果成功会返回 {error: 0} 以及新的 url return objectMapper.readValue(result, new TypeReferenceMapString, Object() {}); } }调用成功后Document Server会返回一个JSON其中包含最新文件的下载地址url。你可以用这个地址下载最新内容也可以等一会让Document Server主动回调你的callbackUrl。这里要提醒一下命令服务返回的url和回调中的url类似都是临时地址及时下载并保存到自己的存储里才是正途。命令服务还有几个常用命令顺便列在这里命令作用forcesave强制保存指定key的文档getinfo获取文档状态信息getforgotten获取所有未保存文档的key列表version获取Document Server版本号如果你的产品要做“文档一键归档”“后台定时保存”这类功能命令服务是绕不开的工具。4.3 关于强制保存的一个经验强制保存虽然好用但要注意频率。如果用户频繁点保存或者后台写了个定时任务每隔几秒强制保存一次Document Server的压力会明显增加而且可能出现“文档没有变更却疯狂保存”的情况白白消耗服务器资源。我项目的做法是普通编辑模式只开autosave用户主动点保存按钮时才触发生效外部按钮触发的强制保存命令只在用户有实际编辑动作时由前端通过业务接口通知SpringBoot再由SpringBoot调用命令服务。这样既保证数据及时落盘又不会无脑刷接口。5. 常见问题与排查技巧实录5.1 部署与访问地址问题“onlyoffice启动之后页面访问地址”是出现频率最高的问题之一。明明容器启动了但浏览器访问不出欢迎页或者编辑器加载后白屏。排查顺序我一般是这样确认容器状态docker ps -a看STATUS是不是Up。看容器日志docker logs -f onlyoffice-docserver报错会直接打出来。确认端口映射如果你把容器80映射到了宿主机的8088就访问http://宿主机IP:8088/welcome/不要用容器内部的80端口。确认防火墙和云安全组8088端口如果没放行外部永远访问不到。如果是本机访问正常、外部访问不了基本就是端口没有对外开放。还有一个细节ONLYOFFICE新版欢迎页面的访问路径可能变了如果在/welcome/下看到404可以试试直接访问根路径http://宿主机IP:8088/有时候会跳到配置向导页面。5.2 依赖、内存与容器异常前面提到的fonts-dejavu依赖问题属于Document Server的非Docker安装场景。如果你用的是Docker镜像还遇到字体缺失一般是因为挂载了自定义字体目录但没放中文字体导致PDF转换或编辑器渲染中文乱码。解决办法是把系统字体目录或中文字体文件挂载到容器里然后重启容器。再一个是内存问题。Document Server内部有一整套Java和Node.js服务栈比较吃内存。如果你给Docker分配的内存太小可能会出现容器启动到一半突然退出、编辑保存时卡死、回调超时等怪问题。建议生产环境至少2核4G多人并发编辑时4核8G才稳妥。5.3 JWT与回调交互问题“ONLYOFFICE强制保存回调失败”“外部按钮触发回调没反应”这类问题十有八九是JWT或者回调地址配置出错了。回调接口校验JWT失败时Document Server会认为这边的接口业务逻辑错误重试几次后放弃导致文档永远保存不到你的存储里。排查时重点看两点一是SpringBoot和Document Server的secret是否完全一致注意字符串不能有多余空格、换行符。二是验签时Authorization头里的token解析逻辑对不对Bearer前缀要正确处理。如果JWT没问题再看回调地址。Document Server要向回调地址发送请求如果回调地址写的是localhost或127.0.0.1那它请求的是Document Server容器自己访问不到SpringBoot。这种情况的表现是你在浏览器里访问回调地址是通的但Document Server保存后就是不回调。解决方法很直接把回调地址写成SpringBoot服务的局域网IP或公网域名并确保防火墙放行。5.4 文档保存异常与旧文件问题还有一种常见现象用户编辑保存后再到系统里下载发现下载下来的还是旧文件。这通常是两种情况第一种SpringBoot没有处理status2的回调。大多数教程只演示了回调接收没强调要在回调里下载新文件并更新存储。Document Server不会自动帮你存到业务数据库它只是通知你“有新文件了你来拿”。如果你收到回调却不下载、不更新文件当然不会变新。第二种document.key没有更新。文件内容改了但key没变Document Server会命中缓存直接返回老文件。解决办法是每次文件保存成功后把key更新成新的时间戳或版本号这样Document Server会认为这是一个新版本文档。我见过一个同事折腾了大半天最后发现是key一直固定写死怎么保存都是旧文件改完key后一切正常。这个坑非常典型值得记笔记。5.5 关于版本的提醒最后说一个很多人忽视的坑ONLYOFFICE的版本兼容性。官方镜像的latest标签是跟随最新版本走的大版本升级后某些配置字段和行为会有调整。比如JWT参数、回调状态码的范围、命令服务返回格式这些在不同大版本里可能有细微差异。如果是一套已经稳定运行的项目不要随便执行docker pull onlyoffice/documentserver:latest升级。升级前先在测试环境完整跑一遍编辑、保存、强制保存、协同编辑流程确认兼容性没问题再上生产。我在项目中会把镜像版本固定到具体的tag比如onlyoffice/documentserver:8.0.1而不是用latest。另外一个体会是ONLYOFFICE集成最耗时间的往往不是编码而是环境联调。SpringBoot这边的接口和逻辑加起来可能就几百行代码但浏览器、SpringBoot、Document Server三方之间的网络和地址问题会反复消耗你的耐心。建议动手之前先把网络拓扑画出来把三个IP地址和四个URL写清楚再开始写代码能省下一大半排障时间。这个方案后续如果要做深其实还有不少可以扩展的地方比如接入OSS保存大文件、结合自己的组织架构做协同权限、对接WebSocket服务推送文档变更通知。核心链路跑通之后这些扩展都只是业务逻辑上的叠加而已。