基于SpringBoot的文档导入导出系统实现方案(Word,Excel,PPT)
作者:身如柳絮随风扬
该文章介绍了如何使用Spring Boot和相关技术栈实现一个文档导出系统,该系统支持Excel、Word和PPT的导入和导出功能,系统采用分层架构,包括实体类、服务层和控制器层,文章详细描述了项目的创建、配置、代码实现以及运行测试的步骤,需要的朋友可以参考下
1. 项目概述
实现以下功能接口:
| 功能 | 请求方式 | 访问路径 | 说明 |
|---|---|---|---|
| Excel 导入 | POST | /api/import/flight-plans | 上传 Excel 文件批量导入 |
| Excel 导出 | GET | /api/export/flight-plans | 下载所有 Excel 文件 |
| Word 导出(模板) | GET | /api/export/word | 下载动态生成的 Word 报告 |
| PPT 导出 | GET | /api/export/ppt | 下载动态生成的 PPT 汇报文件 |
- 默认端口:
8080 - 基础路径:
http://localhost:8080
2. 技术栈选型
| 数据类型 | 选用技术 | 理由 |
|---|---|---|
| Excel | FastExcel | 高性能流式读写,避免 OOM;EasyExcel 官方升级版,持续维护,未来进入 Apache 孵化器 |
| Word (docx) | Apache POI | 功能全面,支持模板填充,样式与数据分离 |
| PPT (pptx) | Apache POI | 完全控制幻灯片生成,支持文本、图片、图表 |
| JSON/YAML | Jackson | Spring Boot 默认集成,性能优异 |
3. 环境准备
- JDK 17 或更高版本
- Maven 3.8+ 或 Gradle
- IDE(推荐 IntelliJ IDEA)
- Postman 或浏览器用于测试
4. 项目创建与配置
4.1 创建 Spring Boot 项目
使用 Spring Initializr 生成基础项目,选择:
- Project:Maven
- Language:Java 17
- Spring Boot:3.5.11
- Dependencies:Spring Web、Lombok
4.2 添加依赖(pom.xml)
<?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>3.5.11</version>
<relativePath/>
</parent>
<groupId>com.example</groupId>
<artifactId>document-export-demo</artifactId>
<version>1.0.0</version>
<name>document-export-demo</name>
<description>文档导入导出示例</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Lombok 简化代码 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- FastExcel (替代 EasyExcel) -->
<dependency>
<groupId>cn.idev.excel</groupId>
<artifactId>fastexcel</artifactId>
<version>1.1.0</version>
</dependency>
<!-- Apache POI 处理 Word/PPT -->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.5</version>
</dependency>
<!-- 测试依赖(可选) -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.3 配置文件(application.yml)
server:
port: 8080
spring:
servlet:
multipart:
max-file-size: 10MB # 最大上传文件大小
max-request-size: 10MB
# 日志级别(可选,便于调试)
logging:
level:
com.example: debug
5. 代码实现(分层架构)
5.1 实体类(FlightPlan.java)
package com.example.entity;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class FlightPlan {
@ExcelProperty("航班号")
private String flightNo;
@ExcelProperty("起飞时间")
private LocalDateTime departureTime;
@ExcelProperty("到达时间")
private LocalDateTime arrivalTime;
@ExcelProperty("起飞机场")
private String departureAirport;
@ExcelProperty("目的机场")
private String arrivalAirport;
}
5.2 Excel 导入监听器(FlightPlanReadListener.java)
package com.example.listener;
import cn.idev.excel.context.AnalysisContext;
import cn.idev.excel.event.AnalysisEventListener;
import com.example.entity.FlightPlan;
import com.example.service.FlightPlanService;
import lombok.extern.slf4j.Slf4j;
import java.util.ArrayList;
import java.util.List;
@Slf4j
public class FlightPlanReadListener extends AnalysisEventListener<FlightPlan> {
private static final int BATCH_COUNT = 100;
private final List<FlightPlan> cache = new ArrayList<>();
private final FlightPlanService flightPlanService;
public FlightPlanReadListener(FlightPlanService flightPlanService) {
this.flightPlanService = flightPlanService;
}
@Override
public void invoke(FlightPlan data, AnalysisContext context) {
cache.add(data);
if (cache.size() >= BATCH_COUNT) {
saveData();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
saveData();
log.info("所有数据解析完成,共导入 {} 条", cache.size());
}
private void saveData() {
flightPlanService.batchInsert(cache);
cache.clear();
}
}
5.3 Service 层接口与实现
5.3.1 航班计划服务接口(FlightPlanService.java)
package com.example.service;
import com.example.entity.FlightPlan;
import java.util.List;
public interface FlightPlanService {
/**
* 批量插入航班计划
*/
void batchInsert(List<FlightPlan> plans);
/**
* 查询所有航班计划
*/
List<FlightPlan> listAll();
}
5.3.2 航班计划服务实现(FlightPlanServiceImpl.java)
package com.example.service.impl;
import com.example.entity.FlightPlan;
import com.example.service.FlightPlanService;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
@Service
public class FlightPlanServiceImpl implements FlightPlanService {
// 模拟数据库存储(线程安全)
private final List<FlightPlan> storage = new CopyOnWriteArrayList<>();
@Override
public void batchInsert(List<FlightPlan> plans) {
storage.addAll(plans);
}
@Override
public List<FlightPlan> listAll() {
return new ArrayList<>(storage);
}
}
5.3.3 Word 导出服务接口(WordExportService.java)
package com.example.service;
import java.io.ByteArrayOutputStream;
import java.util.Map;
public interface WordExportService {
/**
* 根据模板和数据生成 Word 文档
* @param data 占位符数据
* @return 包含文档内容的字节流
*/
ByteArrayOutputStream generateWord(Map<String, Object> data) throws Exception;
}
5.3.4 Word 导出服务实现(WordExportServiceImpl.java)
package com.example.service.impl;
import com.example.service.WordExportService;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import java.io.*;
import java.util.List;
import java.util.Map;
@Service
public class WordExportServiceImpl implements WordExportService {
@Override
public ByteArrayOutputStream generateWord(Map<String, Object> data) throws Exception {
ClassPathResource resource = new ClassPathResource("templates/report_template.docx");
try (InputStream is = resource.getInputStream();
XWPFDocument doc = new XWPFDocument(is);
ByteArrayOutputStream out = new ByteArrayOutputStream()) {
// 替换段落中的占位符
replaceParagraphs(doc.getParagraphs(), data);
// 处理表格(示例:如果模板中有表格,可动态生成行)
for (XWPFTable table : doc.getTables()) {
processTable(table, data);
}
doc.write(out);
return out;
}
}
private void replaceParagraphs(List<XWPFParagraph> paragraphs, Map<String, Object> data) {
for (XWPFParagraph p : paragraphs) {
for (XWPFRun run : p.getRuns()) {
String text = run.getText(0);
if (text != null) {
for (Map.Entry<String, Object> entry : data.entrySet()) {
text = text.replace("${" + entry.getKey() + "}", entry.getValue().toString());
}
run.setText(text, 0);
}
}
}
}
private void processTable(XWPFTable table, Map<String, Object> data) {
// 示例:假设表格第一行为标题,第二行为模板行,根据数据循环复制
// 这里简化,仅演示占位符替换(如表格单元格中的 ${item})
for (XWPFTableRow row : table.getRows()) {
for (XWPFTableCell cell : row.getTableCells()) {
for (XWPFParagraph p : cell.getParagraphs()) {
replaceParagraphs(List.of(p), data);
}
}
}
}
}
5.3.5 PPT 导出服务接口(PPTExportService.java)
package com.example.service;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public interface PPTExportService {
/**
* 生成 PPT 文档
*/
ByteArrayOutputStream generatePPT() throws IOException;
}
5.3.6 PPT 导出服务实现(PPTExportServiceImpl.java)
package com.example.service.impl;
import com.example.service.PPTExportService;
import org.apache.poi.xslf.usermodel.*;
import org.springframework.stereotype.Service;
import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
@Service
public class PPTExportServiceImpl implements PPTExportService {
@Override
public ByteArrayOutputStream generatePPT() throws IOException {
XMLSlideShow ppt = new XMLSlideShow();
XSLFSlide slide = ppt.createSlide();
// 添加标题
XSLFTextShape title = slide.createAutoShape();
title.setText("飞行数据汇报");
title.setAnchor(new Rectangle(50, 50, 500, 60));
// 添加内容文本框
XSLFTextBox textBox = slide.createTextBox();
textBox.setAnchor(new Rectangle(50, 150, 500, 200));
textBox.setText("飞行小时:1250\n告警次数:23\n航班数量:45");
// 可继续添加更多幻灯片或图表
ByteArrayOutputStream out = new ByteArrayOutputStream();
ppt.write(out);
ppt.close();
return out;
}
}
5.4 Controller 层(DocumentController.java)
package com.example.controller;
import cn.idev.excel.FastExcel;
import com.example.entity.FlightPlan;
import com.example.listener.FlightPlanReadListener;
import com.example.service.FlightPlanService;
import com.example.service.WordExportService;
import com.example.service.PPTExportService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class DocumentController {
private final FlightPlanService flightPlanService;
private final WordExportService wordExportService;
private final PPTExportService pptExportService;
/**
* Excel 导入
* POST /api/import/flight-plans
*/
@PostMapping("/import/flight-plans")
public String importFlightPlans(@RequestParam("file") MultipartFile file) throws IOException {
FastExcel.read(file.getInputStream(), FlightPlan.class,
new FlightPlanReadListener(flightPlanService)).sheet().doRead();
return "导入成功";
}
/**
* Excel 导出
* GET /api/export/flight-plans
*/
@GetMapping("/export/flight-plans")
public void exportFlightPlans(HttpServletResponse response) throws IOException {
List<FlightPlan> list = flightPlanService.listAll();
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode("飞行计划", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
FastExcel.write(response.getOutputStream(), FlightPlan.class)
.sheet("飞行计划").doWrite(list);
}
/**
* Word 导出(基于模板)
* GET /api/export/word
*/
@GetMapping("/export/word")
public ResponseEntity<byte[]> exportWord() throws Exception {
Map<String, Object> data = new HashMap<>();
data.put("title", "飞行计划报告");
data.put("date", "2026-03-06");
// 可添加更多动态数据,如飞行列表等
ByteArrayOutputStream baos = wordExportService.generateWord(data);
String filename = URLEncoder.encode("报告.docx", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + filename)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(baos.toByteArray());
}
/**
* PPT 导出
* GET /api/export/ppt
*/
@GetMapping("/export/ppt")
public ResponseEntity<byte[]> exportPPT() throws IOException {
ByteArrayOutputStream baos = pptExportService.generatePPT();
String filename = URLEncoder.encode("汇报.pptx", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename*=utf-8''" + filename)
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(baos.toByteArray());
}
}
5.5 启动类(DocumentExportDemoApplication.java)
package com.example;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class DocumentExportDemoApplication {
public static void main(String[] args) {
SpringApplication.run(DocumentExportDemoApplication.class, args);
}
}
6. 资源文件:Word 模板
在 src/main/resources/templates/ 目录下创建 report_template.docx。
模板内容示例(包含占位符):
- 第一行:
${title} - 第二行:
日期:${date} - 可包含一个表格,第一行为标题行,第二行为数据行(例如:
${flightNo}、${departure}等),后续可由代码动态复制生成多行。
(模板文件可使用 Microsoft Word 编辑,保存为 .docx 格式。)
7. 运行与测试
7.1 启动应用
在 IDE 中运行 DocumentExportDemoApplication.main(),或使用 Maven 命令:
mvn spring-boot:run
控制台输出类似以下内容表示启动成功:
Started DocumentExportDemoApplication in 2.345 seconds (process running at ...)
7.2 测试接口
(1) Excel 导入
- URL:
POST http://localhost:8080/api/import/flight-plans - Content-Type:
multipart/form-data - 参数:
file(选择 Excel 文件)
示例 Excel 文件内容(flight_plans.xlsx):
| 航班号 | 起飞时间 | 到达时间 | 起飞机场 | 目的机场 |
|---|---|---|---|---|
| CA1234 | 2026-03-06 08:00:00 | 2026-03-06 10:30:00 | PEK | SHA |
| MU5678 | 2026-03-06 09:15:00 | 2026-03-06 11:45:00 | CAN | PVG |
使用 Postman 测试:
- 选择
POST请求 - 在
Body标签中选择form-data,添加 key 为file,类型为File,选择本地 Excel 文件 - 发送请求,返回
"导入成功"

(2) Excel 导出
- URL:
GET http://localhost:8080/api/export/flight-plans - 直接在浏览器中访问,或使用 Postman 发送 GET 请求,将自动下载
飞行计划.xlsx文件。
(3) Word 导出
- URL:
GET http://localhost:8080/api/export/word - 浏览器访问即可下载
报告.docx。
(4) PPT 导出
- URL:
GET http://localhost:8080/api/export/ppt - 浏览器访问即可下载
汇报.pptx。
8. 注意事项
- 文件大小限制:在
application.yml中已设置max-file-size=10MB,可根据需要调整。 - 模板文件路径:Word 模板必须放在
resources/templates/下,确保打包后能正确读取。 - FastExcel 与 EasyExcel 兼容性:若老项目使用 EasyExcel,只需修改
import包名为cn.idev.excel,其余代码完全兼容。 - 中文文件名乱码:代码中使用
URLEncoder.encode并设置filename*=utf-8''解决中文乱码问题。 - POI 版本:推荐使用 5.2.5 或更高版本,避免旧版漏洞。
- 接口注入:Controller 中注入的是 Service 接口,Spring 会自动装配对应的实现类(需确保接口只有一个实现,或使用
@Primary/@Qualifier指定)。
以上就是基于SpringBoot的文档导入导出系统实现方案的详细内容,更多关于SpringBoot文档导入导出的资料请关注脚本之家其它相关文章!
