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

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

Spring Boot 数据导入导出与报表生成实战。通过 Apache POI 实现 Excel 数据的读写,利用 JasperReports 生成 PDF 报表。涵盖依赖配置、实体映射、服务层逻辑及控制器接口设计。实际开发中需根据场景选择合适工具,注意异常处理与性能优化。

莫名其妙发布于 2026/3/28更新于 2026/6/215 浏览
Spring Boot 数据导入导出与报表生成实战

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

在业务开发中,数据的批量处理与可视化展示是高频需求。无论是将 Excel 数据导入系统,还是生成 PDF 报表供管理层查看,都需要一套稳定高效的方案。本文将结合 Apache POI 和 JasperReports,演示如何在 Spring Boot 中实现这些功能。

1. Excel 数据导入导出(Apache POI)

Excel 是最通用的数据交换格式。集成 Apache POI 的核心在于解析文件流并映射到实体对象。

1.1 依赖配置

首先在 pom.xml 中加入 Web、JPA 以及 POI 的依赖:

<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>
    <!-- H2 数据库依赖 -->
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </>
    
    
        org.apache.poi
        poi
        4.1.2
    
    
        org.apache.poi
        poi-ooxml
        4.1.2
    
    
    
        org.springframework.boot
        spring-boot-starter-test
        test
    

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>

1.2 核心代码实现

实体类定义 注意字段类型与 Excel 列的对应关系:

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;

    // Getter 和 Setter 方法省略,实际开发建议使用 Lombok
}

服务层逻辑 这里展示了导入导出的关键流程。导入时跳过表头,导出时自动调整列宽。

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();
    }
}

控制器接口 处理文件上传和响应下载流:

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;

@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) {
            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");
        return ResponseEntity.ok().headers(headers).body(bytes);
    }
}

2. 报表生成(JasperReports)

对于需要固定格式、打印友好的场景,PDF 报表是更好的选择。JasperReports 提供了强大的模板引擎支持。

2.1 依赖配置

<dependencies>
    <!-- ... 其他基础依赖 ... -->
    <!-- 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>
</dependencies>

2.2 报表服务实现

加载预编译的 .jasper 模板,填充数据源后导出为 PDF。

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.Map;

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

    public byte[] generateProductReport() throws JRException {
        var 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();
    }
}

配合 Controller 中的 /report 接口即可触发下载。

3. 总结

在实际项目中,数据导入导出与报表生成往往并存。Apache POI 适合灵活的数据交互,而 JasperReports 更适合正式的业务报表。开发时需注意异常处理、大文件内存优化以及字符编码问题,确保系统的稳定性。

目录

  1. Spring Boot 数据导入导出与报表生成
  2. 1. Excel 数据导入导出(Apache POI)
  3. 1.1 依赖配置
  4. 1.2 核心代码实现
  5. 2. 报表生成(JasperReports)
  6. 2.1 依赖配置
  7. 2.2 报表服务实现
  8. 3. 总结
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

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

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

更多推荐文章

查看全部
  • 使用 AI 视觉编程模型优化 Unity 编辑器插件:从功能实现到界面美化
  • 高校论文 AI 检测率标准汇总:30%、20%、10% 解析
  • C++ 基础实战:从循环控制到算法入门
  • F5 刷新背后:浏览器缓存策略与渲染流程深度解析
  • 利用闲置小米 9 打造安卓复古掌机:天马 G 前端实战
前端海报生成技术对比:Snapdom 与 Html2Canvas 选型指南
  • 模型预测控制(MPC)算法原理与实战入门
  • C++ 继承入门:从基础概念到默认成员函数,掌握类复用核心
  • Edict:基于三省六部制的 AI Agent 协作框架
  • SpringBoot 整合 Langchain4j 对接主流大模型实战详解
  • 前端图像生成性能瓶颈的五大解决方案
  • Spring Boot 配置与扩展方式详解
  • 基于 Lucene 构建自定义推荐引擎方案
  • ALEPython 机器学习模型解释与特征分析指南
  • Web JS 逆向全体系详解:原理、工具与实战
  • AI 办公提效指南:7 本精选书籍推荐
  • Linux 文件操作:系统调用与标准库函数接口汇总及代码示例
  • 2026年全球AI大模型深度研究报告
  • 汽车雷达多径幽灵目标检测:GLRT 与稀疏压缩感知解析
  • CTFShow Web 入门命令执行 29-124 全通关详解
  • 相关免费在线工具

    • 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