Spring Boot 数据导入导出与报表生成
Spring Boot 数据导入导出与报表生成
24.1 学习目标与重点提示
学习目标:掌握Spring Boot数据导入导出与报表生成的核心概念与使用方法,包括数据导入导出的定义与特点、Spring Boot与数据导入导出的集成、Spring Boot与数据导入导出的配置、Spring Boot与报表生成的基本方法、Spring Boot的实际应用场景,学会在实际开发中处理数据导入导出与报表生成问题。
重点:数据导入导出的定义与特点、Spring Boot与数据导入导出的集成、Spring Boot与数据导入导出的配置、Spring Boot与报表生成的基本方法、Spring Boot的实际应用场景。
24.2 数据导入导出概述
数据导入导出是Java开发中的重要组件。
24.2.1 数据导入导出的定义
定义:数据导入导出是指将数据从一个系统导入到另一个系统,或从一个系统导出到另一个系统的过程。
作用:
- 实现数据的迁移。
- 实现数据的备份。
- 实现数据的共享。
常见的数据导入导出格式:
- CSV:Comma-Separated Values,逗号分隔值格式。
- Excel:Microsoft Excel格式。
- JSON:JavaScript Object Notation,JavaScript对象表示法格式。
- XML:eXtensible Markup Language,可扩展标记语言格式。
✅ 结论:数据导入导出是指将数据从一个系统导入到另一个系统,或从一个系统导出到另一个系统的过程,作用是实现数据的迁移、备份、共享。
24.2.2 数据导入导出的特点
定义:数据导入导出的特点是指数据导入导出的特性。
特点:
- 易用性:数据导入导出提供易用的编程模型。
- 高效性:数据导入导出提供高效的数据处理。
- 可扩展性:数据导入导出可以扩展到多个应用程序之间的数据通信。
- 可靠性:数据导入导出提供可靠的数据传输。
✅ 结论:数据导入导出的特点包括易用性、高效性、可扩展性、可靠性。
24.3 Spring Boot与数据导入导出的集成
Spring Boot与数据导入导出的集成是Java开发中的重要内容。
24.3.1 集成Apache POI的步骤
定义:集成Apache POI的步骤是指使用Spring Boot与Apache POI集成的方法。
步骤:
- 创建Spring Boot项目。
- 添加所需的依赖。
- 创建数据访问层。
- 创建业务层。
- 创建控制器类。
- 测试应用。
示例:
pom.xml文件中的依赖:
<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></dependency><!-- Apache POI依赖 --><dependency><groupId>org.apache.poi</groupId><artifactId>poi</artifactId><version>4.1.2</version></dependency><dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version></dependency><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>application.properties文件中的配置:
# 服务器端口 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 # JPA配置 spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true # H2数据库控制台 spring.h2.console.enabled=true spring.h2.console.path=/h2-console 实体类:
importjavax.persistence.*;@Entity@Table(name ="product")publicclassProduct{@Id@GeneratedValue(strategy =GenerationType.IDENTITY)privateLong id;privateString productId;privateString productName;privatedouble price;privateint sales;publicProduct(){}publicProduct(String productId,String productName,double price,int sales){this.productId = productId;this.productName = productName;this.price = price;this.sales = sales;}// Getter和Setter方法publicLonggetId(){return id;}publicvoidsetId(Long id){this.id = id;}publicStringgetProductId(){return productId;}publicvoidsetProductId(String productId){this.productId = productId;}publicStringgetProductName(){return productName;}publicvoidsetProductName(String productName){this.productName = productName;}publicdoublegetPrice(){return price;}publicvoidsetPrice(double price){this.price = price;}publicintgetSales(){return sales;}publicvoidsetSales(int sales){this.sales = sales;}@OverridepublicStringtoString(){return"Product{"+"id="+ id +",+ productId +'\''+",+ productName +'\''+", price="+ price +", sales="+ sales +'}';}}Repository接口:
importorg.springframework.data.jpa.repository.JpaRepository;importorg.springframework.stereotype.Repository;@RepositorypublicinterfaceProductRepositoryextendsJpaRepository<Product,Long>{}Service类:
importorg.apache.poi.ss.usermodel.*;importorg.apache.poi.xssf.usermodel.XSSFWorkbook;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importorg.springframework.web.multipart.MultipartFile;importjava.io.ByteArrayOutputStream;importjava.io.IOException;importjava.util.ArrayList;importjava.util.Iterator;importjava.util.List;@ServicepublicclassProductService{@AutowiredprivateProductRepository productRepository;@TransactionalpublicvoidimportProducts(MultipartFile file)throwsIOException{List<Product> products =newArrayList<>();Workbook workbook =newXSSFWorkbook(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 =newProduct(); 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)publicbyte[]exportProducts()throwsIOException{List<Product> products = productRepository.findAll();Workbook workbook =newXSSFWorkbook();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 =newByteArrayOutputStream(); workbook.write(outputStream); workbook.close();return outputStream.toByteArray();}@TransactionalpublicProductaddProduct(Product product){return productRepository.save(product);}@Transactional(readOnly =true)publicList<Product>getAllProducts(){return productRepository.findAll();}}控制器类:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpHeaders;importorg.springframework.http.MediaType;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importorg.springframework.web.multipart.MultipartFile;importjava.io.IOException;importjava.util.List;@RestController@RequestMapping("/api/products")publicclassProductController{@AutowiredprivateProductService productService;@PostMapping("/import")publicResponseEntity<String>importProducts(@RequestParam("file")MultipartFile file){try{ productService.importProducts(file);returnResponseEntity.ok("数据导入成功");}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body("数据导入失败:"+ e.getMessage());}}@GetMapping("/export")publicResponseEntity<byte[]>exportProducts(){try{byte[] bytes = productService.exportProducts();HttpHeaders headers =newHttpHeaders(); 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");returnResponseEntity.ok().headers(headers).body(bytes);}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body(null);}}@PostMapping("/")publicProductaddProduct(@RequestBodyProduct product){return productService.addProduct(product);}@GetMapping("/")publicList<Product>getAllProducts(){return productService.getAllProducts();}}应用启动类:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassProductApplication{publicstaticvoidmain(String[] args){SpringApplication.run(ProductApplication.class, args);}@AutowiredprivateProductService productService;publicvoidrun(String... args){// 初始化数据 productService.addProduct(newProduct("P001","手机",1000.0,100)); productService.addProduct(newProduct("P002","电脑",5000.0,50)); productService.addProduct(newProduct("P003","电视",3000.0,80)); productService.addProduct(newProduct("P004","手表",500.0,200)); productService.addProduct(newProduct("P005","耳机",300.0,150));}}测试类:
importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.boot.test.web.client.TestRestTemplate;importorg.springframework.boot.web.server.LocalServerPort;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.ResponseEntity;importorg.springframework.util.LinkedMultiValueMap;importorg.springframework.util.MultiValueMap;importorg.springframework.web.multipart.MultipartFile;importorg.springframework.web.multipart.commons.CommonsMultipartFile;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStream;importstaticorg.assertj.core.api.Assertions.assertThat;@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classProductApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestAddProduct(){Product product =newProduct("P006","平板",2000.0,70);Product savedProduct = restTemplate.postForObject("http://localhost:"+ port +"/api/products/", product,Product.class);assertThat(savedProduct).isNotNull();assertThat(savedProduct.getProductId()).isEqualTo("P006");}@TestvoidtestGetAllProducts(){List<Product> products = restTemplate.getForObject("http://localhost:"+ port +"/api/products/",List.class);assertThat(products).isNotNull();assertThat(products.size()).isGreaterThanOrEqualTo(5);}@TestvoidtestImportProducts()throwsIOException{File file =newFile("src/test/resources/products.xlsx");InputStream inputStream =newFileInputStream(file);MultipartFile multipartFile =newCommonsMultipartFile(inputStream);HttpHeaders headers =newHttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap<String,Object> body =newLinkedMultiValueMap<>(); body.add("file", multipartFile);HttpEntity<MultiValueMap<String,Object>> requestEntity =newHttpEntity<>(body, headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/api/products/import",HttpMethod.POST, requestEntity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("数据导入成功");}@TestvoidtestExportProducts(){ResponseEntity<byte[]> response = restTemplate.getForEntity("http://localhost:"+ port +"/api/products/export",byte[].class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).isNotNull();assertThat(response.getBody().length).isGreaterThan(0);}}✅ 结论:集成Apache POI的步骤包括创建Spring Boot项目、添加所需的依赖、创建数据访问层、创建业务层、创建控制器类、测试应用。
24.4 Spring Boot与报表生成的基本方法
Spring Boot与报表生成的基本方法包括使用Apache POI、使用JasperReports、使用Excel模板。
24.4.1 使用JasperReports
定义:使用JasperReports是指Spring Boot与报表生成集成的基本方法之一。
作用:
- 实现报表生成。
- 提高应用程序的性能。
示例:
pom.xml文件中的依赖:
<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></dependency><!-- 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><!-- 测试依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>Service类:
importnet.sf.jasperreports.engine.*;importnet.sf.jasperreports.engine.data.JRBeanCollectionDataSource;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.io.ByteArrayOutputStream;importjava.io.InputStream;importjava.util.HashMap;importjava.util.List;importjava.util.Map;@ServicepublicclassReportService{@AutowiredprivateProductRepository productRepository;@Transactional(readOnly =true)publicbyte[]generateProductReport()throwsJRException{List<Product> products = productRepository.findAll();// 加载Jasper模板InputStream templateStream =getClass().getResourceAsStream("/reports/product-report.jasper");JasperReport jasperReport =(JasperReport)JRLoader.loadObject(templateStream);// 设置参数Map<String,Object> parameters =newHashMap<>(); parameters.put("Title","产品销售报表");// 设置数据源JRBeanCollectionDataSource dataSource =newJRBeanCollectionDataSource(products);// 生成报表JasperPrint jasperPrint =JasperFillManager.fillReport(jasperReport, parameters, dataSource);// 导出报表为PDFByteArrayOutputStream outputStream =newByteArrayOutputStream();JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);return outputStream.toByteArray();}}控制器类:
importnet.sf.jasperreports.engine.JRException;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.http.HttpHeaders;importorg.springframework.http.MediaType;importorg.springframework.http.ResponseEntity;importorg.springframework.web.bind.annotation.*;importorg.springframework.web.multipart.MultipartFile;importjava.io.IOException;importjava.util.List;@RestController@RequestMapping("/api/products")publicclassProductController{@AutowiredprivateProductService productService;@AutowiredprivateReportService reportService;@GetMapping("/report")publicResponseEntity<byte[]>generateProductReport(){try{byte[] bytes = reportService.generateProductReport();HttpHeaders headers =newHttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/pdf")); headers.setContentDispositionFormData("attachment","product-report.pdf"); headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");returnResponseEntity.ok().headers(headers).body(bytes);}catch(JRException e){ e.printStackTrace();returnResponseEntity.status(500).body(null);}}@PostMapping("/import")publicResponseEntity<String>importProducts(@RequestParam("file")MultipartFile file){try{ productService.importProducts(file);returnResponseEntity.ok("数据导入成功");}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body("数据导入失败:"+ e.getMessage());}}@GetMapping("/export")publicResponseEntity<byte[]>exportProducts(){try{byte[] bytes = productService.exportProducts();HttpHeaders headers =newHttpHeaders(); 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");returnResponseEntity.ok().headers(headers).body(bytes);}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body(null);}}@PostMapping("/")publicProductaddProduct(@RequestBodyProduct product){return productService.addProduct(product);}@GetMapping("/")publicList<Product>getAllProducts(){return productService.getAllProducts();}}测试类:
importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.boot.test.web.client.TestRestTemplate;importorg.springframework.boot.web.server.LocalServerPort;importorg.springframework.http.HttpEntity;importorg.springframework.http.HttpHeaders;importorg.springframework.http.HttpMethod;importorg.springframework.http.ResponseEntity;importorg.springframework.util.LinkedMultiValueMap;importorg.springframework.util.MultiValueMap;importorg.springframework.web.multipart.MultipartFile;importorg.springframework.web.multipart.commons.CommonsMultipartFile;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStream;importstaticorg.assertj.core.api.Assertions.assertThat;@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classProductApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestAddProduct(){Product product =newProduct("P006","平板",2000.0,70);Product savedProduct = restTemplate.postForObject("http://localhost:"+ port +"/api/products/", product,Product.class);assertThat(savedProduct).isNotNull();assertThat(savedProduct.getProductId()).isEqualTo("P006");}@TestvoidtestGetAllProducts(){List<Product> products = restTemplate.getForObject("http://localhost:"+ port +"/api/products/",List.class);assertThat(products).isNotNull();assertThat(products.size()).isGreaterThanOrEqualTo(5);}@TestvoidtestImportProducts()throwsIOException{File file =newFile("src/test/resources/products.xlsx");InputStream inputStream =newFileInputStream(file);MultipartFile multipartFile =newCommonsMultipartFile(inputStream);HttpHeaders headers =newHttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap<String,Object> body =newLinkedMultiValueMap<>(); body.add("file", multipartFile);HttpEntity<MultiValueMap<String,Object>> requestEntity =newHttpEntity<>(body, headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/api/products/import",HttpMethod.POST, requestEntity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("数据导入成功");}@TestvoidtestExportProducts(){ResponseEntity<byte[]> response = restTemplate.getForEntity("http://localhost:"+ port +"/api/products/export",byte[].class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).isNotNull();assertThat(response.getBody().length).isGreaterThan(0);}@TestvoidtestGenerateProductReport(){ResponseEntity<byte[]> response = restTemplate.getForEntity("http://localhost:"+ port +"/api/products/report",byte[].class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).isNotNull();assertThat(response.getBody().length).isGreaterThan(0);}}✅ 结论:使用JasperReports是指Spring Boot与报表生成集成的基本方法之一,作用是实现报表生成、提高应用程序的性能。
24.5 Spring Boot的实际应用场景
在实际开发中,Spring Boot数据导入导出与报表生成的应用场景非常广泛,如:
- 实现产品信息的导入导出。
- 实现用户信息的导入导出。
- 实现订单信息的导入导出。
- 实现产品销售报表的生成。
示例:
importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublicclassProductApplication{publicstaticvoidmain(String[] args){SpringApplication.run(ProductApplication.class, args);}@AutowiredprivateProductService productService;publicvoidrun(String... args){// 初始化数据 productService.addProduct(newProduct("P001","手机",1000.0,100)); productService.addProduct(newProduct("P002","电脑",5000.0,50)); productService.addProduct(newProduct("P003","电视",3000.0,80)); productService.addProduct(newProduct("P004","手表",500.0,200)); productService.addProduct(newProduct("P005","耳机",300.0,150));}}@ServiceclassProductService{@AutowiredprivateProductRepository productRepository;@TransactionalpublicvoidimportProducts(MultipartFile file)throwsIOException{List<Product> products =newArrayList<>();Workbook workbook =newXSSFWorkbook(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 =newProduct(); 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)publicbyte[]exportProducts()throwsIOException{List<Product> products = productRepository.findAll();Workbook workbook =newXSSFWorkbook();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 =newByteArrayOutputStream(); workbook.write(outputStream); workbook.close();return outputStream.toByteArray();}@TransactionalpublicProductaddProduct(Product product){return productRepository.save(product);}@Transactional(readOnly =true)publicList<Product>getAllProducts(){return productRepository.findAll();}}@RestController@RequestMapping("/api/products")classProductController{@AutowiredprivateProductService productService;@AutowiredprivateReportService reportService;@GetMapping("/report")publicResponseEntity<byte[]>generateProductReport(){try{byte[] bytes = reportService.generateProductReport();HttpHeaders headers =newHttpHeaders(); headers.setContentType(MediaType.parseMediaType("application/pdf")); headers.setContentDispositionFormData("attachment","product-report.pdf"); headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");returnResponseEntity.ok().headers(headers).body(bytes);}catch(JRException e){ e.printStackTrace();returnResponseEntity.status(500).body(null);}}@PostMapping("/import")publicResponseEntity<String>importProducts(@RequestParam("file")MultipartFile file){try{ productService.importProducts(file);returnResponseEntity.ok("数据导入成功");}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body("数据导入失败:"+ e.getMessage());}}@GetMapping("/export")publicResponseEntity<byte[]>exportProducts(){try{byte[] bytes = productService.exportProducts();HttpHeaders headers =newHttpHeaders(); 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");returnResponseEntity.ok().headers(headers).body(bytes);}catch(IOException e){ e.printStackTrace();returnResponseEntity.status(500).body(null);}}@PostMapping("/")publicProductaddProduct(@RequestBodyProduct product){return productService.addProduct(product);}@GetMapping("/")publicList<Product>getAllProducts(){return productService.getAllProducts();}}// 测试类@SpringBootTest(webEnvironment =SpringBootTest.WebEnvironment.RANDOM_PORT)classProductApplicationTests{@LocalServerPortprivateint port;@AutowiredprivateTestRestTemplate restTemplate;@TestvoidcontextLoads(){}@TestvoidtestAddProduct(){Product product =newProduct("P006","平板",2000.0,70);Product savedProduct = restTemplate.postForObject("http://localhost:"+ port +"/api/products/", product,Product.class);assertThat(savedProduct).isNotNull();assertThat(savedProduct.getProductId()).isEqualTo("P006");}@TestvoidtestGetAllProducts(){List<Product> products = restTemplate.getForObject("http://localhost:"+ port +"/api/products/",List.class);assertThat(products).isNotNull();assertThat(products.size()).isGreaterThanOrEqualTo(5);}@TestvoidtestImportProducts()throwsIOException{File file =newFile("src/test/resources/products.xlsx");InputStream inputStream =newFileInputStream(file);MultipartFile multipartFile =newCommonsMultipartFile(inputStream);HttpHeaders headers =newHttpHeaders(); headers.setContentType(MediaType.MULTIPART_FORM_DATA);MultiValueMap<String,Object> body =newLinkedMultiValueMap<>(); body.add("file", multipartFile);HttpEntity<MultiValueMap<String,Object>> requestEntity =newHttpEntity<>(body, headers);ResponseEntity<String> response = restTemplate.exchange("http://localhost:"+ port +"/api/products/import",HttpMethod.POST, requestEntity,String.class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).contains("数据导入成功");}@TestvoidtestExportProducts(){ResponseEntity<byte[]> response = restTemplate.getForEntity("http://localhost:"+ port +"/api/products/export",byte[].class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).isNotNull();assertThat(response.getBody().length).isGreaterThan(0);}@TestvoidtestGenerateProductReport(){ResponseEntity<byte[]> response = restTemplate.getForEntity("http://localhost:"+ port +"/api/products/report",byte[].class);assertThat(response.getStatusCodeValue()).isEqualTo(200);assertThat(response.getBody()).isNotNull();assertThat(response.getBody().length).isGreaterThan(0);}}输出结果:
- 访问http://localhost:8080/api/products/report:下载产品销售报表(PDF格式)。
- 访问http://localhost:8080/api/products/import:上传产品信息Excel文件,导入数据。
- 访问http://localhost:8080/api/products/export:下载产品信息Excel文件。
✅ 结论:在实际开发中,Spring Boot数据导入导出与报表生成的应用场景非常广泛,需要根据实际问题选择合适的导入导出格式和报表生成工具。
总结
本章我们学习了Spring Boot数据导入导出与报表生成,包括数据导入导出的定义与特点、Spring Boot与数据导入导出的集成、Spring Boot与数据导入导出的配置、Spring Boot与报表生成的基本方法、Spring Boot的实际应用场景,学会了在实际开发中处理数据导入导出与报表生成问题。其中,数据导入导出的定义与特点、Spring Boot与数据导入导出的集成、Spring Boot与数据导入导出的配置、Spring Boot与报表生成的基本方法、Spring Boot的实际应用场景是本章的重点内容。从下一章开始,我们将学习Spring Boot的其他组件、微服务等内容。