跳到主要内容
Spring Boot 数据导入导出与报表生成实战 | 极客日志
Java java
Spring Boot 数据导入导出与报表生成实战 综述由AI生成 演示了如何在 Spring Boot 项目中实现数据导入导出与报表生成功能。通过集成 Apache POI 库,实现了 Excel 文件的读取与写入,支持批量导入产品数据及导出查询结果。同时结合 JasperReports 引擎,展示了如何加载模板生成 PDF 格式的销售报表。代码涵盖了依赖配置、实体定义、Service 层流处理及 Controller 接口暴露,适用于企业级数据迁移、备份及统计场景。
念念不忘 发布于 2026/3/15 更新于 2026/4/26 3 浏览Spring Boot 数据导入导出与报表生成
在企业级开发中,数据的批量处理与可视化展示是高频需求。无论是将 Excel 表格导入数据库进行初始化,还是从系统导出报表供管理层查看,都需要稳定高效的解决方案。本文将结合 Apache POI 和 JasperReports,演示如何在 Spring Boot 项目中实现 Excel 的导入导出以及 PDF 报表的生成。
一、Excel 数据导入导出 (Apache POI)
1. 依赖配置
首先需要在 pom.xml 中添加 Web、JPA、H2 测试库以及 Apache POI 的核心依赖。这里我们使用 H2 内存数据库以便快速验证逻辑。
<dependencies >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-web</artifactId >
</dependency >
<dependency >
<groupId > org.springframework.boot</groupId >
<artifactId > spring-boot-starter-data-jpa</artifactId >
</dependency >
<dependency >
<groupId > com.h2database</groupId >
<artifactId > h2</artifactId >
runtime
org.apache.poi
poi
4.1.2
org.apache.poi
poi-ooxml
4.1.2
org.springframework.boot
spring-boot-starter-test
test
<scope >
</scope >
</dependency >
<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 >
2. 基础配置与实体类 在 application.properties 中开启 H2 控制台并配置 JPA 行为:
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
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;
}
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; }
}
配合标准的 Repository 接口即可开始业务层开发。
3. 核心 Service 实现 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 负责接收文件上传请求或返回下载流。注意设置正确的 Content-Type 和响应头。
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() {
try {
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);
} catch (IOException e) {
e.printStackTrace();
return ResponseEntity.status(500 ).body(null );
}
}
@PostMapping("/")
public Product addProduct (@RequestBody Product product) {
return productService.addProduct(product);
}
@GetMapping("/")
public List<Product> getAllProducts () {
return productService.getAllProducts();
}
}
二、PDF 报表生成 (JasperReports) 对于需要打印或正式归档的场景,PDF 格式更为合适。JasperReports 是 Java 生态中成熟的报表引擎。
1. 添加依赖 <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 模板文件(通常由 .jrxml 编译而来),放在 resources/reports/ 目录下。
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 org.springframework.transaction.annotation.Transactional;
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;
@Transactional(readOnly = true)
public byte [] generateProductReport() throws JRException {
List<Product> products = productRepository.findAll();
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);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream ();
JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
return outputStream.toByteArray();
}
}
3. 集成到 Controller 只需在原有的 Controller 中注入 ReportService 并新增一个 GET 接口即可。
@GetMapping("/report")
public ResponseEntity<byte []> generateProductReport() {
try {
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);
} catch (JRException e) {
e.printStackTrace();
return ResponseEntity.status(500 ).body(null );
}
}
三、应用启动与测试 为了让应用启动时自动初始化一些测试数据,建议实现 CommandLineRunner 接口,而不是在 main 方法中直接操作 Bean。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProductApplication implements CommandLineRunner {
@Autowired
private ProductService productService;
public static void main (String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
@Override
public void run (String... args) throws Exception {
productService.addProduct(new Product ("P001" , "手机" , 1000.0 , 100 ));
productService.addProduct(new Product ("P002" , "电脑" , 5000.0 , 50 ));
productService.addProduct(new Product ("P003" , "电视" , 3000.0 , 80 ));
productService.addProduct(new Product ("P004" , "手表" , 500.0 , 200 ));
productService.addProduct(new Product ("P005" , "耳机" , 300.0 , 150 ));
}
}
启动后,访问 /api/products/export 可下载 Excel,访问 /api/products/report 可下载 PDF。实际开发中,根据业务复杂度,还可以引入 EasyExcel 简化 POI 的使用,或使用 Freemarker 定制 HTML 报表。
相关免费在线工具 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