跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Boot 数据导入导出与报表生成

Spring Boot 数据导入导出与报表生成涉及将系统间数据进行迁移、备份和共享。通过集成 Apache POI 可实现 Excel 文件的读写操作,利用 JasperReports 则能生成专业的 PDF 报表。本文详细讲解了从项目配置到代码实现的完整流程,涵盖依赖引入、实体类设计、业务逻辑处理及控制器接口开发,帮助开发者在实际场景中高效完成数据交互任务。

laoliangsh发布于 2026/3/24更新于 2026/8/1742 浏览
Spring Boot 数据导入导出与报表生成

Spring Boot 数据导入导出与报表生成

技术架构图

在 Java 企业级开发中,数据的交互往往离不开导入导出功能。无论是将 Excel 表格中的数据批量入库,还是将数据库中的报表导出为 PDF 供管理层查看,都是高频需求。Spring Boot 凭借其自动配置和生态丰富的特点,能让我们快速搭建起这套能力。

核心概念与场景

简单来说,数据导入导出就是把数据从一个系统搬到另一个系统,或者从系统里拿出来备份、共享。常见的格式包括 CSV、Excel、JSON 和 XML。

在实际开发中,我们主要关注以下几点:

  • 易用性:代码要简洁,开发者上手快。
  • 高效性:处理大量数据时不能卡死线程。
  • 可靠性:数据传输过程中不能丢包或损坏。

应用场景非常广泛,比如产品信息的批量录入、用户数据的迁移、订单统计报表的生成等。

集成 Apache POI 实现 Excel 操作

Apache POI 是处理 Office 文档的经典库。在 Spring Boot 中集成它并不复杂,关键在于依赖管理和文件流的处理。

1. 项目准备与依赖

首先创建一个标准的 Spring Boot 项目,并在 pom.xml 中加入 Web、JPA、H2 数据库以及 POI 相关的依赖。这里推荐使用 H2 内存数据库作为演示环境,方便快速验证。

<dependencies>
    <!-- Web 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!-- Data JPA 依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    
    
        com.h2database
        h2
        runtime
    
    
    
        org.apache.poi
        poi
        4.1.2
    
    
        org.apache.poi
        poi-ooxml
        4.1.2
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

<!-- H2 数据库依赖 -->
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<scope>
</scope>
</dependency>
<!-- Apache POI 依赖 -->
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
</dependency>
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<version>
</version>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>
</groupId>
<artifactId>
</artifactId>
<scope>
</scope>
</dependency>
</dependencies>

配置文件 application.properties 中开启 H2 控制台并设置基本连接信息:

server.port=8080
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console

2. 实体层设计

我们需要一个对应的实体类来映射数据库表。注意这里的 toString 方法需要修正,确保输出格式正确。

import javax.persistence.*;

@Entity
@Table(name = "product")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String productId;
    private String productName;
    private double price;
    private int sales;

    public Product() {}

    public Product(String productId, String productName, double price, int sales) {
        this.productId = productId;
        this.productName = productName;
        this.price = price;
        this.sales = sales;
    }

    // Getter and Setter methods omitted for brevity
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public String getProductId() { return productId; }
    public void setProductId(String productId) { this.productId = productId; }
    public String getProductName() { return productName; }
    public void setProductName(String productName) { this.productName = productName; }
    public double getPrice() { return price; }
    public void setPrice(double price) { this.price = price; }
    public int getSales() { return sales; }
    public void setSales(int sales) { this.sales = sales; }

    @Override
    public String toString() {
        return "Product{" +
                "id=" + id +
                ", productId='" + productId + '\'' +
                ", productName='" + productName + '\'' +
                ", price=" + price +
                ", sales=" + sales +
                '}';
    }
}

Repository 接口继承 JpaRepository 即可,无需额外编写 SQL。

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {}

3. 业务逻辑层 (Service)

