Spring Batch 之 Sample(複合格式文件的讀、多文件的寫)(七)

 前面關於Spring Batch的文章,講述了SpringBatch對CSV文件的讀寫操作對XML文件的操作,以及對固定長格式文件的操作。這些事例,同一個Reader讀取的都是相同格式的數據,最終寫入一個文件。如果遇到下面這樣的數據,並想將學生信息和商品信息分類後寫入兩個文件,應該如何處理呢?

student,200001,ZhangSan,18,78
goodsPNH001011000200.1zhangshana2011/12/18 01:12:36
student,200002,LiSi,19,79
goodsPNH001022000300.1zhangshanb2011/12/19 01:12:36
student,200003,WangWu,20,80
goodsPNH001033000400.1zhangshanc2011/12/20 01:12:36

  * 以student開頭的數據代表學生信息,以goods開頭代表商品信息

這次將和大家一起探討Spring Batch讀取複合格式的數據,然後寫入不同的文件的處理方式。

      工程結構如下圖:

       applicationContext.xml和log4j.xml前文已經敘述過,在此不做贅述。

      本實例的核心配置文件batch.mxl內容如下:

  1<?xml version="1.0" encoding="UTF-8"?>
2<bean:beans xmlns="http://www.springframework.org/schema/batch"
3 xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
5 xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
6 xmlns:util="http://www.springframework.org/schema/util"
7 xsi:schemaLocation="http://www.springframework.org/schema/beans
8http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
9http://www.springframework.org/schema/tx
10http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
11http://www.springframework.org/schema/aop
12http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
13http://www.springframework.org/schema/context
14http://www.springframework.org/schema/context/spring-context-2.5.xsd
15http://www.springframework.org/schema/batch
16http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
17http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
18
19<bean:import resource="applicationContext.xml"/>
20<!-- Job的配置信息 -->
21<job id="multiTypeSingleFileJob">
22<step id="xmlFileReadAndWriterStep">
23<tasklet>
24<chunk reader="multiTypesItemReader" writer="multiTypesItemWriter"
25 commit-interval="1">
26<streams>
27<stream ref="studentWriter"/>
28<stream ref="goodsWriter"/>
29</streams>
30</chunk>
31</tasklet>
32</step>
33</job>
34
35<!-- 不同格式數據的文件讀取 -->
36<bean:bean id="multiTypesItemReader"
37 class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
38<bean:property name="resource"
39 value="file:#{jobParameters['inputFilePath']}"/>
40<bean:property name="lineMapper">
41<bean:bean
42class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper">
43<bean:property name="tokenizers">
44<bean:map>
45<bean:entry key="student*" value-ref="studentTokenizer"/>
46<bean:entry key="goods*" value-ref="goodsTokenizer"/>
47</bean:map>
48</bean:property>
49<bean:property name="fieldSetMappers">
50<bean:map>
51<bean:entry key="student*" value-ref="studentFieldSetMapper"/>
52<bean:entry key="goods*" value-ref="goodsFieldSetMapper"/>
53</bean:map>
54</bean:property>
55</bean:bean>
56</bean:property>
57</bean:bean>
58<bean:bean id="studentTokenizer"
59 class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
60<bean:property name="delimiter" value=","/>
61<bean:property name="names">
62<bean:list>
63<bean:value>student</bean:value>
64<bean:value>ID</bean:value>
65<bean:value>name</bean:value>
66<bean:value>age</bean:value>
67<bean:value>score</bean:value>
68</bean:list>
69</bean:property>
70</bean:bean>
71<bean:bean id="studentFieldSetMapper"
72 class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
73<bean:property name="prototypeBeanName" value="student"/>
74<bean:property name="distanceLimit" value="100"/>
75</bean:bean>
76<!-- 學生Pojo類 -->
77<bean:bean id="student"
78 class="com.wanggc.springbatch.sample.multitypessinglefile.pojo.Student"
79 scope="prototype"/>
80
81<bean:bean id="goodsTokenizer"
82 class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
83<bean:property name="columns" value="6-13,14-17,18-22,23-32,33-"/>
84<bean:property name="names"
85 value="isin,quantity,price,customer,buyDay"/>
86</bean:bean>
87<bean:bean id="goodsFieldSetMapper"
88 class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
89<bean:property name="prototypeBeanName" value="goods"/>
90</bean:bean>
91<!-- 商品Pojo類 -->
92<bean:bean id="goods"
93 class="com.wanggc.springbatch.sample.multitypessinglefile.pojo.Goods"
94 scope="prototype"/>
95
96<bean:bean id="multiTypesItemWriter"
97 class="com.wanggc.springbatch.sample.multitypessinglefile.MultiItemWriter">
98<bean:property name="delegates">
99<bean:list>
100<bean:ref bean="studentWriter"/>
101<bean:ref bean="goodsWriter"/>
102</bean:list>
103</bean:property>
104</bean:bean>
105<!-- 學生信息的寫 -->
106<bean:bean id="studentWriter"
107 class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
108<bean:property name="resource"
109 value="file:#{jobParameters['outputFilePathStudent']}"/>
110<bean:property name="lineAggregator">
111<bean:bean
112class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
113<bean:property name="fieldExtractor">
114<bean:bean
115class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
116<bean:property name="names" value="ID,name,age,score"/>
117</bean:bean>
118</bean:property>
119<bean:property name="format" value="%-9s%-9s%3d%-2.0f"/>
120</bean:bean>
121</bean:property>
122</bean:bean>
123<!-- 商品信息的寫 -->
124<bean:bean id="goodsWriter"
125 class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
126<bean:property name="resource"
127 value="file:#{jobParameters['outputFilePathGoods']}"/>
128<bean:property name="lineAggregator">
129<bean:bean
130class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
131<bean:property name="fieldExtractor">
132<bean:bean
133class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
134<bean:property name="names"
135 value="isin,quantity,price,customer,buyDay"/>
136</bean:bean>
137</bean:property>
138</bean:bean>
139</bean:property>
140</bean:bean>
141</bean:beans>

       21-33行配置了Job的基本信息。  

      36-57行配置了Reader的基本信息。FlatFileItemReader的lineMapper屬性使用SpringBatch核心類PatternMatchingCompositeLineMapper的時候,會將讀取的記錄按照不同的方式映射成我們的Pojo對象。當然首先我們要配置不同的tokenizers(43-48)和fieldSetMappers(49-54),並告訴它當前的記錄按照那條原則去解析和映射。如45行所示,我們指定key爲student*的時候,用studentTokenizer去解析成fieldset,用studentFieldSetMapper將studentTokenizer解析好的fieldset記錄映射成Student對象。我們指定的key,其實也就是student開頭的記錄,*是通配符。PatternMatchingCompositeLineMapper支持兩種通配符:*和?,前者代表多個字符,後者僅代表一個字符。至於student和goods信息如何映射成pojo對象,前面的文章中已經做過詳細的介紹,這裏就不做贅述了。

      96-104行配置了Writer的基本信息。Writer也是使用代理的方式,學生信息使用106-122行定義的studentWriter按照固定長的格式寫入學生信息文件中,商品信息使用124-141行定義的goodsWriter按照CSV的格式寫入商品信息文件中。MultiItemWriter的代碼很簡單,就不做詳細解釋了。如下:

