基于SpringBoot的文檔導(dǎo)入導(dǎo)出系統(tǒng)實(shí)現(xiàn)方案(Word,Excel,PPT)
1. 項(xiàng)目概述
實(shí)現(xiàn)以下功能接口:
| 功能 | 請(qǐng)求方式 | 訪問路徑 | 說明 |
|---|---|---|---|
| Excel 導(dǎo)入 | POST | /api/import/flight-plans | 上傳 Excel 文件批量導(dǎo)入 |
| Excel 導(dǎo)出 | GET | /api/export/flight-plans | 下載所有 Excel 文件 |
| Word 導(dǎo)出(模板) | GET | /api/export/word | 下載動(dòng)態(tài)生成的 Word 報(bào)告 |
| PPT 導(dǎo)出 | GET | /api/export/ppt | 下載動(dòng)態(tài)生成的 PPT 匯報(bào)文件 |
- 默認(rèn)端口:
8080 - 基礎(chǔ)路徑:
http://localhost:8080
2. 技術(shù)棧選型
| 數(shù)據(jù)類型 | 選用技術(shù) | 理由 |
|---|---|---|
| Excel | FastExcel | 高性能流式讀寫,避免 OOM;EasyExcel 官方升級(jí)版,持續(xù)維護(hù),未來進(jìn)入 Apache 孵化器 |
| Word (docx) | Apache POI | 功能全面,支持模板填充,樣式與數(shù)據(jù)分離 |
| PPT (pptx) | Apache POI | 完全控制幻燈片生成,支持文本、圖片、圖表 |
| JSON/YAML | Jackson | Spring Boot 默認(rèn)集成,性能優(yōu)異 |
3. 環(huán)境準(zhǔn)備
- JDK 17 或更高版本
- Maven 3.8+ 或 Gradle
- IDE(推薦 IntelliJ IDEA)
- Postman 或?yàn)g覽器用于測(cè)試
4. 項(xiàng)目創(chuàng)建與配置
4.1 創(chuàng)建 Spring Boot 項(xiàng)目
使用 Spring Initializr 生成基礎(chǔ)項(xiàng)目,選擇:
- 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>文檔導(dǎo)入導(dǎo)出示例</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 簡(jiǎn)化代碼 -->
<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>
<!-- 測(cè)試依賴(可選) -->
<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
# 日志級(jí)別(可選,便于調(diào)試)
logging:
level:
com.example: debug
5. 代碼實(shí)現(xiàn)(分層架構(gòu))
5.1 實(shí)體類(FlightPlan.java)
package com.example.entity;
import cn.idev.excel.annotation.ExcelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
public class FlightPlan {
@ExcelProperty("航班號(hào)")
private String flightNo;
@ExcelProperty("起飛時(shí)間")
private LocalDateTime departureTime;
@ExcelProperty("到達(dá)時(shí)間")
private LocalDateTime arrivalTime;
@ExcelProperty("起飛機(jī)場(chǎng)")
private String departureAirport;
@ExcelProperty("目的機(jī)場(chǎng)")
private String arrivalAirport;
}
5.2 Excel 導(dǎo)入監(jiān)聽器(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("所有數(shù)據(jù)解析完成,共導(dǎo)入 {} 條", cache.size());
}
private void saveData() {
flightPlanService.batchInsert(cache);
cache.clear();
}
}
5.3 Service 層接口與實(shí)現(xiàn)
5.3.1 航班計(jì)劃服務(wù)接口(FlightPlanService.java)
package com.example.service;
import com.example.entity.FlightPlan;
import java.util.List;
public interface FlightPlanService {
/**
* 批量插入航班計(jì)劃
*/
void batchInsert(List<FlightPlan> plans);
/**
* 查詢所有航班計(jì)劃
*/
List<FlightPlan> listAll();
}
5.3.2 航班計(jì)劃服務(wù)實(shí)現(xiàn)(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 {
// 模擬數(shù)據(jù)庫(kù)存儲(chǔ)(線程安全)
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 導(dǎo)出服務(wù)接口(WordExportService.java)
package com.example.service;
import java.io.ByteArrayOutputStream;
import java.util.Map;
public interface WordExportService {
/**
* 根據(jù)模板和數(shù)據(jù)生成 Word 文檔
* @param data 占位符數(shù)據(jù)
* @return 包含文檔內(nèi)容的字節(jié)流
*/
ByteArrayOutputStream generateWord(Map<String, Object> data) throws Exception;
}
5.3.4 Word 導(dǎo)出服務(wù)實(shí)現(xiàn)(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);
// 處理表格(示例:如果模板中有表格,可動(dòng)態(tài)生成行)
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) {
// 示例:假設(shè)表格第一行為標(biāo)題,第二行為模板行,根據(jù)數(shù)據(jù)循環(huán)復(fù)制
// 這里簡(jiǎn)化,僅演示占位符替換(如表格單元格中的 ${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 導(dǎo)出服務(wù)接口(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 導(dǎo)出服務(wù)實(shí)現(xiàn)(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();
// 添加標(biāo)題
XSLFTextShape title = slide.createAutoShape();
title.setText("飛行數(shù)據(jù)匯報(bào)");
title.setAnchor(new Rectangle(50, 50, 500, 60));
// 添加內(nèi)容文本框
XSLFTextBox textBox = slide.createTextBox();
textBox.setAnchor(new Rectangle(50, 150, 500, 200));
textBox.setText("飛行小時(shí):1250\n告警次數(shù):23\n航班數(shù)量:45");
// 可繼續(xù)添加更多幻燈片或圖表
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 導(dǎo)入
* 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 "導(dǎo)入成功";
}
/**
* Excel 導(dǎo)出
* 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("飛行計(jì)劃", StandardCharsets.UTF_8)
.replaceAll("\\+", "%20");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
FastExcel.write(response.getOutputStream(), FlightPlan.class)
.sheet("飛行計(jì)劃").doWrite(list);
}
/**
* Word 導(dǎo)出(基于模板)
* GET /api/export/word
*/
@GetMapping("/export/word")
public ResponseEntity<byte[]> exportWord() throws Exception {
Map<String, Object> data = new HashMap<>();
data.put("title", "飛行計(jì)劃報(bào)告");
data.put("date", "2026-03-06");
// 可添加更多動(dòng)態(tài)數(shù)據(jù),如飛行列表等
ByteArrayOutputStream baos = wordExportService.generateWord(data);
String filename = URLEncoder.encode("報(bào)告.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 導(dǎo)出
* GET /api/export/ppt
*/
@GetMapping("/export/ppt")
public ResponseEntity<byte[]> exportPPT() throws IOException {
ByteArrayOutputStream baos = pptExportService.generatePPT();
String filename = URLEncoder.encode("匯報(bào).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 啟動(dòng)類(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/ 目錄下創(chuàng)建 report_template.docx。
模板內(nèi)容示例(包含占位符):
- 第一行:
${title} - 第二行:
日期:${date} - 可包含一個(gè)表格,第一行為標(biāo)題行,第二行為數(shù)據(jù)行(例如:
${flightNo}、${departure}等),后續(xù)可由代碼動(dòng)態(tài)復(fù)制生成多行。
(模板文件可使用 Microsoft Word 編輯,保存為 .docx 格式。)
7. 運(yùn)行與測(cè)試
7.1 啟動(dòng)應(yīng)用
在 IDE 中運(yùn)行 DocumentExportDemoApplication.main(),或使用 Maven 命令:
mvn spring-boot:run
控制臺(tái)輸出類似以下內(nèi)容表示啟動(dòng)成功:
Started DocumentExportDemoApplication in 2.345 seconds (process running at ...)
7.2 測(cè)試接口
(1) Excel 導(dǎo)入
- URL:
POST http://localhost:8080/api/import/flight-plans - Content-Type:
multipart/form-data - 參數(shù):
file(選擇 Excel 文件)
示例 Excel 文件內(nèi)容(flight_plans.xlsx):
| 航班號(hào) | 起飛時(shí)間 | 到達(dá)時(shí)間 | 起飛機(jī)場(chǎng) | 目的機(jī)場(chǎng) |
|---|---|---|---|---|
| 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 測(cè)試:
- 選擇
POST請(qǐng)求 - 在
Body標(biāo)簽中選擇form-data,添加 key 為file,類型為File,選擇本地 Excel 文件 - 發(fā)送請(qǐng)求,返回
"導(dǎo)入成功"

(2) Excel 導(dǎo)出
- URL:
GET http://localhost:8080/api/export/flight-plans - 直接在瀏覽器中訪問,或使用 Postman 發(fā)送 GET 請(qǐng)求,將自動(dòng)下載
飛行計(jì)劃.xlsx文件。
(3) Word 導(dǎo)出
- URL:
GET http://localhost:8080/api/export/word - 瀏覽器訪問即可下載
報(bào)告.docx。
(4) PPT 導(dǎo)出
- URL:
GET http://localhost:8080/api/export/ppt - 瀏覽器訪問即可下載
匯報(bào).pptx。
8. 注意事項(xiàng)
- 文件大小限制:在
application.yml中已設(shè)置max-file-size=10MB,可根據(jù)需要調(diào)整。 - 模板文件路徑:Word 模板必須放在
resources/templates/下,確保打包后能正確讀取。 - FastExcel 與 EasyExcel 兼容性:若老項(xiàng)目使用 EasyExcel,只需修改
import包名為cn.idev.excel,其余代碼完全兼容。 - 中文文件名亂碼:代碼中使用
URLEncoder.encode并設(shè)置filename*=utf-8''解決中文亂碼問題。 - POI 版本:推薦使用 5.2.5 或更高版本,避免舊版漏洞。
- 接口注入:Controller 中注入的是 Service 接口,Spring 會(huì)自動(dòng)裝配對(duì)應(yīng)的實(shí)現(xiàn)類(需確保接口只有一個(gè)實(shí)現(xiàn),或使用
@Primary/@Qualifier指定)。
以上就是基于SpringBoot的文檔導(dǎo)入導(dǎo)出系統(tǒng)實(shí)現(xiàn)方案的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot文檔導(dǎo)入導(dǎo)出的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
在Spring Boot2中使用CompletableFuture的方法教程
這篇文章主要給大家介紹了關(guān)于在Spring Boot2中使用CompletableFuture的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起看看吧2019-01-01
Java將時(shí)間戳轉(zhuǎn)換為Date對(duì)象的方法小結(jié)
在?Java?編程中,處理日期和時(shí)間是一個(gè)常見需求,特別是在處理網(wǎng)絡(luò)通信或者數(shù)據(jù)庫(kù)操作時(shí),本文主要為大家整理了Java中將時(shí)間戳轉(zhuǎn)換為Date對(duì)象的方法,希望對(duì)大家有所幫助2024-12-12
Mybatisplus創(chuàng)建Spring?Boot工程打包錯(cuò)誤的解決方式
最近在實(shí)戰(zhàn)springboot遇到了一些坑,記錄一下,下面這篇文章主要給大家介紹了關(guān)于Mybatisplus創(chuàng)建Spring?Boot工程打包錯(cuò)誤的解決方式,文中通過圖文介紹的介紹的非常詳細(xì),需要的朋友可以參考下2023-03-03
IntelliJ IDEA快速創(chuàng)建getter和setter方法
這篇文章主要介紹了IntelliJ IDEA快速創(chuàng)建getter和setter方法,本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
java定時(shí)任務(wù)Timer和TimerTask使用詳解
這篇文章主要為大家詳細(xì)介紹了java定時(shí)任務(wù)Timer和TimerTask使用方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
Java遍歷Properties所有元素的方法實(shí)例
這篇文章主要介紹了Java如何遍歷Properties所有元素的方法,大家可以參考使用2013-11-11

