batch Spring

Spring Batch批次處理框架

羅伊辰 2017/12/29 01:56:47
7238

Spring Batch批次處理框架


簡介

介紹Spring Batch環境相關設定。

作者

羅伊辰


前言

  Spring Batch 批次處理框架可以應用于企業級大量的資料處理系統。以 POJO 和大家熟知的 Spring 框架為基礎。本文分別用兩個範例作為說明,範例一介紹如何在eclipsemaven環境搭建Spring Batch框架,並手動執行作業;範例二則以搭建好的框架為基礎,設定SpringBatch使其定時執行作業。

目的

1) 了解 Spring Batch 基本架構及環境設定,以及如何啟動 SpringBatch 作業

2)了解如何設定SpringBatch,使其定時執行作業。

開始前準備

Eclipse with Maven
Jave Jdk 1.7
Database Postgresql 9.3

架構說明

1) JobRepository 負責提供 Launcher Job Step 的持久化機制,負責運行中的 CRUD
2) 一個 JobLauncher 觸發相對應的 Job
3) 一個 Job 有數個 Step
4) Step 有三種應對:分別是 資料讀取( ItemReader )、資料處理( ItemProcessor )、資料寫入( ItemWriter )。

範例一、搭建環境暨手動執行作業:     

A.       新增Maven專案後,建立以下目錄:

-建立resoures 路徑 src/main/resoures

-建立設定檔存放路徑  src/main/resoures/config

-建立資料庫資訊檔存放路徑  src/main/resoures/config/database

-建立Spring batch 設定檔存放路徑 src/main/resoures/config/springbatch

-建立測試資料檔存放路徑  src/main/resoures/csv

B.       新增 database.xml ,加入資料庫資訊
 
src/main/resoures/config/database/database.xml
 
database.xml 內容

<beans xmlns="http://www.springframework.org/schema/beans"

   xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

   xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

    http://www.springframework.org/schema/jdbc

    http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd">

 

 

   <!-- database 連線設定 -->

   <bean id="dataSource"

    class="org.springframework.jdbc.datasource.DriverManagerDataSource">

    <property name="driverClassName" value="org.postgresql.Driver" />

    <property name="url" value="jdbc:postgresql://127.0.0.1:5433/springTest" />

    <property name="username" value="postgres" />

    <property name="password" value="postgres" />

   </bean>

 

   <bean id="transactionManager"

    class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />

 

   <jdbc:initialize-database data-source="dataSource">

    <jdbc:script

     location="org/springframework/batch/core/schema-drop-postgresql.sql" />

    <jdbc:script location="org/springframework/batch/core/schema-postgresql.sql" />

   </jdbc:initialize-database>

 

  </beans>

C.       建立 Spring Batch 相關設定檔
 
 src/main/resoures/config/springbatch/jobs-context.xml
 src/main/resoures/config/springbatch/spring-batch.xml
 
  jobs-context.xml 內容

<beans xmlns="http://www.springframework.org/schema/beans"

 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="

  http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">

 

 <!--設定 JOB database 的關係-->

 <bean id="jobRepository"

  class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean">

  <property name="dataSource" ref="dataSource" />

  <property name="transactionManager" ref="transactionManager" />

  <property name="databaseType" value="POSTGRES" />

 </bean>

 

 <bean id="jobLauncher"

  class="org.springframework.batch.core.launch.support.SimpleJobLauncher">

  <property name="jobRepository" ref="jobRepository" />

 </bean>

 

</beans>

spring-batch.xml 內容     
 

<beans xmlns="http://www.springframework.org/schema/beans"

 xmlns:batch="http://www.springframework.org/schema/batch" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xsi:schemaLocation="http://www.springframework.org/schema/batch

  http://www.springframework.org/schema/batch/spring-batch-3.0.xsd

  http://www.springframework.org/schema/beans

  http://www.springframework.org/schema/beans/spring-beans-4.0.xsd

 ">

 

 <import resource="jobs-context.xml" />

 <import resource="../database/database.xml" />

 

 <!-- 設定model -->

 <bean id="report" class="com.levin.model.Report" scope="prototype" />

 <!-- 設定item Processor -->

 <bean id="itemProcessor" class="com.levin.ReportItemProcessor" />

 

 <!-- -->

 <batch:job id="helloWorldJob">

  <batch:step id="step1">

   <batch:tasklet>

    <batch:chunk reader="csvFileItemReader" writer="xmlItemWriter"

     processor="itemProcessor" commit-interval="10">

    </batch:chunk>

   </batch:tasklet>

  </batch:step>

 </batch:job>

 

 <bean id="csvFileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader">

  <!-- 取得csv資料 -->

  <property name="resource" value="classpath:csv/reportData.csv" />

 

  <property name="lineMapper">

   <bean class="org.springframework.batch.item.file.mapping.DefaultLineMapper">

    <property name="lineTokenizer">

     <bean

      class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">

      <!-- 設定欄位名稱 -->

      <property name="names" value="id,sales,qty,staffName,date" />

     </bean>

    </property>

    <property name="fieldSetMapper">

     <!-- 設定檔案讀取程式 -->

     <bean class="com.levin.ReportFieldSetMapper" />

    </property>

   </bean>

  </property>

 

 </bean>

 

 <!-- 設定寫出資料程式 -->

 <bean id="xmlItemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">

  <!-- 寫出資料存放位置 -->

  <property name="resource" value="file:xml/outputs/report.xml" />

  <property name="marshaller" ref="reportMarshaller" />

  <property name="rootTagName" value="report" />

 </bean>

 <!-- 設定寫出xml model -->

 <bean id="reportMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">

  <property name="classesToBeBound">

   <list>

    <value>com.levin.model.Report</value>

   </list>

  </property>

 </bean>

 

 

