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

GitHub 上开源了 30+ 个 OpenClaw 真实使用案例。

最近逛 GitHub 的时候发现了一个挺有意思的仓库,专门收集 OpenClaw 的 usecases。 说实话,很多人装完 OpenClaw 之后的操作都是一样的:疯狂往里面塞各种 Skill,ClawHub 逛得跟菜市场一样热闹,今天装个天气查询,明天装个股票分析,后天又来个翻译助手。 结果装了一堆却发现每天还是在信息搜索、做个记录。Skill 装了一百个,生活一点没变轻松。 这个开源项目就是专门收集人们真实在用的 OpenClaw 场景,而不是单纯介绍某个 Skill 或插件。 01 开源项目简介 awesome-openclaw-usecases 目前收录了 30 多个经过验证的真实使用场景。 它的核心理念非常简单:不是教你装什么 Skill,而是告诉你别人是怎么把 OpenClaw 变成真正能帮人类干活的私人助理的。 如果你不知道 OpenClaw 具体能做什么,只停留在抽象概念。有一些自动化或搭建 AI 智能体想法,但不知道如何系统落地,想参考别人已经跑通的真实工作流和自动化方案。

By Ne0inhk
Enterprise Architect 16 下载、安装与无限30天操作

Enterprise Architect 16 下载、安装与无限30天操作

文章目录 * Enterprise Architect 16 简介 * (一)支持多种建模语言和标准 * (二)强大的版本控制、协作和文档管理功能 * (三)增强的技术和用户体验 * (四)高级功能和扩展性 * 一,下载软件 * (一)官网 * (二)阿里云盘 * (三)百度网盘 * (四)迅雷 * 二,安装软件 * 三,无限30天设置 * (一)删除`fkey.dat`文件 * (二)删除注册表Kane文件夹 * (三)查看效果 Enterprise Architect 16 简介 Enterprise Architect 16是一款功能强大的企业级建模工具,它为企业和机构在系统设计、业务流程建模、数据建模以及软件开发等方面提供了全面的支持。以下是对Enterprise Architect 16的详细介绍:

By Ne0inhk
最新版 Kimi K2.5 进阶实战全攻略:从开源部署到 Agent 集群搭建(视频理解 + 多模态开发 + 高并发调优)

最新版 Kimi K2.5 进阶实战全攻略:从开源部署到 Agent 集群搭建(视频理解 + 多模态开发 + 高并发调优)

1 技术背景与核心架构原理 1.1 技术定位与版本说明 Kimi K2.5 是月之暗面于2026年初发布的开源多模态大语言模型,聚焦长上下文理解、原生多模态交互、Agent 原生支持三大核心能力,针对工业级落地场景完成了全链路优化。本次实战覆盖的开源版本包括: * kimi-k2.5-chat-70b:基础对话版,支持2000K token 上下文窗口,原生适配工具调用 * kimi-k2.5-multimodal-70b:多模态完整版,新增图像、长视频时序理解能力,支持最长10小时连续视频输入 * kimi-k2.5-agent-70b:Agent 优化版,强化多轮工具链执行、分布式状态同步能力,适配集群化部署 * 量化衍生版本:AWQ 4bit/8bit、FP8 量化版,适配低显存硬件环境,精度损失控制在1%以内 1.2 核心架构与技术亮点 1.2.1

By Ne0inhk
宇树 Qmini 双足机器人训练个人经验总结

宇树 Qmini 双足机器人训练个人经验总结

github:https://github.com/vsislab/RoboTamer4Qmini 本篇内容基于我在 AutoDL 云服务器 上对 Qmini 做完整训练与测试的实践总结,涵盖训练、可视化、策略测试、模型导出、URDF 调试等环节,并重点说明 headless(无显示)环境下的各种坑与解决方案。希望能帮到后来者少走弯路。 前提说明:为什么不建议在云端直接跑渲染? 我最开始的目标是:训练、渲染、视频录制全部在 AutoDL 上完成,不经过本地运行。 然而现实是: * 即使用 Xvfb 等虚拟显示器启动 Isaac Gym,也会发生视频保存全黑的情况。 * VNC 远程桌面也无法正常显示 Isaac Gym 的渲染窗口。 * 根本原因来自 驱动版本过高与 Isaac Gym 对驱动的强依赖。 因此更推荐:

By Ne0inhk