这里是核心部分。导入时,我们需要解析 Excel 流;导出时,则需要构建 Workbook 并写入字节数组。

import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

@Service
public class ProductService {
    @Autowired
    private ProductRepository productRepository;

    @Transactional
    public void importProducts(MultipartFile file) throws IOException {
        List<Product> products = new ArrayList<>();
        Workbook workbook = new XSSFWorkbook(file.getInputStream());
        Sheet sheet = workbook.getSheetAt(0);
        Iterator<Row> iterator = sheet.iterator();
        
        if (iterator.hasNext()) {
            iterator.next(); // 跳过标题行
        }
        
        while (iterator.hasNext()) {
            Row currentRow = iterator.next();
            Product product = new Product();
            product.setProductId(currentRow.getCell(0).getStringCellValue());
            product.setProductName(currentRow.getCell(1).getStringCellValue());
            product.setPrice(currentRow.getCell(2).getNumericCellValue());
            product.setSales((int) currentRow.getCell(3).getNumericCellValue());
            products.add(product);
        }
        productRepository.saveAll(products);
        workbook.close();
    }

    @Transactional(readOnly = true)
    public byte[] exportProducts() throws IOException {
        List<Product> products = productRepository.findAll();
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Products");
        
        // 创建表头
        Row headerRow = sheet.createRow(0);
        Cell headerCell0 = headerRow.createCell(0); headerCell0.setCellValue("Product ID");
        Cell headerCell1 = headerRow.createCell(1); headerCell1.setCellValue("Product Name");
        Cell headerCell2 = headerRow.createCell(2); headerCell2.setCellValue("Price");
        Cell headerCell3 = headerRow.createCell(3); headerCell3.setCellValue("Sales");

        int rowNum = 1;
        for (Product product : products) {
            Row row = sheet.createRow(rowNum++);
            row.createCell(0).setCellValue(product.getProductId());
            row.createCell(1).setCellValue(product.getProductName());
            row.createCell(2).setCellValue(product.getPrice());
            row.createCell(3).setCellValue(product.getSales());
        }
        
        // 自动调整列宽
        for (int i = 0; i < 4; i++) {
            sheet.autoSizeColumn(i);
        }
        
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        workbook.write(outputStream);
        workbook.close();
        return outputStream.toByteArray();
    }

    @Transactional
    public Product addProduct(Product product) {
        return productRepository.save(product);
    }

    @Transactional(readOnly = true)
    public List<Product> getAllProducts() {
        return productRepository.findAll();
    }
}

4. 控制器层 (Controller)

暴露 RESTful 接口,处理文件上传和下载响应。

import org.springframework.beans.factory.annotation.Autowired;
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.IOException;
import java.util.List;

@RestController
@RequestMapping("/api/products")
public class ProductController {
    @Autowired
    private ProductService productService;

    @PostMapping("/import")
    public ResponseEntity<String> importProducts(@RequestParam("file") MultipartFile file) {
        try {
            productService.importProducts(file);
            return ResponseEntity.ok("数据导入成功");
        } catch (IOException e) {
            e.printStackTrace();
            return ResponseEntity.status(500).body("数据导入失败:" + e.getMessage());
        }
    }

    @GetMapping("/export")
    public ResponseEntity<byte[]> exportProducts() throws IOException {
        byte[] bytes = productService.exportProducts();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.parseMediaType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"));
        headers.setContentDispositionFormData("attachment", "products.xlsx");
        headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
        return ResponseEntity.ok().headers(headers).body(bytes);
    }

    @PostMapping("/")
    public Product addProduct(@RequestBody Product product) {
        return productService.addProduct(product);
    }

    @GetMapping("/")
    public List<Product> getAllProducts() {
        return productService.getAllProducts();
    }
}

启动应用后,可以通过 Postman 或浏览器访问 /api/products/export 下载 Excel,通过 POST 请求 /api/products/import 上传 Excel 文件进行导入。

使用 JasperReports 生成 PDF 报表

如果需要更专业的报表格式(如 PDF),JasperReports 是个不错的选择。它支持复杂的布局设计和模板化生成。

1. 引入依赖

除了基础依赖外,还需要添加 JasperReports 的核心库和字体包。

<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports</artifactId>
    <version>6.17.0</version>
</dependency>
<dependency>
    <groupId>net.sf.jasperreports</groupId>
    <artifactId>jasperreports-fonts</artifactId>
    <version>6.17.0</version>
</dependency>

2. 报表服务实现

我们需要加载预定义的 .jasper 模板文件,传入数据源进行填充。

import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ReportService {
    @Autowired
    private ProductRepository productRepository;

    public byte[] generateProductReport() throws JRException {
        List<Product> products = productRepository.findAll();
        
        // 加载 Jasper 模板
        InputStream templateStream = getClass().getResourceAsStream("/reports/product-report.jasper");
        JasperReport jasperReport = (JasperReport) JRLoader.loadObject(templateStream);
        
        // 设置参数
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("Title", "产品销售报表");
        
        // 设置数据源
        JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(products);
        
        // 生成报表
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
        
        // 导出为 PDF
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
        return outputStream.toByteArray();
    }
}

3. 新增报表接口

在 Controller 中添加一个新的 GET 端点来触发报表生成。

@GetMapping("/report")
public ResponseEntity<byte[]> generateProductReport() throws JRException {
    byte[] bytes = reportService.generateProductReport();
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.parseMediaType("application/pdf"));
    headers.setContentDispositionFormData("attachment", "product-report.pdf");
    headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
    return ResponseEntity.ok().headers(headers).body(bytes);
}

总结

通过以上步骤,我们完成了 Spring Boot 项目中数据导入导出与报表生成的完整闭环。Apache POI 适合处理 Excel 格式的轻量级数据交换,而 JasperReports 则更适合生成正式的业务报表。实际开发中,根据具体需求选择合适的工具,并注意异常处理和资源关闭,就能构建出稳定可靠的数据交互模块。

目录

  1. Spring Boot 数据导入导出与报表生成
  2. 核心概念与场景
  3. 集成 Apache POI 实现 Excel 操作
  4. 1. 项目准备与依赖
  5. 2. 实体层设计
  6. 3. 业务逻辑层 (Service)
  7. 4. 控制器层 (Controller)
  8. 使用 JasperReports 生成 PDF 报表
  9. 1. 引入依赖
  10. 2. 报表服务实现
  11. 3. 新增报表接口
  12. 总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • Vivado 中 ILA 集成逻辑分析仪在线调试方法
  • 动手学大模型应用开发:从零构建个人知识库助手
  • Unity 无人机物理模拟开发:打造穿越机真实手感
  • JetBrains 中 GitHub Copilot Agent Mode 与 MCP 配置实战
  • 昇腾 NPU 实战指南:部署与推理 CodeLlama
  • 前端核心面试题与实战指南
  • 大规模无人机检测数据集:11998 张图像支持 YOLOv8 等多格式训练
  • 电信行业数据分析的主要应用场景与价值分析
  • 大模型 API 实战:打造带 RAG 的电商客服机器人
  • Anaconda 与 Python 环境安装及配置指南
  • Windows 下 VSCode 配置 C/C++ 开发环境指南
  • 知网、维普、万方三大平台 AIGC 检测算法对比
  • WebGoat 安全靶场环境搭建与实战指南
  • 基于 Docker 和 Ollama 的 DeepSeek 本地大模型部署指南
  • Nginx 部署前端 Vue 项目实战指南
  • 大模型领域必须掌握的30个核心概念解析
  • Anaconda 安装与环境配置详解
  • ERNIE-4.5-0.3B 轻量化部署与效能优化实战
  • Python 办公自动化:Word 文档操作与报告生成
  • 基于 LangChain 实现的知识库问答工具

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online