在本文中,我们将演示如何使用 Spring Batch 从 Excel (.xls 或 .xlsx) 文件读取所有行并将其保存到 Spring Boot 应用程序中的数据库中。我们将介绍从读取 Excel 文件、将行转换为Entity实例、将这些实例保存到数据库、记录进度以及使用 cron 表达式安排批处理作业的整个过程。
前提:
确保您具有以下信息:
- JDK 17 或更高版本
- Maven 或 Gradle
- Spring Boot 3.2.7 或更高版本
- H2 或任何其他数据库
- Apache POI 用于读取 Excel 文件
pom.xml:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-batch</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.springframework.batch.extensions</groupId> <artifactId>spring-batch-excel</artifactId> <version>0.1.1</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>5.2.5</version> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> </dependencies>
|
示例Excel 文件包含员工列表,每行代表单个员工的详细信息。Excel 文件中的列直接对应于实体类中的字段Employee:
- Name名称:此列映射到实体name中的字段Employee。
- Department部门:此列映射到实体department中的字段Employee。
- Email电子邮件:此列映射到实体email中的字段Employee。
实体Employee类定义如下:
@Entity public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String name; private String department; private String email; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } @Override public String toString() { return "Employee{" + "id=" + id + ", name=" + name + ", department=" + department + ", email=" + email + '}'; } }
|
为实体Employee创建一个存储库接口。
@Repository public interface EmployeeRepository extends JpaRepository{ }
|
使用 PoiItemReader 实现 Excel 阅读器
Spring Batch Extension 提供PoiItemReader读取 Excel 文件的功能。在这里,我们将配置它来处理员工数
@Configuration public class PoiReader { @Value("${excel.file.path}") private String filePath; @Bean public ItemReader<Employee> employeeReader() { PoiItemReader<Employee> reader = new PoiItemReader<>(); reader.setResource(new ClassPathResource(filePath)); reader.setLinesToSkip(1); reader.setRowMapper(new BeanWrapperRowMapper<Employee>() { { setTargetType(Employee.class); } }); reader.setName("employeeReader"); return reader; } }
|
- @Value注释从应用程序属性中注入文件路径(例如excel.file.path=employees.xlsx)。
- PoiItemReader将 Excel 文件位置配置为 ClasspathResource。
- BeanWrapperRowMapper自动将列名映射到类中相应的字段Employee。
- setLinesToSkip(1)确保跳过标题行。
使用 JpaRepository 保存到数据库
接下来,我们将利用 Spring Data JPA EmployeeRepository将处理后的员工数据保存到数据库。
@Bean public ItemWriter employeeWriter(EmployeeRepository repository) { return items -> { for (Employee employee : items) { repository.save(employee); System.out.println("Employee saved: " + employee.getName()); } }; }
|
该 ItemWriter 会遍历雇员对象列表,并使用 EmployeeRepository 保存这些对象。
配置Spring Batch作业
以下是本文中用于配置 Spring Batch 作业的完整示例代码,该作业从 Excel 文件读取员工数据、处理数据并将其写入数据库。每个步骤都分解为更小的组件 - ItemReader、ItemProcessor 和 ItemWriter。
@Configuration public class PoiReader { @Value("${excel.file.path}") private String filePath; private final JobRepository jobRepository; private final PlatformTransactionManager transactionManager; private final EmployeeRepository employeeRepository; public PoiReader(JobRepository jobRepository, EmployeeRepository employeeRepository, PlatformTransactionManager transactionManager) { this.jobRepository = jobRepository; this.transactionManager = transactionManager; this.employeeRepository = employeeRepository; } @Bean public ItemReader<Employee> employeeReader() { PoiItemReader<Employee> reader = new PoiItemReader<>(); reader.setResource(new ClassPathResource(filePath)); reader.setLinesToSkip(1); reader.setRowMapper(new BeanWrapperRowMapper<Employee>() { { setTargetType(Employee.class); } }); reader.setName("employeeReader"); return reader; } @Bean public ItemWriter<Employee> employeeWriter() { return items -> { for (Employee employee : items) { employeeRepository.save(employee); System.out.println("Employee saved: " + employee.getName()); } }; } @Bean public ItemProcessor<Employee, Employee> processor() { return employee -> { // Example processor logic employee.setName(employee.getName()); System.out.println("Name: " + employee.getName() + ", Department: " + employee.getDepartment()); return employee; }; } @Bean public Step chunkProcessingStep() { var builder = new StepBuilder("chunkProcessingStep", jobRepository); return builder .<Employee, Employee>chunk(1, transactionManager) .reader(employeeReader()) .processor(processor()) .writer(employeeWriter()) .build(); } @Bean Job importUserJob(Step step1) { var builder = new JobBuilder("importUserJob", jobRepository); return builder .incrementer(new RunIdIncrementer()) .start(step1) .build(); } }
|
上述代码定义了一个 Spring Batch 配置,该配置使用 @Value 注入 Excel 文件的路径,还包括 JobRepository、EmployeeRepository 和 PlatformTransactionManager 的构造函数注入,它们分别用于管理作业执行、数据库操作和事务管理。 该类定义了对批处理至关重要的几个 Bean:
该类定义了对批处理至关重要的几个bean:
- employeeReader(): 此 Bean 使用 PoiItemReader 从 Excel 文件中读取数据。 它会跳过标题行,并使用 BeanWrapperRowMapper 将每一行映射到雇员对象:
- employeeWriter(): 此 bean 使用 EmployeeRepository 将处理过的雇员对象写入数据库。
- Processor(): 此 Bean 处理每个雇员对象。 在此示例中,它会打印雇员的姓名和部门。
- chunkProcessingStep(): 它将读取器、处理器和写入器结合起来,以处理数据块。
- importUserJob(): 此 Bean 将定义批处理作业本身,从定义的步骤开始,并使用 RunIdIncrementer 确保作业运行的唯一性。
调度批处理作业
一旦配置好批处理作业,下一步就是调度它在特定时间间隔运行。 Spring Boot 通过 @EnableScheduling 注解和 @Scheduled 注解提供了调度功能。 通过使用这些注解,我们可以轻松地调度批处理作业以固定的时间间隔运行,如每小时、每天或基于更复杂的 cron 表达式。
在我们的示例中,我们将调度批处理作业在每小时的顶部运行。 这样就能确保每小时从 Excel 文件读取雇员数据并写入数据库。
@Configuration @EnableScheduling public class BatchScheduler { @Autowired private JobLauncher jobLauncher; @Autowired private Job importUserJob; @Scheduled(cron = "0 0 * * * ?") // Run at the top of every hour public void perform() throws Exception { jobLauncher.run(importUserJob, new JobParameters()); } }
|
上面的代码片段调度一个批处理任务在每小时的顶部运行。 该类使用 @EnableScheduling 进行注解,以启用 Spring 的计划任务执行功能。 它自动连接了 JobLauncher 和 Job Bean,以启动和执行名为 importUserJob 的批处理任务。
@Scheduled(cron = "0 0 * * * ?") 注解指定了 perform() 方法应在每小时开始时运行,从而触发批处理任务。
结论
在本文中,我们探讨了如何实现 Spring Batch Excel 阅读器,以便从 Excel 文件中高效读取员工数据并将其存储到数据库中。 我们介绍了从设置项目和定义实体到配置批处理作业和使用 cron 表达式调度的各个步骤。