SpringBoot实现Word和PDF互相转换的操作详解
第一章: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互转的资料请关注脚本之家其它相关文章!
相关文章
maven中no main manifest attribute的问题解决
本文主要介绍了maven中no main manifest attribute的问题解决,这个错误通常意味着Spring Boot应用在启动时遇到了问题,下面就来具体介绍一下,感兴趣的可以了解一下2024-08-08
关于@Component注解下的类无法@Autowired问题
这篇文章主要介绍了关于@Component注解下的类无法@Autowired问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教2022-03-03


最新评论