第一章:word和pdf的“爱恨情仇”
1.1 初遇:两种不同的“性格”
word同学:活泼开朗的编辑小王子,天生爱打扮(格式丰富),随时可以改头换面(可编辑),但有时候过于花哨,换个环境就“水土不服”。
pdf同学:高冷严谨的档案管理员,保持原样绝不动摇(格式固定),去哪都一个样(跨平台一致),但有点固执——“你可以看我,但别想碰我”(难以编辑)。
1.2 办公室恋情发展
- word转pdf:word决定“从良”,放弃花哨生活,变成稳重可靠的pdf。这叫“爱的封印”——把美好定格,防止别人乱改。
- pdf转word:pdf想要“放开自我”,尝试可编辑的生活。但这个过程就像“开盲盒”——有时候能完美转换,有时候……只能说“尽力了”。
第二章:springboot当“红娘”的准备步骤
2.1 创建springboot“婚介所”
用spring initializr创建项目,记得带上这些“彩礼”:
- spring web (提供rest api)
- apache poi (处理word)
- pdfbox (处理pdf)
- openpdf (或itext,用于pdf生成)
2.2 maven依赖配置(pom.xml)
<!-- 婚礼请柬列表 -->
<dependencies>
<!-- springboot基础套餐 -->
<dependency>
<groupid>org.springframework.boot</groupid>
<artifactid>spring-boot-starter-web</artifactid>
</dependency>
<!-- word处理专家:apache poi全家桶 -->
<dependency>
<groupid>org.apache.poi</groupid>
<artifactid>poi</artifactid>
<version>5.2.3</version>
</dependency>
<dependency>
<groupid>org.apache.poi</groupid>
<artifactid>poi-ooxml</artifactid>
<version>5.2.3</version>
</dependency>
<!-- pdf处理专家:pdfbox -->
<dependency>
<groupid>org.apache.pdfbox</groupid>
<artifactid>pdfbox</artifactid>
<version>2.0.27</version>
</dependency>
<!-- 另一种pdf生成选择:openpdf -->
<dependency>
<groupid>com.github.librepdf</groupid>
<artifactid>openpdf</artifactid>
<version>1.3.30</version>
</dependency>
</dependencies>
第三章:详细实现步骤(带完整代码)
3.1 word转pdf:word的“成熟仪式”
创建word处理服务
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.stereotype.service;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.font.pdtype1font;
import com.lowagie.text.*;
import com.lowagie.text.pdf.pdfwriter;
import java.io.*;
@service
public class wordtopdfservice {
/**
* 方法1:使用apache poi + openpdf(适合.doc和.docx)
* 这是我们的“豪华版”转换,带格式的
*/
public void convertwordtopdf(inputstream wordstream, outputstream pdfstream)
throws exception {
// 1. 读取word文档(就像给word做体检)
xwpfdocument document = new xwpfdocument(wordstream);
// 2. 创建pdf文档(准备新衣服)
document pdfdocument = new document();
pdfwriter.getinstance(pdfdocument, pdfstream);
pdfdocument.open();
// 3. 逐段处理(把word的每一句话翻译成pdf能听懂的语言)
for (xwpfparagraph paragraph : document.getparagraphs()) {
string text = paragraph.gettext();
if (!text.isempty()) {
// 设置字体大小(pdf比较挑剔,要明确告诉它)
font font = new font(font.helvetica, 12);
pdfdocument.add(new paragraph(text, font));
}
}
// 4. 处理表格(如果有的话)
for (xwpftable table : document.gettables()) {
// 这里可以添加表格处理逻辑
// 为了简化,我们先跳过复杂的表格转换
}
// 5. 完成转换(礼成!)
pdfdocument.close();
document.close();
}
/**
* 方法2:快速转换版(只提取文本,适合简单文档)
* 这是“经济适用型”转换
*/
public void convertwordtopdfsimple(file wordfile, file pdffile)
throws ioexception {
xwpfdocument doc = new xwpfdocument(new fileinputstream(wordfile));
try (pddocument pdfdoc = new pddocument()) {
pdpage page = new pdpage();
pdfdoc.addpage(page);
try (pdpagecontentstream contentstream =
new pdpagecontentstream(pdfdoc, page)) {
contentstream.begintext();
contentstream.setfont(pdtype1font.helvetica, 12);
contentstream.newlineatoffset(50, 700);
// 逐段添加文本
for (xwpfparagraph para : doc.getparagraphs()) {
string text = para.gettext();
if (!text.trim().isempty()) {
contentstream.showtext(text);
contentstream.newlineatoffset(0, -15); // 换行
}
}
contentstream.endtext();
}
pdfdoc.save(pdffile);
}
doc.close();
}
}
创建rest控制器
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.multipartfile;
import java.io.*;
@restcontroller
@requestmapping("/api/document")
public class documentconversioncontroller {
@autowired
private wordtopdfservice wordtopdfservice;
/**
* word转pdf的api端点
* 访问方式:post /api/document/word-to-pdf
*/
@postmapping("/word-to-pdf")
public responseentity<byte[]> convertwordtopdf(
@requestparam("file") multipartfile file) {
try {
// 1. 检查文件类型(确保不是乱来的文件)
string filename = file.getoriginalfilename();
if (filename == null ||
(!filename.endswith(".docx") && !filename.endswith(".doc"))) {
return responseentity.badrequest()
.body("只能上传.doc或.docx文件!".getbytes());
}
// 2. 创建临时文件(给word和pdf准备临时婚房)
file tempwordfile = file.createtempfile("temp", ".docx");
file temppdffile = file.createtempfile("converted", ".pdf");
// 3. 保存上传的文件
file.transferto(tempwordfile);
// 4. 执行转换(见证奇迹的时刻!)
wordtopdfservice.convertwordtopdfsimple(
tempwordfile, temppdffile);
// 5. 读取生成的pdf
byte[] pdfbytes = files.readallbytes(temppdffile.topath());
// 6. 设置响应头(告诉浏览器:这是pdf,请用pdf方式打开)
httpheaders headers = new httpheaders();
headers.setcontenttype(mediatype.application_pdf);
headers.setcontentdisposition(
contentdisposition.attachment()
.filename(filename.replace(".docx", ".pdf").replace(".doc", ".pdf"))
.build()
);
// 7. 清理临时文件(婚房不能留着,要环保)
tempwordfile.delete();
temppdffile.delete();
return new responseentity<>(pdfbytes, headers, httpstatus.ok);
} catch (exception e) {
return responseentity.status(httpstatus.internal_server_error)
.body(("转换失败:" + e.getmessage()).getbytes());
}
}
}
3.2 pdf转word:pdf的“解放运动”
创建pdf转word服务
import org.apache.pdfbox.pdmodel.pddocument;
import org.apache.pdfbox.text.pdftextstripper;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.stereotype.service;
import java.io.*;
@service
public class pdftowordservice {
/**
* pdf转word - 文本提取版
* 警告:这就像把煎蛋变回鸡蛋——能变,但样子不一样了
*/
public void convertpdftoword(file pdffile, file wordfile) throws ioexception {
// 1. 读取pdf(撬开pdf的嘴,让它说话)
try (pddocument document = pddocument.load(pdffile)) {
// 2. 创建word文档(准备新容器)
xwpfdocument worddoc = new xwpfdocument();
// 3. 提取pdf文本(让pdf"吐"出文字)
pdftextstripper stripper = new pdftextstripper();
string text = stripper.gettext(document);
// 4. 按行分割并添加到word
string[] lines = text.split("\n");
for (string line : lines) {
if (!line.trim().isempty()) {
xwpfparagraph paragraph = worddoc.createparagraph();
xwpfrun run = paragraph.createrun();
run.settext(line);
run.setfontsize(12);
}
}
// 5. 保存word文档(完成转换)
try (fileoutputstream out = new fileoutputstream(wordfile)) {
worddoc.write(out);
}
worddoc.close();
}
}
/**
* 高级版:带基本格式保留
* 注意:pdf转word是"世界难题",不要期待完美
*/
public void convertpdftowordadvanced(inputstream pdfstream,
outputstream wordstream)
throws ioexception {
try (pddocument pdfdoc = pddocument.load(pdfstream);
xwpfdocument worddoc = new xwpfdocument()) {
pdftextstripper stripper = new pdftextstripper();
// 设置提取参数
stripper.setsortbyposition(true); // 按位置排序
stripper.setstartpage(1); // 从第1页开始
stripper.setendpage(pdfdoc.getnumberofpages()); // 到最后一页
string text = stripper.gettext(pdfdoc);
// 处理文本,尝试保留一些结构
string[] paragraphs = text.split("\n\n"); // 假设空行是段落分隔
for (string paratext : paragraphs) {
if (paratext.trim().length() > 0) {
xwpfparagraph paragraph = worddoc.createparagraph();
// 设置段落格式
paragraph.setalignment(paragraphalignment.left);
// 添加文本
xwpfrun run = paragraph.createrun();
run.settext(paratext);
run.setfontfamily("宋体");
run.setfontsize(12);
// 添加空行作为段落间隔
worddoc.createparagraph();
}
}
worddoc.write(wordstream);
}
}
}
添加pdf转word的api端点
// 在documentconversioncontroller中添加
@postmapping("/pdf-to-word")
public responseentity<byte[]> convertpdftoword(
@requestparam("file") multipartfile file) {
try {
// 1. 检查文件类型
string filename = file.getoriginalfilename();
if (filename == null || !filename.endswith(".pdf")) {
return responseentity.badrequest()
.body("只能上传.pdf文件!".getbytes());
}
// 2. 创建临时文件
file temppdffile = file.createtempfile("temp", ".pdf");
file tempwordfile = file.createtempfile("converted", ".docx");
// 3. 保存上传的文件
file.transferto(temppdffile);
// 4. 执行转换(让pdf"变身")
pdftowordservice pdftowordservice = new pdftowordservice();
pdftowordservice.convertpdftoword(temppdffile, tempwordfile);
// 5. 读取生成的word
byte[] wordbytes = files.readallbytes(tempwordfile.topath());
// 6. 设置响应头
httpheaders headers = new httpheaders();
headers.setcontenttype(mediatype.application_octet_stream);
headers.setcontentdisposition(
contentdisposition.attachment()
.filename(filename.replace(".pdf", ".docx"))
.build()
);
// 7. 清理临时文件
temppdffile.delete();
tempwordfile.delete();
return new responseentity<>(wordbytes, headers, httpstatus.ok);
} catch (exception e) {
return responseentity.status(httpstatus.internal_server_error)
.body(("转换失败:" + e.getmessage()).getbytes());
}
}
3.3 创建前端页面(html + javascript)
<!doctype html>
<html>
<head>
<title>文档转换器 - word和pdf的相亲平台</title>
<style>
body {
font-family: 'comic sans ms', cursive, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}
.container {
background: white;
padding: 30px;
border-radius: 15px;
box-shadow: 0 10px 30px rgba(0,0,0,0.1);
}
h1 {
color: #2c3e50;
text-align: center;
margin-bottom: 30px;
}
.converter-box {
border: 2px dashed #3498db;
padding: 20px;
border-radius: 10px;
margin: 20px 0;
text-align: center;
transition: all 0.3s;
}
.converter-box:hover {
border-color: #e74c3c;
background: #f9f9f9;
}
button {
background: #3498db;
color: white;
border: none;
padding: 12px 24px;
border-radius: 25px;
cursor: pointer;
font-size: 16px;
margin: 10px;
transition: all 0.3s;
}
button:hover {
background: #2980b9;
transform: translatey(-2px);
}
#result {
margin-top: 20px;
padding: 15px;
background: #ecf0f1;
border-radius: 5px;
display: none;
}
.tips {
background: #fff3cd;
border-left: 4px solid #ffc107;
padding: 15px;
margin: 20px 0;
border-radius: 0 5px 5px 0;
}
</style>
</head>
<body>
<div class="container">
<h1>📄 word ↔ pdf 转换器 📄</h1>
<p>让word和pdf愉快地"谈恋爱"!选择你想进行的转换:</p>
<div class="tips">
<strong>温馨提示:</strong>
1. word转pdf:婚礼很完美,格式基本保留
2. pdf转word:离婚再结婚,可能损失一些"财产"(格式)
3. 文件大小限制:10mb以内
</div>
<!-- word转pdf区域 -->
<div class="converter-box">
<h2>word → pdf 转换</h2>
<p>让活泼的word变成稳重的pdf(推荐使用)</p>
<input type="file" id="wordfile" accept=".doc,.docx">
<button onclick="convertwordtopdf()">开始转换!</button>
</div>
<!-- pdf转word区域 -->
<div class="converter-box">
<h2>pdf → word 转换</h2>
<p>尝试让高冷的pdf变得可编辑(结果可能"惊喜")</p>
<input type="file" id="pdffile" accept=".pdf">
<button onclick="convertpdftoword()">勇敢尝试!</button>
</div>
<!-- 结果显示区域 -->
<div id="result">
<h3>转换结果</h3>
<p id="resultmessage"></p>
<a id="downloadlink" style="display:none;">
<button>下载转换后的文件</button>
</a>
</div>
</div>
<script>
// word转pdf函数
async function convertwordtopdf() {
const fileinput = document.getelementbyid('wordfile');
const file = fileinput.files[0];
if (!file) {
alert('请先选择一个word文件!');
return;
}
const formdata = new formdata();
formdata.append('file', file);
try {
const response = await fetch('/api/document/word-to-pdf', {
method: 'post',
body: formdata
});
if (response.ok) {
const blob = await response.blob();
const url = window.url.createobjecturl(blob);
document.getelementbyid('result').style.display = 'block';
document.getelementbyid('resultmessage').textcontent =
'转换成功!word已成功"进化"为pdf!';
const downloadlink = document.getelementbyid('downloadlink');
downloadlink.href = url;
downloadlink.download = file.name.replace(/\.(docx|doc)$/, '.pdf');
downloadlink.style.display = 'block';
} else {
throw new error('转换失败');
}
} catch (error) {
document.getelementbyid('result').style.display = 'block';
document.getelementbyid('resultmessage').textcontent =
'转换失败:' + error.message;
}
}
// pdf转word函数
async function convertpdftoword() {
const fileinput = document.getelementbyid('pdffile');
const file = fileinput.files[0];
if (!file) {
alert('请先选择一个pdf文件!');
return;
}
const formdata = new formdata();
formdata.append('file', file);
try {
const response = await fetch('/api/document/pdf-to-word', {
method: 'post',
body: formdata
});
if (response.ok) {
const blob = await response.blob();
const url = window.url.createobjecturl(blob);
document.getelementbyid('result').style.display = 'block';
document.getelementbyid('resultmessage').textcontent =
'pdf成功"解放"为word!部分格式可能丢失,请理解。';
const downloadlink = document.getelementbyid('downloadlink');
downloadlink.href = url;
downloadlink.download = file.name.replace('.pdf', '.docx');
downloadlink.style.display = 'block';
} else {
throw new error('转换失败');
}
} catch (error) {
document.getelementbyid('result').style.display = 'block';
document.getelementbyid('resultmessage').textcontent =
'转换失败:' + error.message + '。pdf可能太"固执"了!';
}
}
</script>
</body>
</html>
3.4 添加application主类
import org.springframework.boot.springapplication;
import org.springframework.boot.autoconfigure.springbootapplication;
import org.springframework.context.annotation.bean;
import org.springframework.web.multipart.commons.commonsmultipartresolver;
@springbootapplication
public class documentconverterapplication {
public static void main(string[] args) {
springapplication.run(documentconverterapplication.class, args);
system.out.println("======================================");
system.out.println("文档转换服务启动成功!");
system.out.println("访问地址:http://localhost:8080");
system.out.println("word和pdf可以开始'谈恋爱'了!");
system.out.println("======================================");
}
@bean(name = "multipartresolver")
public commonsmultipartresolver multipartresolver() {
commonsmultipartresolver resolver = new commonsmultipartresolver();
resolver.setmaxuploadsize(10485760); // 10mb限制
resolver.setdefaultencoding("utf-8");
return resolver;
}
}
3.5 添加配置文件(application.yml)
spring:
servlet:
multipart:
max-file-size: 10mb
max-request-size: 10mb
application:
name: document-converter
server:
port: 8080
servlet:
context-path: /
# 日志配置,方便调试
logging:
level:
org.springframework.web: info
com.example.documentconverter: debug
file:
name: logs/document-converter.log
第四章:项目优化和高级功能
4.1 添加批量转换功能
@service
public class batchconversionservice {
/**
* 批量转换 - 适合大量文档处理
* 比如:把整个部门的word报告都转成pdf
*/
public void batchwordtopdf(list<file> wordfiles, file outputdir) {
wordfiles.parallelstream().foreach(wordfile -> {
try {
file pdffile = new file(outputdir,
wordfile.getname().replacefirst("\\.[^.]+$", "") + ".pdf");
// 调用转换服务
// wordtopdfservice.convertwordtopdfsimple(wordfile, pdffile);
system.out.println("转换完成: " + wordfile.getname());
} catch (exception e) {
system.err.println("转换失败: " + wordfile.getname() + " - " + e.getmessage());
}
});
}
}
4.2 添加转换进度跟踪
@component
public class conversionprogresstracker {
private map<string, conversionstatus> statusmap = new concurrenthashmap<>();
public enum conversionstatus {
pending, processing, completed, failed
}
public void startconversion(string taskid, string filename) {
statusmap.put(taskid, conversionstatus.processing);
}
public void updateprogress(string taskid, int progress) {
// 更新进度
}
public conversionstatus getstatus(string taskid) {
return statusmap.getordefault(taskid, conversionstatus.pending);
}
}
4.3 添加水印功能
@service
public class watermarkservice {
/**
* 给pdf添加水印
*/
public void addwatermarktopdf(file pdffile, string watermarktext)
throws ioexception {
try (pddocument document = pddocument.load(pdffile)) {
for (pdpage page : document.getpages()) {
try (pdpagecontentstream contentstream =
new pdpagecontentstream(document, page,
pdpagecontentstream.appendmode.append, true)) {
// 设置水印样式
contentstream.setfont(pdtype1font.helvetica_oblique, 60);
contentstream.setnonstrokingcolor(200, 200, 200); // 浅灰色
// 旋转45度
contentstream.begintext();
contentstream.settextrotation(math.toradians(45),
page.getmediabox().getwidth() / 2,
page.getmediabox().getheight() / 2);
contentstream.showtext(watermarktext);
contentstream.endtext();
}
}
document.save(pdffile);
}
}
}
第五章:总结与心得
5.1 转换效果对比
word转pdf:
- 成功率高,就像把新鲜水果做成果酱——能很好地保存原味
- 格式基本保留,布局不乱
- 推荐使用apache poi + openpdf组合
pdf转word:
- 像把炒熟的鸡蛋变回生鸡蛋——技术上有难度
- 复杂格式(表格、特殊排版)容易丢失
- 扫描版pdf需要ocr,这是另一个故事了
5.2 实战建议
选择合适的工具库:
- 简单需求:apache poi + pdfbox
- 复杂需求:考虑aspose或商业库(但要花钱)
- 云端方案:直接用microsoft graph api或google docs api
性能优化建议:
- 大文件分块处理
- 使用内存映射文件
- 考虑异步处理 + websocket推送进度
错误处理要点:
- 一定要关闭文档流(否则内存泄漏)
- 添加文件类型验证
- 设置合理的超时时间
安全注意事项:
- 限制上传文件大小
- 检查文件内容(防止恶意文件)
- 临时文件及时清理
5.3 结语
通过这个项目,我们成功地为word和pdf搭建了一个"相亲平台":
- word转pdf就像一场浪漫的婚礼:word穿上pdf的婚纱,承诺"从今以后,我的格式永不变心"。
- pdf转word则像一场冒险:pdf尝试脱下严肃的外套,说"让我也试试自由的感觉"。
以上就是springboot实现word和pdf互相转换的操作详解的详细内容,更多关于springboot word和pdf互转的资料请关注代码网其它相关文章!
发表评论