天天看點

SpringBatch系列文章-官網入門體驗例子

文章目錄

    • 建立一個SpringBoot項目
    • 業務測試和SQL語句
    • 建立業務類
    • 建立一個ItemProcessor實作
    • 建立一個Job并進行相關Bean配置
    • 建立Job及相關的Bean配置
    • 修改啟動類

體驗一下SpringBatch官網的入門例子,例子比較簡單,從一個csv檔案中讀取名字資訊然後轉換為大寫後插入到資料庫中。核心的Step操作如下:

建立一個SpringBoot項目

通過Spring向導建立一個SpringBoot項目,選中SpringBtach即可。完成的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.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ycxy</groupId>
    <artifactId>batchsduty01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>batchsduty01</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.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--
           <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</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>

           

官網的資料庫使用嵌入式資料庫hsql,不需要進行任何媒體安裝,非常友善。後續要時間再改造為Mysql。

業務測試和SQL語句

建立src/main/resources/sample-data.csv和src/main/resources/schema-all.sql。

Jill,Doe

Joe,Doe

Justin,Doe

Jane,Doe

John,Doe

DROP TABLE people IF EXISTS;

CREATE TABLE people (

person_id BIGINT IDENTITY NOT NULL PRIMARY KEY,

first_name VARCHAR(20),

last_name VARCHAR(20)

);

注意檔案名别亂改,SpringBoot自動加載識别schema-all.sql檔案。

建立業務類

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;
  }

}
           

建立一個ItemProcessor實作

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;
  }

}
           

建立一個Job并進行相關Bean配置

建立一個監聽

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."));
    }
  }
}
           

建立Job及相關的Bean配置

package com.ycxy.batchsduty01.batchprocessing;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider;
import org.springframework.batch.item.database.JdbcBatchItemWriter;
import org.springframework.batch.item.database.builder.JdbcBatchItemWriterBuilder;
import org.springframework.batch.item.file.FlatFileItemReader;
import org.springframework.batch.item.file.builder.FlatFileItemReaderBuilder;
import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

import javax.sql.DataSource;

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;
    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @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();
    }
    @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();
    }
}

           

修改啟動類

package com.ycxy.batchsduty01;

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

@SpringBootApplication
public class Batchsduty01Application {

    public static void main(String[] args) {
        System.exit(SpringApplication.exit(SpringApplication.run(Batchsduty01Application.class, args)));

       // SpringApplication.run(Batchsduty01Application.class, args);
    }

}
           

運作日志:

2020-07-20 08:16:30.512  INFO 6816 --- [           main] c.y.b.Batchsduty01Application            : Starting Batchsduty01Application on DESKTOP-5OBEU9N with PID 6816 (F:\yusys\cebank\demo\spbootbatch\batchsduty01\target\classes started by admin in F:\yusys\cebank\demo\spbootbatch\batchsduty01)
2020-07-20 08:16:30.514  INFO 6816 --- [           main] c.y.b.Batchsduty01Application            : No active profile set, falling back to default profiles: default
2020-07-20 08:16:30.844  INFO 6816 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Bootstrapping Spring Data JDBC repositories in DEFAULT mode.
2020-07-20 08:16:30.856  INFO 6816 --- [           main] .s.d.r.c.RepositoryConfigurationDelegate : Finished Spring Data repository scanning in 10ms. Found 0 JDBC repository interfaces.
2020-07-20 08:16:31.004  INFO 6816 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Starting...
2020-07-20 08:16:31.005  WARN 6816 --- [           main] com.zaxxer.hikari.util.DriverDataSource  : Registered driver with driverClassName=org.hsqldb.jdbcDriver was not found, trying direct instantiation.
2020-07-20 08:16:31.162  INFO 6816 --- [           main] com.zaxxer.hikari.pool.PoolBase          : HikariPool-1 - Driver does not support get/set network timeout for connections. (feature not supported)
2020-07-20 08:16:31.164  INFO 6816 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Start completed.
2020-07-20 08:16:31.268  INFO 6816 --- [           main] o.s.b.c.r.s.JobRepositoryFactoryBean     : No database type set, using meta data indicating: HSQL
2020-07-20 08:16:31.323  INFO 6816 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : No TaskExecutor has been set, defaulting to synchronous executor.
2020-07-20 08:16:31.413  INFO 6816 --- [           main] c.y.b.Batchsduty01Application            : Started Batchsduty01Application in 1.135 seconds (JVM running for 3.188)
2020-07-20 08:16:31.414  INFO 6816 --- [           main] o.s.b.a.b.JobLauncherApplicationRunner   : Running default command line with: []
2020-07-20 08:16:31.448  INFO 6816 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] launched with the following parameters: [{run.id=1}]
2020-07-20 08:16:31.472  INFO 6816 --- [           main] o.s.batch.core.job.SimpleStepHandler     : Executing step: [step1]
2020-07-20 08:16:31.490  INFO 6816 --- [           main] c.y.b.b.PersonItemProcessor              : Converting (firstName: Jill, lastName: Doe) into (firstName: JILL, lastName: DOE)
2020-07-20 08:16:31.490  INFO 6816 --- [           main] c.y.b.b.PersonItemProcessor              : Converting (firstName: Joe, lastName: Doe) into (firstName: JOE, lastName: DOE)
2020-07-20 08:16:31.490  INFO 6816 --- [           main] c.y.b.b.PersonItemProcessor              : Converting (firstName: Justin, lastName: Doe) into (firstName: JUSTIN, lastName: DOE)
2020-07-20 08:16:31.490  INFO 6816 --- [           main] c.y.b.b.PersonItemProcessor              : Converting (firstName: Jane, lastName: Doe) into (firstName: JANE, lastName: DOE)
2020-07-20 08:16:31.490  INFO 6816 --- [           main] c.y.b.b.PersonItemProcessor              : Converting (firstName: John, lastName: Doe) into (firstName: JOHN, lastName: DOE)
2020-07-20 08:16:31.495  INFO 6816 --- [           main] o.s.batch.core.step.AbstractStep         : Step: [step1] executed in 21ms
2020-07-20 08:16:31.497  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : !!! JOB FINISHED! Time to verify the results
2020-07-20 08:16:31.498  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JILL, lastName: DOE> in the database.
2020-07-20 08:16:31.498  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JOE, lastName: DOE> in the database.
2020-07-20 08:16:31.498  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JUSTIN, lastName: DOE> in the database.
2020-07-20 08:16:31.498  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JANE, lastName: DOE> in the database.
2020-07-20 08:16:31.498  INFO 6816 --- [           main] .y.b.b.JobCompletionNotificationListener : Found <firstName: JOHN, lastName: DOE> in the database.
2020-07-20 08:16:31.499  INFO 6816 --- [           main] o.s.b.c.l.support.SimpleJobLauncher      : Job: [FlowJob: [name=importUserJob]] completed with the following parameters: [{run.id=1}] and the following status: [COMPLETED] in 32ms
2020-07-20 08:16:31.501  INFO 6816 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown initiated...
2020-07-20 08:16:31.502  INFO 6816 --- [           main] com.zaxxer.hikari.HikariDataSource       : HikariPool-1 - Shutdown completed.

Process finished with exit code 0
           

源網站:https://spring.io/guides/gs/batch-processing/