自己搭建Spring Batch

目标:

构建一个批处理job:从CVS导入数据,对其进行转换,然后传输到指定位置。本例是通过日志打印。

源码下载地址

原文

业务数据放在CVS文件中(sample-data.csv):

Jill,Doe
Joe,Doe
Justin,Doe
Jane,Doe
John,Doe

SQL脚本创建一个表来存储数据(schema-all.sql):

DROP TABLE people IF EXISTS;

CREATE TABLE people  (
    person_id BIGINT IDENTITY NOT NULL PRIMARY KEY,
    first_name VARCHAR(20),
    last_name VARCHAR(20)
);

在这里插入图片描述

Spring Batch和HyperSQL数据库依赖项(pom.xml):

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.2.2.RELEASE</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>batch-processing</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>batch-processing</name>
	<description>Demo project for Spring Boot</description>

	<properties>
		<java.version>1.8</java.version>
	</properties>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-batch</artifactId>
		</dependency>

		<dependency>
			<groupId>org.hsqldb</groupId>
			<artifactId>hsqldb</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
			<exclusions>
				<exclusion>
					<groupId>org.junit.vintage</groupId>
					<artifactId>junit-vintage-engine</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.springframework.batch</groupId>
			<artifactId>spring-batch-test</artifactId>
			<scope>test</scope>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

选择Gradle(build.gradle):

plugins {
    
    
	id 'org.springframework.boot' version '2.2.2.RELEASE'
	id 'io.spring.dependency-management' version '1.0.8.RELEASE'
	id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
    
    
	mavenCentral()
}

dependencies {
    
    
	implementation 'org.springframework.boot:spring-boot-starter-batch'
	runtimeOnly 'org.hsqldb:hsqldb'
	testImplementation('org.springframework.boot:spring-boot-starter-test') {
    
    
		exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
	}
	testImplementation 'org.springframework.batch:spring-batch-test'
}

test {
    
    
	useJUnitPlatform()
}

创建业务类:

通过构造函数或通过设置属性来使用名字和姓氏实例化该类(Person.java):

package com.example.batchprocessing;

public class Person {
    
    

  private String lastName;
  private String firstName;

  public Person() {
    
    
  }

  public Person(String firstName, String lastName) {
    
    
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public void setFirstName(String firstName) {
    
    
    this.firstName = firstName;
  }

  public String getFirstName() {
    
    
    return firstName;
  }

  public String getLastName() {
    
    
    return lastName;
  }

  public void setLastName(String lastName) {
    
    
    this.lastName = lastName;
  }

  @Override
  public String toString() {
    
    
    return "firstName: " + firstName + ", lastName: " + lastName;
  }

}

创建一个中间处理器:

转换器,将名字转换为大写(PersonItemProcessor.java):

package com.example.batchprocessing;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.batch.item.ItemProcessor;

public class PersonItemProcessor implements ItemProcessor<Person, Person> {
    
    

  private static final Logger log = LoggerFactory.getLogger(PersonItemProcessor.class);

  @Override
  public Person process(final Person person) throws Exception {
    
    
    final String firstName = person.getFirstName().toUpperCase();
    final String lastName = person.getLastName().toUpperCase();

    final Person transformedPerson = new Person(firstName, lastName);

    log.info("Converting (" + person + ") into (" + transformedPerson + ")");

    return transformedPerson;
  }

}

汇总批处理作业

读取器,处理器和写入器(BatchConfiguration.java):

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {
    
    

	@Autowired
	public JobBuilderFactory jobBuilderFactory;

	@Autowired
	public StepBuilderFactory stepBuilderFactory;
	// end::setup[]

	// tag::readerwriterprocessor[]
	@Bean
	public FlatFileItemReader<Person> reader() {
    
    
		return new FlatFileItemReaderBuilder<Person>()
			.name("personItemReader")
			.resource(new ClassPathResource("sample-data.csv"))
			.delimited()
			.names(new String[]{
    
    "firstName", "lastName"})
			.fieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {
    
    {
    
    
				setTargetType(Person.class);
			}})
			.build();
	}

