Spring Batch 之 Sample(復(fu)合格式文件(jian)的讀(du)、多文件(jian)的寫)(七)
前面關于Spring Batch的文章,講述了SpringBatch對CSV文件的讀寫操作、對XML文件的操作,以及對固定長格式文件的操作。這些事例,同(tong)一個(ge)Reader讀取的都是相同(tong)格式的數據,最終寫入一個(ge)文件。如果遇到下面這樣的數據,并想將(jiang)學生信(xin)息和商(shang)品信(xin)息分類后寫入兩個(ge)文件,應該如何處理(li)呢?
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開(kai)頭的數(shu)據代表(biao)學生信息,以goods開(kai)頭代表(biao)商(shang)品信息
這次將和大家一(yi)起探討Spring Batch讀取復合(he)格式(shi)的(de)(de)數據,然后寫入不同的(de)(de)文(wen)件的(de)(de)處理(li)方(fang)式(shi)。
工程結構如下(xia)圖(tu):

applicationContext.xml和log4j.xml前文已經敘述(shu)過,在此不(bu)做贅(zhui)述(shu)。
本實例(li)的核心(xin)配(pei)置文件batch.mxl內容(rong)如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <bean:beans xmlns="//www.springframework.org/schema/batch"
3 xmlns:bean="//www.springframework.org/schema/beans" xmlns:xsi="//www.w3.org/2001/XMLSchema-instance"
4 xmlns:p="//www.springframework.org/schema/p" xmlns:tx="//www.springframework.org/schema/tx"
5 xmlns:aop="//www.springframework.org/schema/aop" xmlns:context="//www.springframework.org/schema/context"
6 xmlns:util="//www.springframework.org/schema/util"
7 xsi:schemaLocation="//www.springframework.org/schema/beans
8 //www.springframework.org/schema/beans/spring-beans-3.0.xsd
9 //www.springframework.org/schema/tx
10 //www.springframework.org/schema/tx/spring-tx-3.0.xsd
11 //www.springframework.org/schema/aop
12 //www.springframework.org/schema/aop/spring-aop-3.0.xsd
13 //www.springframework.org/schema/context
14 //www.springframework.org/schema/context/spring-context-2.5.xsd
15 //www.springframework.org/schema/batch
16 //www.springframework.org/schema/batch/spring-batch-2.1.xsd
17 //www.springframework.org/schema/util //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 <!-- 不同(tong)格式數據的文件(jian)讀取 -->
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
42 class="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 <!-- 學(xue)生(sheng)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 <!-- 商(shang)品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 <!-- 學生(sheng)信息的寫 -->
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
112 class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
113 <bean:property name="fieldExtractor">
114 <bean:bean
115 class="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 <!-- 商品(pin)信息的寫 -->
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
130 class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
131 <bean:property name="fieldExtractor">
132 <bean:bean
133 class="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行配置(zhi)了(le)Job的基本信(xin)息。
36-57行配(pei)置(zhi)了Reader的(de)(de)(de)(de)基本(ben)信息。FlatFileItemReader的(de)(de)(de)(de)lineMapper屬性使(shi)用SpringBatch核心類PatternMatchingCompositeLineMapper的(de)(de)(de)(de)時候(hou),會將讀(du)取的(de)(de)(de)(de)記(ji)錄按照(zhao)不同(tong)(tong)的(de)(de)(de)(de)方式映(ying)射(she)成(cheng)我(wo)們(men)的(de)(de)(de)(de)Pojo對象(xiang)。當(dang)然(ran)首先我(wo)們(men)要配(pei)置(zhi)不同(tong)(tong)的(de)(de)(de)(de)tokenizers(43-48)和(he)fieldSetMappers(49-54),并告訴它當(dang)前的(de)(de)(de)(de)記(ji)錄按照(zhao)那條(tiao)原則去(qu)解(jie)析(xi)和(he)映(ying)射(she)。如45行所示(shi),我(wo)們(men)指定(ding)key為student*的(de)(de)(de)(de)時候(hou),用studentTokenizer去(qu)解(jie)析(xi)成(cheng)fieldset,用studentFieldSetMapper將studentTokenizer解(jie)析(xi)好的(de)(de)(de)(de)fieldset記(ji)錄映(ying)射(she)成(cheng)Student對象(xiang)。我(wo)們(men)指定(ding)的(de)(de)(de)(de)key,其實也就是student開頭的(de)(de)(de)(de)記(ji)錄,*是通配(pei)符(fu)。PatternMatchingCompositeLineMapper支持兩(liang)種通配(pei)符(fu):*和(he)?,前者代表多個字(zi)符(fu),后者僅(jin)代表一個字(zi)符(fu)。至于student和(he)goods信息如何映(ying)射(she)成(cheng)pojo對象(xiang),前面的(de)(de)(de)(de)文章中已經做(zuo)過詳(xiang)細(xi)的(de)(de)(de)(de)介紹,這里就不做(zuo)贅述了。
96-104行配置了Writer的(de)基本信(xin)(xin)息。Writer也是使(shi)用代(dai)理的(de)方式,學生信(xin)(xin)息使(shi)用106-122行定義(yi)的(de)studentWriter按照(zhao)固(gu)定長的(de)格(ge)式寫入學生信(xin)(xin)息文(wen)件(jian)中(zhong),商品信(xin)(xin)息使(shi)用124-141行定義(yi)的(de)goodsWriter按照(zhao)CSV的(de)格(ge)式寫入商品信(xin)(xin)息文(wen)件(jian)中(zhong)。MultiItemWriter的(de)代(dai)碼很簡單(dan),就(jiu)不做詳(xiang)細解(jie)釋了。如下:
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")
public class MultiItemWriter<T> implements ItemWriter<T> {
/** 寫代(dai)理(li) */
private List<ItemWriter<? super T>> delegates;
public void setDelegates(List<ItemWriter<? super T>> delegates) {
this.delegates = delegates;
}
@Override
public void write(List<? extends T> items) throws Exception {
// 學生(sheng)信息(xi)的Writer
ItemWriter studentWriter = (ItemWriter) delegates.get(0);
// 商(shang)品信(xin)息的Writer
ItemWriter goodsWriter = (ItemWriter) delegates.get(1);
// 學生(sheng)信(xin)息
List<Student> studentList = new ArrayList<Student>();
// 商品(pin)信息(xi)
List<Goods> goodsList = new ArrayList<Goods>();
// 將傳(chuan)過來(lai)的(de)信息(xi)按照不(bu)同(tong)的(de)類型添加到不(bu)同(tong)的(de)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));
}
}
// 如果學生(sheng)List中有數據,就(jiu)執行學生(sheng)信息(xi)的寫
if (studentList.size() > 0) {
studentWriter.write(studentList);
}
// 如果商(shang)品List中有數據,就(jiu)執行商(shang)品信息的(de)寫
if (goodsList.size() > 0) {
goodsWriter.write(goodsList);
}
}
}
至此(ci),復合文件的(de)讀寫操作(zuo)已經(jing)討論結束(shu)了。注(zhu)意實例沒有配置Processor。下面是一些(xie)輔助文件的(de)信息。
student和(he)goods類的(de)信息與前面文章一樣,就不再貼(tie)出代碼了。
Job啟動(dong)的代(dai)碼如下:
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;
public class Launch {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"batch.xml");
JobLauncher launcher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("multiTypeSingleFileJob");
try {
// JOB實行(xing)
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());
// 運(yun)行結(jie)果輸出
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Input文件內容如下圖:

處(chu)理結(jie)果(guo)的學生信息文件如下圖:

處理(li)結果的商品(pin)信息(xi)文件如下圖:

Spring Batch對復合格式文件的讀寫操作就討論到這里。至此,Spring Batch對文件簡單操作的討論也告一段落,下次將討論Spring Batch讀寫DB的操作。
歡迎轉載,請注明出處!
感謝您的閱讀,請關注后續博客!
共享視頻教程請訪問:
