java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot文档导入导出

基于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 汇报文件

2. 技术栈选型

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

3. 环境准备

4. 项目创建与配置

4.1 创建 Spring Boot 项目

使用 Spring Initializr 生成基础项目,选择:

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

模板内容示例(包含占位符):

(模板文件可使用 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 导入

示例 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 测试

(2) Excel 导出

(3) Word 导出

(4) PPT 导出

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文档导入导出的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
阅读全文