モーダルを閉じる工作HardwareHub ロゴ画像

工作HardwareHubは、ロボット工作や電子工作に関する情報やモノが行き交うコミュニティサイトです。さらに詳しく

利用規約プライバシーポリシー に同意したうえでログインしてください。

工作HardwareHub ロゴ画像 (Laptop端末利用時)
工作HardwareHub ロゴ画像 (Mobile端末利用時)

Spring Batch サンプルコード (Java/Gradle)

モーダルを閉じる

ステッカーを選択してください

モーダルを閉じる

お支払い内容をご確認ください

購入商品
」ステッカーの表示権
メッセージ
料金
(税込)
決済方法
GooglePayマーク
決済プラットフォーム
確認事項

利用規約をご確認のうえお支払いください

※カード情報はGoogleアカウント内に保存されます。本サイトやStripeには保存されません

※記事の執筆者は購入者のユーザー名を知ることができます

※購入後のキャンセルはできません

作成日作成日
2017/05/26
最終更新最終更新
2019/11/25
記事区分記事区分
一般公開

目次

    アカウント プロフィール画像 (サイドバー)

    Spring Bootでの実用的な機能をわかりやすく解説中

    0
    ステッカーを贈るとは?

    Spring Boot でバッチ処理アプリケーションを作成します。内部的に Spring Batch を利用します。CSV ファイルを読み込んで、文字列加工して、MySQL DB に出力するバッチ処理です。

    公式ドキュメント

    プロジェクト構成

    .
    |-- build.gradle
    |-- gradle
    |   `-- wrapper
    |       |-- gradle-wrapper.jar
    |       `-- gradle-wrapper.properties
    |-- gradlew
    |-- gradlew.bat
    `-- src
        `-- main
            |-- java
            |   `-- hello
            |       |-- Application.java
            |       |-- BatchConfiguration.java
            |       |-- JobCompletionNotificationListener.java
            |       |-- Person.java
            |       `-- PersonItemProcessor.java
            `-- resources
                |-- application.properties
                |-- sample-data.csv
                `-- schema-all.sql
    

    build.gradle

    今回は Spring Batch を直接利用する場合は想定しておらず、あくまでも、Spring Batch を内部的に利用した Spring Boot アプリケーションです。

    buildscript {
        ext {
            springBootVersion = '1.5.3.RELEASE'
        }
        repositories {
            mavenCentral()
        }
        dependencies {
            classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
        }
    }
    
    apply plugin: 'java'
    apply plugin: 'eclipse'
    apply plugin: 'idea'
    apply plugin: 'org.springframework.boot'
    
    jar {
        baseName = 'gs-batch-processing'
        version =  '0.1.0'
    }
    
    repositories {
        mavenCentral()
    }
    
    sourceCompatibility = 1.8
    targetCompatibility = 1.8
    
    dependencies {
        // Spring Batch を内部的に利用します。
        // 今回は Web アプリケーションではないため `spring-boot-starter-web` は不要です。
        compile('org.springframework.boot:spring-boot-starter-batch')
    
        // http://search.maven.org/#artifactdetails|mysql|mysql-connector-java|6.0.6|jar
        compile('mysql:mysql-connector-java:6.0.6')
    }
    

    リソースファイル

    sample-data.csv

    今回のサンプル入力となる CSV ファイルです。

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

    application.properties

    出力先 MySQL DB への接続情報です。Spring Boot では、こちらのページに記載の優先順位でプロパティを読み込みます。今回は特に、「15. Application properties packaged inside your jar (JAR 内のアプリケーション設定ファイル)」を利用していることになります。ちなみに、「14. Application properties outside of your packaged jar (JAR 外のアプリケーション設定ファイル)」の方が優先順位が高いため、実行時に設定を上書きできます。設定項目の一覧はこちらです。

    spring.datasource.url=jdbc:mysql://localhost:3306/mydb
    spring.datasource.username=myuser
    spring.datasource.password=myuser
    spring.datasource.driver-class-name=com.mysql.jdbc.Driver
    

    application.yml を利用することもできます。

    spring:
      datasource:
        url: jdbc:mysql://localhost:3306/mydb
        username: myuser
        password: myuser
        driver-class-name: com.mysql.jdbc.Driver
    

    schema-all.sql

    出力先 MySQL テーブルの DDL です。こちらのページに記載されているとおり、schema-all.sql というファイル名の SQL がアプリケーション起動時に実行されます。より柔軟かつ高度な初期化処理が必要な場合は Flywayと連携するように設定します

    DROP TABLE IF EXISTS people;
    CREATE TABLE people (
        person_id BIGINT NOT NULL AUTO_INCREMENT,
        first_name VARCHAR(20),
        last_name VARCHAR(20),
        PRIMARY KEY (person_id)
    );
    

    プロパティ値をメンバ変数に設定 (参考)

    先程記載した優先順位に関するページで紹介されている @Value アノテーションを利用すると application.properties などで設定したプロパティをメンバ変数に設定して利用できます。Lombok の @Value と区別して利用します。

    package hello;
    
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @RestController
    public class HelloController {
    
        @Value("${spring.datasource.url}")
        private String datasourceUrl;
    
        @RequestMapping("/")
        public String index() {
            System.out.println(datasourceUrl);
            return "Greetings from Spring Boot! " + datasourceUrl;
        }
    }
    

    Java ソースコード

    Person.java

    mydb.people テーブル内の 1 レコードに対応するクラスです。

    package hello;
    
    public class Person {
        private String firstName;
        private String lastName;
    
        public Person() {
        }
    
        public Person(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }
    
        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }
    
        public void setLastName(String lastName) {
            this.lastName = lastName;
        }
    
        public String getFirstName() {
            return firstName;
        }
    
        public String getLastName() {
            return lastName;
        }
    
        @Override
        public String toString() {
            return "firstName: " + firstName + ", lastName: " + lastName;
        }
    }
    

    PersonItemProcessor.java

    一連バッチ処理「Read → Process → Write」における Process 処理のためのクラスです。Spring Batch が提供する ItemProcessor インターフェースを実装します。

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

    Application.java

    Spring Boot のエントリーポイントとなるクラスです。

    package hello;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class Application {
    
        public static void main(String[] args) throws Exception {
            SpringApplication.run(Application.class, args);
        }
    }
    

    JobCompletionNotificationListener.java

    必須ではありませんが、以下のように記述することで、バッチ処理が完了した後に実行する処理を設定できます。spring-jdbc を利用して DB からデータを SELECT しています。

    package hello;
    
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    
    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.jdbc.core.RowMapper;
    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");
    
                List<Person> results = jdbcTemplate.query("SELECT first_name, last_name FROM people", new RowMapper<Person>() {
                    @Override
                    public Person mapRow(ResultSet rs, int row) throws SQLException {
                        return new Person(rs.getString(1), rs.getString(2));
                    }
                });
    
                for (Person person : results) {
                    log.info("Found <" + person + "> in the database.");
                }
            }
        }
    }
    

    BatchConfiguration.java

    バッチ処理を設定するクラスです。

    package hello;
    
    import javax.sql.DataSource;
    
    import org.springframework.batch.core.Job;
    import org.springframework.batch.core.JobExecutionListener;
    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.file.FlatFileItemReader;
    import org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper;
    import org.springframework.batch.item.file.mapping.DefaultLineMapper;
    import org.springframework.batch.item.file.transform.DelimitedLineTokenizer;
    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 org.springframework.jdbc.core.JdbcTemplate;
    
    @Configuration
    @EnableBatchProcessing
    public class BatchConfiguration {
    
        @Autowired
        public JobBuilderFactory jobBuilderFactory;
    
        @Autowired
        public StepBuilderFactory stepBuilderFactory;
    
        @Autowired
        public DataSource dataSource;
    
        // reader/processor/writer
        @Bean
        public FlatFileItemReader<Person> reader() {
            FlatFileItemReader<Person> reader = new FlatFileItemReader<Person>();
            reader.setResource(new ClassPathResource("sample-data.csv"));
            reader.setLineMapper(new DefaultLineMapper<Person>() {{
                setLineTokenizer(new DelimitedLineTokenizer() {{
                    setNames(new String[] { "firstName", "lastName" });
                }});
                setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{
                    setTargetType(Person.class);
                }});
            }});
            return reader;
        }
    
        @Bean
        public PersonItemProcessor processor() {
            return new PersonItemProcessor();
        }
    
        @Bean
        public JdbcBatchItemWriter<Person> writer() {
            JdbcBatchItemWriter<Person> writer = new JdbcBatchItemWriter<Person>();
            writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Person>());
            writer.setSql("INSERT INTO people (first_name, last_name) VALUES (:firstName, :lastName)");
            writer.setDataSource(dataSource);
            return writer;
        }
    
        // job/step
        @Bean
        public Job importUserJob(JobCompletionNotificationListener listener) {
            return jobBuilderFactory.get("importUserJob")
                    .incrementer(new RunIdIncrementer())
                    .listener(listener)
                    .flow(step1())
                    .end()
                    .build();
        }
    
        @Bean
        public Step step1() {
            return stepBuilderFactory.get("step1")
                    .<Person, Person> chunk(10)
                    .reader(reader())
                    .processor(processor())
                    .writer(writer())
                    .build();
        }
    }
    
    項目 概要
    @Configuration @Bean 定義を行うクラスに設定します。
    @EnableBatchProcessing Spring Batch のバッチ処理を定義するクラスに設定します。
    @Autowired 他のクラスの Bean 定義で生成されたシングルトンを関連付けて利用できるようにします。
    @Bean @Configuration が設定されたクラスのメソッドに対して設定できます。@Bean 設定されたメソッドはインスタンスを返します。これは設定値をもつシングルトンとして、アプリケーション全体で利用できます。

    アプリケーション実行

    ./gradlew build && java -jar build/libs/gs-batch-processing-0.1.0.jar
    (or ./gradlew bootRun)
    

    実行結果は以下のとおりです。すべて大文字化されて、レコードとして格納されました。

    mysql> show tables from mydb;
    +------------------------------+
    | Tables_in_mydb               |
    +------------------------------+
    | BATCH_JOB_EXECUTION          |
    | BATCH_JOB_EXECUTION_CONTEXT  |
    | BATCH_JOB_EXECUTION_PARAMS   |
    | BATCH_JOB_EXECUTION_SEQ      |
    | BATCH_JOB_INSTANCE           |
    | BATCH_JOB_SEQ                |
    | BATCH_STEP_EXECUTION         |
    | BATCH_STEP_EXECUTION_CONTEXT |
    | BATCH_STEP_EXECUTION_SEQ     |
    | people                       |  ←結果
    +------------------------------+
    10 rows in set (0.00 sec)
    
    mysql> select * from mydb.people;
    +-----------+------------+-----------+
    | person_id | first_name | last_name |
    +-----------+------------+-----------+
    |         1 | JILL       | DOE       |
    |         2 | JOE        | DOE       |
    |         3 | JUSTIN     | DOE       |
    |         4 | JANE       | DOE       |
    |         5 | JOHN       | DOE       |
    +-----------+------------+-----------+
    5 rows in set (0.00 sec)
    
    0
    詳細設定を開く/閉じる
    アカウント プロフィール画像 (本文下)

    Spring Bootでの実用的な機能をわかりやすく解説中

    記事の執筆者にステッカーを贈る

    有益な情報に対するお礼として、またはコメント欄における質問への返答に対するお礼として、 記事の読者は、執筆者に有料のステッカーを贈ることができます。

    さらに詳しく →
    ステッカーを贈る コンセプト画像

    Feedbacks

    Feedbacks コンセプト画像

      ログインするとコメントを投稿できます。

      関連記事

      • Spring Security フォームログインのサンプルコード
        Spring フレームワークによる Web アプリケーション開発で、ログイン処理を実装する際は Spring Security が便利です。ここでは特に Spring Boot で Web アプリケーションを開発する場合を対象とし、フォームによる ID/Password ログインを行うためのサンプルコードをまとめます。 公式ドキュメント [Spring Security チュートリアル](http...
        えびちゃんえびちゃん12/4/2019に更新
        いいねアイコン画像0
      • Java配列の宣言方法 (C/C++との違い)
        Javaの配列 Javaの配列宣言方法はC/C++と似ているようで若干異なる。 初期化しない場合 C/C++の int array[10]; はJavaでは int array[] = new int[10]; となる。同様にC/C++の int array[3][3]; はJavaでは int array[][] = new int[3][3]; となる。 初期化
        てんとうむしてんとうむし5/13/2018に更新
        いいねアイコン画像0
      • PlantUML による UML 図の描き方
        サムネイル画像-c788fffde5
        PlantUML はテキスト形式で表現されたシーケンス図やクラス図といった UML (Unified Modeling Language) 図の情報から画像を生成するためのツールです。簡単な使い方をまとめます。 インストール方法の選択 Atom や Eclipse のプラグインをインストールしてエディタから利用する方法、JAR をダウンロードして Java コマンドで実行する方法、Redmine ...
        kentakenta1/21/2020に更新
        いいねアイコン画像0
      • Akka HTTP サンプルコード (Scala)
        サムネイル画像-a98142497c
        Akka アクターを用いて実装された汎用 HTTP フレームワークです。Spray の後継です。コアモジュールである akka-http-core は 2016/2/17 に experimental が外れました。akka-http などのいくつかのサブモジュールは 2016/3/1 現在 experimental のままですが、基本的な
        雄太雄太10/7/2021に更新
        いいねアイコン画像0
      • Kestrel の使用例
        Kestrel は Message Queue (MQ) の実装のひとつです。一般に MQ はアプリケーション間やプロセス間、スレッド間で非同期に通信するために用いられます。メッセージの送信側は MQ に書き込めば受信側の応答を待たずに次の処理に非同期に進むことができます。Kestrel はわずか 2500 行程の Scala で実装されており JVM で動作します。MQ 自体はメモリ上に存在する...
        したくんしたくん10/12/2017に更新
        いいねアイコン画像0