适合:政务系统、企业管理系统、案件系统、OA、调解系统、内网系统
关键词:文件预览、Word预览、PDF预览、Vue、Spring Boot、LibreOffice、PDF.js、权限控制
一、为什么"文件预览"是个坑?
很多项目一开始都会选择最简单的方案,比如:
Google Docs Viewer (Web 在线预览)
适合公开可访问的文档 URL:
✔️ 支持 Word、Excel、PPT、PDF
✔️ 免费
❗️文件需能被 Google 访问(即公网 URL)
javascript
<iframe
width="100%"
height="600px"
:src="`https://docs.google.com/gview?url=${encodeURIComponent(docUrl)}&embedded=true`"
/>
Microsoft Office Online Viewer
类似 Google Docs:
javascript
<iframe
width="100%"
height="600px"
:src="`https://view.officeapps.live.com/op/embed.aspx?src=${encodeURIComponent(docUrl)}`"
/>
✔️ 支持 Office 文件(docx/xlsx/pptx)
✔️ 免费
❗️文件同样必须能公网访问
或者:用的是
Google Docs Viewer (Web 在线预览)
xdocin 在线预览服务 ,这个服务的预览体验不错,但它本身 不是完全免费的(尤其对大文件、长期/商用预览、去掉水印等都有收费策略),而且用过一段时间就需要收费了,会让你加qq群啥的,可以领个3天免费使用。
javascript
<iframe :src="https://view.xdocin.com/view?src=${docUrl}&toolbar=false"></iframe>
在测试环境看起来没问题,但一旦上线就会遇到:
-
❌ 预览服务到期 / 收费
-
❌ 内网文件无法访问
-
❌ HTTP / IP 地址被拦截
-
❌ 中文文件名解析失败
-
❌ 权限失控,文件被外部平台拉取
-
❌ CSP / iframe 安全策略拦截
本质问题:你把"核心业务能力"交给了第三方平台。
在政务、企业系统中,文件通常涉及:
-
隐私数据
-
案件信息
-
合同、协议、回执
这些文件不应该、也不适合交给 Google / 微软 / 外部 SaaS 平台处理。
二、常见方案对比
| 方案 | 免费 | 稳定 | 支持内网 | 权限控制 | 生产环境推荐 |
|---|---|---|---|---|---|
| Google Docs Viewer | ✅ | ⚠️ | ❌ | ❌ | ❌ |
| Microsoft Viewer | ✅ | ⚠️ | ❌ | ❌ | ❌ |
| xdocin / 商业服务 | ❌ | ⚠️ | ⚠️ | ⚠️ | ⚠️ |
| 自建 PDF 预览方案 | ✅ | ✅ | ✅ | ✅ | ✅ |
结论:真正适合上线的,只有"自建 PDF 预览方案"
三、企业级"正确架构"设计
核心思想
所有文件统一转为 PDF → 前端只负责预览 PDF
为什么?
-
PDF 跨平台
-
浏览器原生支持
-
不依赖第三方
-
易加水印、权限、日志
四、整体架构图
浏览器(Vue / H5 / 小程序)
↓
请求预览接口
↓
后端 /api/preview?fileId=xxx
↓
权限校验 / 日志记录
↓
是否已有 PDF?
├─ 是 → 返回 PDF 地址
└─ 否 → 转换生成 PDF
↓
返回 PDF 地址
↓
前端使用 PDF.js 渲染
五、后端实现方案(Java + Spring Boot)
1. 安装 LibreOffice(Linux)
sudo apt update
sudo apt install libreoffice
2. 转换命令
soffice --headless --convert-to pdf input.docx --outdir /data/pdf
支持格式:
-
doc / docx
-
xls / xlsx
-
ppt / pptx
-
odt / odp
六、Spring Boot 转换代码示例
public void convertToPdf(String inputPath, String outputDir) throws Exception {
ProcessBuilder builder = new ProcessBuilder(
"soffice",
"--headless",
"--convert-to",
"pdf",
inputPath,
"--outdir",
outputDir
);
Process process = builder.start();
process.waitFor();
}
七、预览接口设计(推荐方式)
接口设计
GET /api/preview?fileId=123
后端流程
-
校验用户登录状态
-
校验文件权限
-
查询 PDF 是否已存在
-
不存在则触发转换
-
返回 PDF 访问地址或流
八、前端 Vue + PDF.js 实现
安装依赖
npm install pdfjs-dist
Vue 组件示例
<template>
<div class="pdf-container">
<canvas ref="canvas"></canvas>
</div>
</template>
<script setup>
import { ref, onMounted } from "vue"
import * as pdfjsLib from "pdfjs-dist"
pdfjsLib.GlobalWorkerOptions.workerSrc =
"https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js"
const canvas = ref()
const pdfUrl = "/api/preview?fileId=123"
onMounted(async () => {
const pdf = await pdfjsLib.getDocument(pdfUrl).promise
const page = await pdf.getPage(1)
const viewport = page.getViewport({ scale: 1.5 })
const context = canvas.value.getContext("2d")
canvas.value.height = viewport.height
canvas.value.width = viewport.width
page.render({ canvasContext: context, viewport })
})
</script>
<style>
.pdf-container {
width: 100%;
overflow: auto;
}
</style>
九、安全设计(非常重要)
1. 不要暴露真实文件路径
错误做法:
http://server/files/secret.docx
正确做法:
/api/preview?fileId=xxx
2. 权限校验
建议校验:
-
用户身份
-
文件归属
-
角色权限
3. 临时访问机制
可以给 PDF 地址设置:
-
Token
-
5 分钟有效期
-
单次访问
十、性能优化建议
缓存机制
-
转换后的 PDF 不要重复生成
-
存 Redis 或数据库标记
异步转换
-
大文件走消息队列
-
前端轮询状态
十一、进阶功能
| 功能 | 说明 |
|---|---|
| 水印 | 防截图、防泄密 |
| 操作日志 | 谁看了什么文件 |
| 搜索 | PDF 文本检索 |
| 分页加载 | 大文件优化 |
| 电子签章 | 合同系统常用 |
十二、适用场景
特别适合:
-
政务系统
-
调解 / 案件系统
-
OA 系统
-
内网平台
-
医疗 / 金融系统
不适合:
-
个人博客
-
临时演示页面
十三、总结
错误路线
iframe + Google / 微软 / 商业预览服务
短期能跑,长期必踩坑
正确路线
后端统一转 PDF → 前端 PDF.js 渲染 → 权限控制 + 缓存 + 审计
这是:
-
稳定
-
免费
-
安全
-
可控
-
企业级
十四、结语
文件预览看起来是小功能,实际上是:
安全 + 权限 + 稳定性 + 架构设计能力的综合体现
如果你系统要长期维护、多人使用、涉及隐私数据,一定要走自建方案。
十五、交流
如果你正在做:
-
Vue / React 管理系统
-
政务 / 企业平台
-
文件系统 / 电子签约
欢迎留言交流架构和实现方案