</beans>  

完成後如下

D.      建立 csv 測試資料檔
 
 
    資料存放位置: src/main/resoures/csv/reportData.csv  

inpu資料檔(reportData.csv)內容:


1001, "213,12" ,  980 , Levin  ,  2013/1/02
1002, "220,20", 1080 , tom 1 ,  2013/2/4
1003, "252,19" , 2200 , tom 2 ,  2013/11/10
1003, "248,19" , 1500 , tom 3 ,  2013/10/20
1003, "552,18" , 2800 , tom 4 ,  2013/6/15
1003, "323,78" , 1900 , tom 5 ,  2013/5/12

  

E.       建立相關java程式

新增model Report.java for資料欄位 mapping
檔案路徑: src/main/java/com/levin/model/Report.java 

package com.levin.model;
 
import java.math.BigDecimal;
import java.util.Date;
 
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
 * 訂單報表
 */
@XmlRootElement(name = "record")
public class Report {
 
 /**
  * 編號
  */
 private int id;
 /**
  * 銷售
  */
 private BigDecimal sales;
 /**
  * 數量
  */
 private int qty;
 /**
  * 銷售人員名稱
  */
 private String staffName;
 /**
  * 日期
  */
 private Date date;
 
 @XmlAttribute(name = "id")
 public int getId() {
  return id;
 }
 
 public void setId(int id) {
  this.id = id;
 }
 
 @XmlElement(name = "sales")
 public BigDecimal getSales() {
  return sales;
 }
 
 public void setSales(BigDecimal sales) {
  this.sales = sales;
 }
 
 @XmlElement(name = "qty")
 public int getQty() {
  return qty;
 }
 
 public void setQty(int qty) {
  this.qty = qty;
 }
 
 @XmlElement(name = "staffName")
 public String getStaffName() {
  return staffName;
 }
 
 public void setStaffName(String staffName) {
  this.staffName = staffName;
 }
 
 public Date getDate() {
  return date;
 }
 
 public void setDate(Date date) {
  this.date = date;
 }
 
 @Override
 public String toString() {
  return "Report [id=" + id + ", sales=" + sales + ", qty=" + qty + ", staffName=" + staffName + "]";
 }
 
}
  - 新增 讀資料程式 ReportFieldSetMapper.java

檔案路徑: src/main/java/com/levin/ReportFieldSetMapper.java

 

package com.levin;
 
import java.text.ParseException;
import java.text.SimpleDateFormat;
 
import org.springframework.batch.item.file.mapping.FieldSetMapper;
import org.springframework.batch.item.file.transform.FieldSet;
import org.springframework.validation.BindException;
 
import com.levin.model.Report;
 
public class ReportFieldSetMapper implements FieldSetMapper {
 
 private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
 
 public Report mapFieldSet(FieldSet fieldSet) throws BindException {
  
  Report report = new Report();
  report.setId(fieldSet.readInt(0));
  report.setSales(fieldSet.readBigDecimal(1));
  report.setQty(fieldSet.readInt(2));
  report.setStaffName(fieldSet.readString(3));
  
  //fieldSet.readDate(4); //預設的 format yyyy-MM-dd
  String date = fieldSet.readString(4);
  try {
   report.setDate(dateFormat.parse(date));
  } catch (ParseException e) {
   e.printStackTrace();
  }
  
  return report;
  
 }
 
}

 

 

 

 

新增處理資料項目程式 ReportItemProcessor.java
檔案路徑: src/main/java/com/levin/ReportItemProcessor.java

 

package com.levin;
 
import org.springframework.batch.item.ItemProcessor;
 
import com.levin.model.Report;
 
public class ReportItemProcessor implements ItemProcessor {
 
 public Report process(Report item) throws Exception {
  
  System.out.println("執行中..." + item);
  return item;
 }
 
}

 

-新增程式進入點 App.java,用以spring batch
檔案路徑: src/main/java/com/levin/App.java

 

 

 

完成後如下

  此案將輸入資料轉成 xml 檔,自 App.java 啟動程式後,輸出如下

範例二、設定scheduler使其每五秒鐘執行一次特定作業

  新增程式 BatchJob.java
  Spring-Batch.xml 中新增以下標籤,並設定 con 屬性值為 */5***** 代表每五秒鐘執行一次 BatchJob.java 程式

 

  開啟範例一中的 App.java 程式,保留讀取 spring-batch.xml 的部分,其餘註解掉

 

App.java啟動程式後,執行結果如下,每五秒鐘於console印出字串

羅伊辰