OnlyOffice 私有化部署与 Spring Boot 整合实战教程
在 Windows 11 环境下通过 Docker 私有化部署 OnlyOffice Document Server,并结合 Spring Boot 实现文档预览与编辑功能。流程包括镜像拉取、容器参数配置、Java 后端接口开发、前端 SDK 集成及常见问题排查,重点解决跨域访问、回调保存及网络连通性问题,提供可直接运行的代码示例与测试步骤。

在 Windows 11 环境下通过 Docker 私有化部署 OnlyOffice Document Server,并结合 Spring Boot 实现文档预览与编辑功能。流程包括镜像拉取、容器参数配置、Java 后端接口开发、前端 SDK 集成及常见问题排查,重点解决跨域访问、回调保存及网络连通性问题,提供可直接运行的代码示例与测试步骤。

docker -v 验证)打开 Win11 的「终端」(管理员模式),执行以下命令拉取官方最新镜像:
# 拉取 OnlyOffice Document Server 最新版镜像
docker pull onlyoffice/documentserver:latest
docker images,能看到 onlyoffice/documentserver 镜像即成功。为了避免容器重启后数据丢失,创建本地目录映射容器内数据目录:
# 新建本地目录(建议放在非系统盘,比如 D 盘)
mkdir D:\onlyoffice\data
mkdir D:\onlyoffice\logs
mkdir D:\onlyoffice\plugins
mkdir D:\onlyoffice\fonts
核心命令:关闭 JWT 验证(忽略 token),并映射端口和目录:
docker run -itd --name onlyoffice \
-p 9999:80 \
-v D:\onlyoffice\data:/var/www/onlyoffice/Data \
-v D:\onlyoffice\logs:/var/log/onlyoffice \
-v D:\onlyoffice\plugins:/var/www/onlyoffice/documentserver/sdkjs-plugins \
-v D:\onlyoffice\fonts:/usr/share/fonts \
-e JWT_SECRET=mysecret \
-e JWT_ENABLED=false \
--restart=always \
onlyoffice/documentserver:latest
参数说明:
-p 9999:80:将容器 80 端口映射到主机 9999 端口(访问用)-v:目录挂载(数据/日志/插件/字体持久化)JWT_ENABLED=false:关键!关闭 Token 验证(忽略 JWT)--restart=always:Docker 重启后自动启动容器--name onlyoffice:给容器命名,方便管理
docker logs onlyoffice 查看报错(常见问题:端口被占用,换 -p 9998:80 重试)。http://localhost:9999/healthcheck,返回 {"status":"true"} 即服务正常。浏览器访问验证:打开 http://localhost:9999,若看到 OnlyOffice 欢迎页(显示 Document Server is running),则部署成功!
查看容器状态:执行 docker ps,若 onlyoffice 状态为 Up 则运行中;
OnlyOffice 启动需要下载依赖,Win11 可能出现启动超时:
docker exec -it onlyoffice bash 进入容器;退出容器:exit
手动执行初始化脚本:
supervisorctl restart all
Java 后端提供「文档预览/编辑」接口,返回 OnlyOffice 所需的配置参数(文档地址、回调地址等),前端通过 OnlyOffice SDK 加载编辑器。
<?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.7.0</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>onlyoffice-demo</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<!-- Spring Web 核心 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web
org.springframework.boot
spring-boot-starter-webflux
com.alibaba
fastjson
1.2.83
org.springframework.boot
spring-boot-starter-test
test
org.springframework.boot
spring-boot-maven-plugin
server:
port: 48083 # Java 服务端口
# OnlyOffice 配置
onlyOffice:
server:
url: http://localhost:9999 # 本地 Docker 部署的 OnlyOffice 地址
document:
storage: D:/onlyoffice/documents/ # 本地文档存储目录(需提前创建)
创建 DocumentUtils.java,处理文档路径、URL 生成:
package com.example.onlyofficedemo.utils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.io.File;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
@Component
public class OnlyOfficeUtils {
@Value("${onlyoffice.document.storage}")
private String documentStoragePath;
@Value("${onlyoffice.server.url}")
private String onlyOfficeServerUrl;
@Value("${server.port}")
private String serverPort;
// 初始化文档存储目录
public void initStorageDir() {
File dir = new File(documentStoragePath);
if (!dir.exists()) {
dir.mkdirs();
}
}
// 获取文档访问 URL(供 OnlyOffice 访问)
public String getDocumentUrl(String fileName) {
// 本地 Java 服务的 IP + 端口(Win11 需替换为实际 IP,不能用 localhost,否则容器访问不到)
String host = "http://" + getLocalIp() + ":" + serverPort;
return host + "/document/get?fileName=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8);
}
// 获取回调 URL(OnlyOffice 保存文档时回调)
public String getCallbackUrl(String fileName) {
String + getLocalIp() + + serverPort;
host + + URLEncoder.encode(fileName, StandardCharsets.UTF_8);
}
String {
onlyOfficeServerUrl + ;
}
String {
{
java.net. java.net.InetAddress.getLocalHost();
addr.getHostAddress();
} (Exception e) {
;
}
}
String {
documentStoragePath + File.separator + fileName;
}
}
创建 OnlyOfficeOffController.java,提供「文档获取、编辑配置、回调保存」接口:
package com.vintechhk.module.document.controller.app.document;
import com.alibaba.fastjson.JSONObject;
import com.vintechhk.module.document.util.OnlyOfficeUtils;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.UUID;
/**
* 用户端 - 协作文档 Controller
*/
@Tag(name = "用户端 - 在线文档")
@RestController
@RequestMapping("/doc/only-office")
@Validated
@Slf4j
@CrossOrigin(origins = "*") // 允许跨域(测试用,生产需限制)
public class OnlyOfficeOffController {
@Autowired
private OnlyOfficeUtils onlyOfficeUtils;
// 初始化:创建测试文档
@GetMapping("/init")
public String initTestDocument() {
log.info("-----------------------初始化---init-------1-----------");
onlyOfficeUtils.initStorageDir();
+ UUID.randomUUID() + ;
onlyOfficeUtils.getDocumentLocalPath(testFileName);
(localPath);
(!testFile.exists()) {
{
testFile.createNewFile();
(testFile);
fos.write(.getBytes());
fos.close();
} (Exception e) {
+ e.getMessage();
}
}
log.info();
+ testFileName + + testFileName;
}
ResponseEntity<FileSystemResource> {
onlyOfficeUtils.getDocumentLocalPath(fileName);
(localPath);
(!file.exists()) {
<>(HttpStatus.NOT_FOUND);
}
();
headers.add(, );
headers.add(, + fileName);
headers.add(, );
headers.add(, );
ResponseEntity.ok().headers(headers).contentLength(file.length()).contentType(MediaType.APPLICATION_OCTET_STREAM).body( (file));
}
JSONObject {
();
config.put(, );
config.put(, onlyOfficeUtils.getEditorUrl());
();
document.put(, fileName);
document.put(, onlyOfficeUtils.getDocumentUrl(fileName));
document.put(, fileName.substring(fileName.lastIndexOf() + ));
document.put(, UUID.randomUUID().toString());
config.put(, document);
();
editorConfig.put(, onlyOfficeUtils.getCallbackUrl(fileName));
editorConfig.put(, );
config.put(, editorConfig);
config;
}
String {
{
JSONObject.parseObject(request.getInputStream(), .getClass());
json.getString();
(.equals(status)) {
json.getJSONObject().getString();
(downloadUrl);
url.openConnection();
conn.getInputStream();
onlyOfficeUtils.getDocumentLocalPath(fileName);
(localPath);
[] buffer = [];
len;
((len = is.read(buffer)) != -) {
fos.write(buffer, , len);
}
fos.close();
is.close();
}
;
} (Exception e) {
+ e.getMessage() + ;
}
}
}
创建 OnlyOfficeDemoApplication.java:
package com.example.onlyofficedemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OnlyOfficeDemoApplication {
public static void main(String[] args) {
SpringApplication.run(OnlyOfficeDemoApplication.class, args);
}
}
在 resources/static 目录下创建 edit.html(Spring Boot 静态资源目录):
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>OnlyOffice 编辑测试</title>
<style>
#editor { width: 100%; height: 800px; }
</style>
</head>
<body>
<div id="editor"></div>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
<script>
// 获取 URL 参数
function getUrlParam(name) {
let reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
let r = window.location.search.substr(1).match(reg);
(r != ) (r[]);
;
}
fileName = ();
$.( + fileName, () {
script = .();
script. = data.;
script. = () {
.(, {
: data.,
: data.,
: data.,
: ,
:
});
};
..(script);
});
docker start onlyoffice);OnlyOfficeDemoApplication.java);D:/onlyoffice/documents/ 目录(文档存储用)。浏览器访问:http://localhost:48083/document/init
返回类似:测试文档创建成功!文件名:test-xxx.docx,访问编辑页:http://localhost:48083/document/edit?fileName=test-xxx.docx
复制返回的编辑页 URL 到浏览器打开,即可看到 OnlyOffice 编辑器加载完成,显示测试文档:
http://localhost:48083/document/callback 接口,将编辑后的内容保存到本地文档。打开 D:/onlyoffice/documents/ 下的测试文档,查看内容是否已更新,确认保存成功。
localhost,容器内无法访问主机的 localhost;DocumentUtils.java 中 getLocalIp() 需返回 Win11 实际 IP(如 192.168.1.100),而非 127.0.0.1。docker exec -it onlyoffice bash 进入容器,运行 apt update && apt install -y wget,再重启容器。<meta charset="UTF-8">。JWT_ENABLED=false),映射端口和目录;至此,从 OnlyOffice 私有化部署到 Java 对接测试的全流程已完成,可基于此扩展更多功能(如文档权限控制、多格式支持、历史版本等)。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online