基于SpringBoot的文档导入导出系统实现方案(Word,Excel,PPT)

 更新时间:2026年03月10日 08:28:06   作者:身如柳絮随风扬  
该文章介绍了如何使用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. 技术栈选型

数据类型选用技术理由
ExcelFastExcel高性能流式读写,避免 OOM;EasyExcel 官方升级版,持续维护,未来进入 Apache 孵化器
Word (docx)Apache POI功能全面,支持模板填充,样式与数据分离
PPT (pptx)Apache POI完全控制幻灯片生成,支持文本、图片、图表
JSON/YAMLJacksonSpring 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 导入

  • URLPOST http://localhost:8080/api/import/flight-plans
  • Content-Typemultipart/form-data
  • 参数file(选择 Excel 文件)

示例 Excel 文件内容(flight_plans.xlsx):

航班号起飞时间到达时间起飞机场目的机场
CA12342026-03-06 08:00:002026-03-06 10:30:00PEKSHA
MU56782026-03-06 09:15:002026-03-06 11:45:00CANPVG

使用 Postman 测试

  • 选择 POST 请求
  • Body 标签中选择 form-data,添加 key 为 file,类型为 File,选择本地 Excel 文件
  • 发送请求,返回 "导入成功"

(2) Excel 导出

  • URLGET http://localhost:8080/api/export/flight-plans
  • 直接在浏览器中访问,或使用 Postman 发送 GET 请求,将自动下载 飞行计划.xlsx 文件。

(3) Word 导出

  • URLGET http://localhost:8080/api/export/word
  • 浏览器访问即可下载 报告.docx

(4) PPT 导出

  • URLGET http://localhost:8080/api/export/ppt
  • 浏览器访问即可下载 汇报.pptx

8. 注意事项

  1. 文件大小限制:在 application.yml 中已设置 max-file-size=10MB,可根据需要调整。
  2. 模板文件路径:Word 模板必须放在 resources/templates/ 下,确保打包后能正确读取。
  3. FastExcel 与 EasyExcel 兼容性:若老项目使用 EasyExcel,只需修改 import 包名为 cn.idev.excel,其余代码完全兼容。
  4. 中文文件名乱码:代码中使用 URLEncoder.encode 并设置 filename*=utf-8'' 解决中文乱码问题。
  5. POI 版本:推荐使用 5.2.5 或更高版本,避免旧版漏洞。
  6. 接口注入:Controller 中注入的是 Service 接口,Spring 会自动装配对应的实现类(需确保接口只有一个实现,或使用 @Primary / @Qualifier 指定)。

以上就是基于SpringBoot的文档导入导出系统实现方案的详细内容,更多关于SpringBoot文档导入导出的资料请关注脚本之家其它相关文章!

相关文章

  • java 9大性能优化经验总结

    java 9大性能优化经验总结

    这篇文章主要介绍了java 9大性能优化经验总结,包括:Java代码优化,数据库优化,分布式缓存,异步化,Web前段,搜索引擎优化等需要的朋友可以参考下
    2023-02-02
  • Java轻松使用工具类实现获取MP3音频时长

    Java轻松使用工具类实现获取MP3音频时长

    在Java中,工具类定义了一组公共方法,这篇文章将介绍Java中使用工具类来获取一个MP3音频文件的时间长度,感兴趣的同学继续往下阅读吧
    2021-10-10
  • jdk环境配置Maven环境配置实践

    jdk环境配置Maven环境配置实践

    文章介绍了如何配置JDK和Maven环境变量,并通过命令验证配置是否成功,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2026-02-02
  • IDEA Debug启动tomcat报60659端口占用错误的解决

    IDEA Debug启动tomcat报60659端口占用错误的解决

    工作中将开发工具由Eclipse转为IntelliJ IDEA,在使用过程中遇到许多问题,其中60659端口占用错误对于不熟悉IDEA的开发者来说或许会比较头痛,本文就来解决一下这个问题
    2018-11-11
  • java解析背包问题实例代码(简单易懂)

    java解析背包问题实例代码(简单易懂)

    背包问题是计算机科学中的经典问题,涉及到在给定的一组物品中选择最佳的物品组合,以使其总重量不超过背包所能承载的限制,同时获得最大的总价值,这篇文章主要介绍了java解析背包问题的相关资料,需要的朋友可以参考下
    2025-10-10
  • MyBatis Mapper.xml中的命名空间及命名方式

    MyBatis Mapper.xml中的命名空间及命名方式

    这篇文章主要介绍了MyBatis Mapper.xml中的命名空间及命名方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • 9个java数组常用操作实例

    9个java数组常用操作实例

    在本篇文章里小编给各位整理了关于java数组常用操作的实例以及相关的代码,需要的朋友们跟着学习下。
    2019-07-07
  • Java使用JSqlParser解析复杂的SQL语句的详细步骤

    Java使用JSqlParser解析复杂的SQL语句的详细步骤

    这篇文章介绍了在Java代码中使用 JSqlParser解析复杂SQL语句的相关内容,包括JSqlParser是什么及安装步骤,其使用场景如分析、转换、生成和验证SQL语句,处理SQL注入攻击的方法,以及解析复杂SQL语句的步骤、示例代码和对不同类型语句的处理,需要的朋友可以参考下
    2025-01-01
  • Activiti7与Spring以及Spring Boot整合开发

    Activiti7与Spring以及Spring Boot整合开发

    这篇文章主要介绍了Activiti7与Spring以及Spring Boot整合开发,在Activiti中核心类的是ProcessEngine流程引擎,与Spring整合就是让Spring来管理ProcessEngine,有感兴趣的同学可以参考阅读
    2023-03-03
  • 如何解决idea安装插件后报错打不开问题

    如何解决idea安装插件后报错打不开问题

    这篇文章主要介绍了如何解决idea安装插件后报错打不开问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-06-06

最新评论