package com.wanggc.springbatch.sample.multitypessinglefile;

import java.util.ArrayList;
import java.util.List;

import org.springframework.batch.item.ItemWriter;

import com.wanggc.springbatch.sample.multitypessinglefile.pojo.Goods;
import com.wanggc.springbatch.sample.multitypessinglefile.pojo.Student;

/**
* 寫處理類。
*
*
@author Wanggc
*
*
@param <T>
*/
@SuppressWarnings("unchecked")
publicclass MultiItemWriter<T> implements ItemWriter<T> {
/** 寫代理 */
private List<ItemWriter<? super T>> delegates;

publicvoid setDelegates(List<ItemWriter<? super T>> delegates) {
this.delegates = delegates;
}

@Override
publicvoid write(List<? extends T> items) throws Exception {
// 學生信息的Writer
ItemWriter studentWriter = (ItemWriter) delegates.get(0);
// 商品信息的Writer
ItemWriter goodsWriter = (ItemWriter) delegates.get(1);
// 學生信息
List<Student> studentList = new ArrayList<Student>();
// 商品信息
List<Goods> goodsList = new ArrayList<Goods>();
// 將傳過來的信息按照不同的類型添加到不同的List中
for (int i = 0; i < items.size(); i++) {
if ("Student".equals(items.get(i).getClass().getSimpleName())) {
studentList.add((Student) items.get(i));
} else {
goodsList.add((Goods) items.get(i));
}
}
// 如果學生List中有數據,就執行學生信息的寫
if (studentList.size() > 0) {
studentWriter.write(studentList);
}
// 如果商品List中有數據,就執行商品信息的寫
if (goodsList.size() > 0) {
goodsWriter.write(goodsList);
}
}
}

      至此,複合文件的讀寫操作已經討論結束了。注意實例沒有配置Processor。下面是一些輔助文件的信息。

      student和goods類的信息與前面文章一樣,就不再貼出代碼了。

      Job啓動的代碼如下:

package com.wanggc.springbatch.sample.multitypessinglefile;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

publicclass Launch {
publicstaticvoid main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"batch.xml");
JobLauncher launcher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("multiTypeSingleFileJob");

try {
// JOB實行
JobExecution result = launcher.run(
job,
new JobParametersBuilder()
.addString("inputFilePath",
"C:\\testData\\multiTypesInput.txt")
.addString("outputFilePathStudent",
"C:\\testData\\student.txt")
.addString("outputFilePathGoods",
"C:\\testData\\goods.csv")
.toJobParameters());
// 運行結果輸出
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}

      Input文件內容如下圖:

      處理結果的學生信息文件如下圖:

     處理結果的商品信息文件如下圖:

      Spring Batch對複合格式文件的讀寫操作就討論到這裏。至此,Spring Batch對文件簡單操作的討論也告一段落,下次將討論Spring Batch讀寫DB的操作。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章