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

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集成的方法。
步骤

  1. 创建Spring Boot项目。
  2. 添加所需的依赖。
  3. 创建数据访问层。
  4. 创建业务层。
  5. 创建控制器类。
  6. 测试应用。

示例
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的其他组件、微服务等内容。

Read more

突破MCU瓶颈:FPGA重构电机控制的实战指南

突破MCU瓶颈:FPGA重构电机控制的实战指南 【免费下载链接】FPGA-FOCFPGA-based Field Oriented Control (FOC) for driving BLDC/PMSM motor. 基于FPGA的FOC控制器,用于驱动BLDC/PMSM电机。 项目地址: https://gitcode.com/gh_mirrors/fp/FPGA-FOC 在工业自动化与机器人领域,电机控制技术正面临前所未有的性能挑战。传统MCU方案受限于串行处理架构,难以满足永磁同步电机(PMSM)对实时性和控制精度的双重需求。本文将深入剖析当前电机控制领域的核心痛点,揭示FPGA技术如何通过并行计算架构突破这些限制,并提供一套从硬件选型到算法实现的完整实践路径。作为技术探索者,我们将通过"问题-方案-实践"的三段式框架,重新定义高性能电机控制的实现方式,特别聚焦FPGA在无刷电机驱动与场定向控制(FOC)领域的技术突破价值。 电机控制的三大核心挑战:为何MCU方案渐显乏力? 现代电机控制系统在追求更高性能指标的过程中,正遭遇来自硬件架构的根本性限制。这些瓶颈不仅影响控制

By Ne0inhk
Vivado 使用教程

Vivado 使用教程

目录 一、创建工程 二、创建文件 三、编写代码 四、仿真验证 五、配置管脚 六、生成Bitstream文件并烧录 一、创建工程 1.左边创建(或打开)工程,右侧可以快速打开最近打开过的工程。 2.来到这一步,命名工程并设置工程的存放路径(这里以D触发器为例) 3.选择RTL点击next。会来到添加文件环节(可以在这里添加.v等文件,不过后面再添加是一样的)直接点击next。 4.选择芯片型号(根据开发板选,这里随便选的),完成后点next会弹出信息概要,finish完成。         二、创建文件 完成上述步骤会进入当前界面: 1.工程管理器add sourse添加(创建)设计文件,创建文件后选择Verilog语言并命名。 2.定义端口(可选),若在这定义后,

By Ne0inhk
Formality:原语(primitive)的概念

Formality:原语(primitive)的概念

相关阅读 Formalityhttps://blog.ZEEKLOG.net/weixin_45791458/category_12841971.html?spm=1001.2014.3001.5482         原语(primitive)一般指的是语言内置的基本构件,它们代表了基本的逻辑门和构件,通常用于建模电路的基本功能,例如Verilog中的门级建模会使用and、or等关键词表示单元门。Formality也存在原语的概念,这一般出现在对门级网表进行建模时,本文将对此进行详细解释。         假设以例1所示的RTL代码作为参考设计(可以看出添加了// synopsys sync_set_reset综合指令让Design Compiler将其实现为带同步复位端的D触发器),例2所示的综合后网表作为实现设计,其中data_out_reg原语是一个带同步复位端的D触发器(FDS2)。 // 例1 module ref( input clk, input reset, input data_in, output reg data_

By Ne0inhk
程序员的自我修养:用 AR 眼镜管理健康

程序员的自我修养:用 AR 眼镜管理健康

欢迎文末添加好友交流,共同进步! “ 俺はモンキー・D・ルフィ。海贼王になる男だ!” * 一、从一次体检说起 * 二、为什么是 AR 眼镜? * 三、技术选型:CXR-M SDK vs 灵珠平台 * 四、项目架构设计 * 五、从配置开始:Gradle 和权限 * 5.1 添加 SDK 依赖 * 5.2 权限配置 * 六、数据层实现 * 6.1 数据模型 * 6.2 数据仓库 * 七、SDK 封装层 * 7.1 发送提醒到眼镜 * 7.2 TTS 语音播报

By Ne0inhk