	@Bean
	public PersonItemProcessor processor() {
    
    
		return new PersonItemProcessor();
	}

	@Bean
	public JdbcBatchItemWriter<Person> writer(DataSource dataSource) {
    
    
		return new JdbcBatchItemWriterBuilder<Person>()
			.itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>())
			.sql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)")
			.dataSource(dataSource)
			.build();
	}
	// end::readerwriterprocessor[]

	// tag::jobstep[]
	@Bean
	public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
    
    
		return jobBuilderFactory.get("importUserJob")
			.incrementer(new RunIdIncrementer())
			.listener(listener)
			.flow(step1)
			.end()
			.build();
	}

	@Bean
	public Step step1(JdbcBatchItemWriter<Person> writer) {
    
    
		return stepBuilderFactory.get("step1")
			.<Person, Person> chunk(10)
			.reader(reader())
			.processor(processor())
			.writer(writer)
			.build();
	}
	// end::jobstep[]
}

关于上面代码的详解:

在这里插入图片描述
Spring Batch提供了许多实用程序类,这些实用程序类减少了编写自定义代码的需求。您可以专注于业务逻辑。
在这里插入图片描述
第一部分代码定义了输入,处理器和输出。

  • reader()创建一个ItemReader。它会寻找一个名为的文件,sample-data.csv并为每个订单项解析足够的信息,以将其转换为Person。
  • processor()创建PersonItemProcessor您之前定义的的实例,以将数据转换为大写。
  • writer(DataSource)创建一个ItemWriter。这是针对JDBC目标的,并自动获取由创建的dataSource的副本@EnableBatchProcessing。它包含Person由Java bean属性驱动的插入单个所需的SQL语句。
    在这里插入图片描述
    第一种方法定义了job,第二种方法定义了一个步骤。job是按步骤构建的,每个步骤都可以涉及阅读器,处理器和编写器
    chunk()的前缀<Person,Person>,表示每个“块”处理的输入和输出类型。
    job完成时,获得通知的方法:

(JobCompletionNotificationListener.java):

package com.example.batchprocessing;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

@Component
public class JobCompletionNotificationListener extends JobExecutionListenerSupport {
    
    

  private static final Logger log = LoggerFactory.getLogger(JobCompletionNotificationListener.class);

  private final JdbcTemplate jdbcTemplate;

  @Autowired
  public JobCompletionNotificationListener(JdbcTemplate jdbcTemplate) {
    
    
    this.jdbcTemplate = jdbcTemplate;
  }

  @Override
  public void afterJob(JobExecution jobExecution) {
    
    
    if(jobExecution.getStatus() == BatchStatus.COMPLETED) {
    
    
      log.info("!!! JOB FINISHED! Time to verify the results");

      jdbcTemplate.query("SELECT first_name, last_name FROM people",
        (rs, row) -> new Person(
          rs.getString(1),
          rs.getString(2))
      ).forEach(person -> log.info("Found <" + person + "> in the database."));
    }
  }
}

(BatchProcessingApplication.java):

package com.example.batchprocessing;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class BatchProcessingApplication {
    
    

  public static void main(String[] args) throws Exception {
    
    
    System.exit(SpringApplication.exit(SpringApplication.run(BatchProcessingApplication.class, args)));
  }
}

@SpringBootApplication 是一个方便注释,它添加了以下所有内容:

  • @Configuration:将类标记为应用程序上下文的Bean定义的源。
  • @EnableAutoConfiguration:告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,则此注释将应用程序标记为Web应用程序并激活关键行为,例如设置DispatcherServlet。
  • @ComponentScan:告诉Spring在包中寻找其他组件,配置和服务com/example,让它找到控制器。

运行

  • 右击 两个maven文件选择:
    在这里插入图片描述
  • 启动:
    在这里插入图片描述
  • 在maven,打complete文件对应的jar包:(判断方式就是jar最后在complete文件夹内)在这里插入图片描述
    -执行java -jar target / jar包名(java -jar target / batch-processing-0.0.1.jar)
    在这里插入图片描述

结果:

就可以看到通过日志打印的执行结果,将名字全转为大写:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Ciel_Y/article/details/108857369
今日推荐