Spring Batch 之 Sample(XML文件操作)(五)
前篇關于Spring Batch的文章,講述了Spring Batch 對CSV文件的讀寫操作。 本文將通過一個(ge)(ge)完整的(de)(de)實(shi)(shi)例(li),與大家一起討論運用(yong)Spring Batch對XML文件的(de)(de)讀(du)寫(xie)操作。實(shi)(shi)例(li)流程是從一個(ge)(ge)XML文件中(zhong)讀(du)取(qu)商品信息,經過簡(jian)單的(de)(de)處理,寫(xie)入另外一個(ge)(ge)XML文件中(zhong)。
工程結構(gou)如下圖:

log4j.xml是(shi)log處理的(de)配置文件,與本文沒(mei)有必然聯系,再此(ci)不做論述。
application.xml文件內容如下:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <beans xmlns="//www.springframework.org/schema/beans"
3 xmlns:xsi="//www.w3.org/2001/XMLSchema-instance" xmlns:p="//www.springframework.org/schema/p"
4 xmlns:tx="//www.springframework.org/schema/tx" xmlns:aop="//www.springframework.org/schema/aop"
5 xmlns:context="//www.springframework.org/schema/context"
6 xsi:schemaLocation="//www.springframework.org/schema/beans
7 //www.springframework.org/schema/beans/spring-beans-3.0.xsd
8 //www.springframework.org/schema/tx
9 //www.springframework.org/schema/tx/spring-tx-3.0.xsd
10 //www.springframework.org/schema/aop
11 //www.springframework.org/schema/aop/spring-aop-3.0.xsd
12 //www.springframework.org/schema/context
13 //www.springframework.org/schema/context/spring-context-2.5.xsd"
14 default-autowire="byName">
15
16 <!-- auto scan path -->
17 <context:component-scan base-package="com.wanggc.springbatch.sample.xml" />
18
19 <bean id="jobLauncher"
20 class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
21 <property name="jobRepository" ref="jobRepository" />
22 </bean>
23
24 <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean" />
25
26 <bean id="transactionManager"
27 class="org.springframework.batch.support.transaction.ResourcelessTransactionManager">
28 </bean>
29 </beans>
17行是base-spckage的(de)指(zhi)定,是spring的(de)用法。
19-22行配置的(de)jobLauncher用來啟動Job。
24行配置的jobRepository為job提供持久化操作。
26-28行的(de)transactionManager提(ti)供事物管理操作。
本(ben)文核心配(pei)置文件batch.xml內容如(ru)下:
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
21 <job id="xmlFileReadAndWriterJob">
22 <step id="xmlFileReadAndWriterStep">
23 <tasklet>
24 <chunk reader="xmlReader" writer="xmlWriter" processor="xmlProcessor"
25 commit-interval="10">
26 </chunk>
27 </tasklet>
28 </step>
29 </job>
30
31 <!-- XML文(wen)件讀取 -->
32 <bean:bean id="xmlReader"
33 class="org.springframework.batch.item.xml.StaxEventItemReader" scope="step">
34 <bean:property name="fragmentRootElementName" value="goods" />
35 <bean:property name="unmarshaller" ref="tradeMarshaller" />
36 <bean:property name="resource"
37 value="file:#{jobParameters['inputFilePath']}"></bean:property>
38 </bean:bean>
39
40 <!-- XML文件寫入 -->
41 <bean:bean id="xmlWriter"
42 class="org.springframework.batch.item.xml.StaxEventItemWriter" scope="step">
43 <bean:property name="rootTagName" value="wanggc" />
44 <bean:property name="marshaller" ref="tradeMarshaller" />
45 <bean:property name="resource"
46 value="file:#{jobParameters['outputFilePath']}" />
47 </bean:bean>
48
49 <bean:bean id="tradeMarshaller"
50 class="org.springframework.oxm.xstream.XStreamMarshaller">
51 <bean:property name="aliases">
52 <util:map id="aliases">
53 <bean:entry key="goods"
54 value="com.wanggc.springbatch.sample.xml.pojo.Goods" />
55 <bean:entry key="buyDay" value="java.util.Date"></bean:entry>
56 </util:map>
57 </bean:property>
58 </bean:bean>
59 </bean:beans>
21-29行配置了Job的基本(ben)信息。此Job包含一個Step,Step中包含了基本(ben)的讀(xmlReader),處理(xmlProcessor),寫(xmlWriter)。
32-38行配置了對XML文(wen)件讀操作。對XML的(de)讀是(shi)(shi)由(you)SpringBatch提供的(de)StaxEventItemReader類來完成。要讀取一個XML文(wen)件,首先要知(zhi)道(dao)(dao)這(zhe)(zhe)個文(wen)件的(de)存放路徑(jing),resource屬(shu)(shu)性(xing)就是(shi)(shi)指定(ding)文(wen)件路徑(jing)信(xin)(xin)息的(de)。知(zhi)道(dao)(dao)了文(wen)件路徑(jing),還需要知(zhi)道(dao)(dao)要讀取的(de)XML的(de)根節(jie)點名(ming)稱(cheng),fragmentRootElementName屬(shu)(shu)性(xing)就是(shi)(shi)指定(ding)根節(jie)點名(ming)稱(cheng)的(de)。知(zhi)道(dao)(dao)了根節(jie)點名(ming)稱(cheng),還需要知(zhi)道(dao)(dao)的(de)一點就是(shi)(shi)怎么解析這(zhe)(zhe)個節(jie)點信(xin)(xin)息,unmarshaller就負(fu)責完成解析節(jie)點信(xin)(xin)息,并(bing)映(ying)射成程(cheng)序pojo對象。注意(yi),根節(jie)點并(bing)不(bu)是(shi)(shi)指整個XML文(wen)件的(de)根節(jie)點,而是(shi)(shi)指要讀取的(de)信(xin)(xin)息片(pian)段的(de)根節(jie)點,不(bu)管這(zhe)(zhe)個節(jie)點片(pian)段處在哪一層(ceng),框(kuang)架都會遍(bian)歷到(dao)。
49-58行配置了(le)解析XML節點(dian)信息(xi)的(de)unmarshaller。其(qi)中(zhong)entry的(de)key指定對應(ying)根(gen)節點(dian)名稱goods,value指定程序的(de)pojo類(lei),這樣(yang),程序就(jiu)(jiu)(jiu)可(ke)以將goods節點(dian)下的(de)子(zi)(zi)節點(dian)與pojo類(lei)(Goods)中(zhong)的(de)屬(shu)性(xing)去(qu)匹配,當(dang)匹配到子(zi)(zi)節點(dian)名與pojo類(lei)中(zhong)的(de)屬(shu)性(xing)名相同時,就(jiu)(jiu)(jiu)會將子(zi)(zi)節點(dian)的(de)內容賦值給pojo類(lei)的(de)屬(shu)性(xing)。這樣(yang)就(jiu)(jiu)(jiu)完(wan)(wan)成(cheng)了(le)一個根(gen)節點(dian)的(de)讀(du)(du)取,框架會控制循(xun)環(huan)操作,直到將文(wen)件中(zhong)所有根(gen)(goods)節點(dian)全(quan)部讀(du)(du)完(wan)(wan)為止。這樣(yang)就(jiu)(jiu)(jiu)完(wan)(wan)成(cheng)了(le)XML文(wen)件的(de)讀(du)(du)操作。
41-47行配置(zhi)了對XML文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)寫(xie)(xie)操作(zuo)。與(yu)(yu)讀(du)(du)(du)XML文(wen)(wen)件(jian)(jian)一(yi)樣,要寫(xie)(xie)一(yi)個(ge)XML文(wen)(wen)件(jian)(jian),也(ye)是(shi)需(xu)要知道這個(ge)文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)存放路(lu)(lu)徑的(de)(de)(de)(de)(de),同樣是(shi)resource屬(shu)(shu)性提(ti)(ti)供(gong)文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)路(lu)(lu)徑信(xin)息(xi)(xi)。同時(shi),也(ye)是(shi)需(xu)要知道這個(ge)文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)跟(gen)節(jie)點信(xin)息(xi)(xi)的(de)(de)(de)(de)(de),rootTagName屬(shu)(shu)性提(ti)(ti)供(gong)根節(jie)點名信(xin)息(xi)(xi)。注意此處的(de)(de)(de)(de)(de)根節(jie)點,指整個(ge)文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)跟(gen)節(jie)點,與(yu)(yu)讀(du)(du)(du)得時(shi)候稍(shao)有(you)(you)區別,從兩個(ge)屬(shu)(shu)性的(de)(de)(de)(de)(de)名稱上(shang)也(ye)可(ke)以看出。有(you)(you)了上(shang)面的(de)(de)(de)(de)(de)信(xin)息(xi)(xi),完(wan)成(cheng)一(yi)個(ge)寫(xie)(xie)操作(zuo),還需(xu)要一(yi)個(ge)把pojo對象(xiang)轉(zhuan)換(huan)成(cheng)XML片段的(de)(de)(de)(de)(de)工具,由(you)marshaller提(ti)(ti)供(gong)。本文(wen)(wen)讀(du)(du)(du)操作(zuo)的(de)(de)(de)(de)(de)unmarshaller和寫(xie)(xie)操作(zuo)的(de)(de)(de)(de)(de)marshaller用(yong)的(de)(de)(de)(de)(de)是(shi)同一(yi)個(ge)轉(zhuan)換(huan)器,因為XStreamMarshaller既提(ti)(ti)供(gong)將(jiang)節(jie)點片段轉(zhuan)換(huan)為pojo對象(xiang)功能(neng)(neng),同時(shi)又提(ti)(ti)供(gong)將(jiang)pojo對象(xiang)持久化(hua)為xml文(wen)(wen)件(jian)(jian)的(de)(de)(de)(de)(de)功能(neng)(neng)。如果寫(xie)(xie)的(de)(de)(de)(de)(de)內容(rong)與(yu)(yu)讀(du)(du)(du)得內容(rong)有(you)(you)很大差異,可(ke)以另(ling)外配置(zhi)一(yi)個(ge)轉(zhuan)換(huan)器。
batch.xml文(wen)件(jian)配置(zhi)的(de)(de)(de)對XML文(wen)件(jian)的(de)(de)(de)讀寫操作,至于讀出(chu)來的(de)(de)(de)信(xin)息(xi)做怎么樣的(de)(de)(de)處理再寫入(ru)文(wen)件(jian),通過簡單的(de)(de)(de)配置(zhi)恐怕就(jiu)無法完成(cheng)(cheng)了,就(jiu)需要我們自己寫代碼(ma)完成(cheng)(cheng)了。XMLProcessor類就(jiu)是完成(cheng)(cheng)這個(ge)工作的(de)(de)(de)。只要在Job的(de)(de)(de)配置(zhi)文(wen)件(jian)中指定到(dao)這個(ge)類就(jiu)可以了。XMLProcessor類的(de)(de)(de)內容如下:
package com.wanggc.springbatch.sample.xml;
import java.util.Date;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;
import com.wanggc.springbatch.sample.xml.pojo.Goods;
/**
* XML文件處理類。
*/
@Component("xmlProcessor")
public class XMLProcessor implements ItemProcessor<Goods, Goods> {
/**
* XML文件內容處理。
*
*/
@Override
public Goods process(Goods goods) throws Exception {
// 購入日期(qi)變更
goods.setBuyDay(new Date());
// 顧客信息(xi)變更
goods.setCustomer(goods.getCustomer() + "顧客!");
// ISIN變(bian)更
goods.setIsin(goods.getIsin() + "IsIn");
// 價格變更(geng)
goods.setPrice(goods.getPrice() + 1000.112);
// 數量變更
goods.setQuantity(goods.getQuantity() + 100);
// 處(chu)理后的數據返(fan)回
return goods;
}
}
內容很簡單(dan),再此(ci)就不做贅述(shu)了。要(yao)注意的(de)(de)一點(dian)就是紅背(bei)景色的(de)(de)地方。加(jia)了此(ci)標簽(qian)無須在(zai)batch.xml文件增加(jia)對xmlProcessor聲明用(yong)的(de)(de)bean,可(ke)以(yi)在(zai)job中直接(jie)引用(yong),這(zhe)(zhe)是Spring的(de)(de)功能。當然,實現這(zhe)(zhe)個的(de)(de)前提是要(yao)在(zai)applicationContext.xml中配置base-package,只有這(zhe)(zhe)樣才(cai)能找到。
工程結構圖中的XMLLaunch類用來(lai)啟動Job。內容如下:
package com.wanggc.springbatch.sample.xml;
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 XMLLaunch {
/**
* @param args
*/
public static void main(String[] args1) {
ApplicationContext context = new ClassPathXmlApplicationContext(
"batch.xml");
JobLauncher launcher = (JobLauncher) context.getBean("jobLauncher");
Job job = (Job) context.getBean("xmlFileReadAndWriterJob");
try {
// JOB實行
JobExecution result = launcher.run(job, new JobParametersBuilder()
.addString("inputFilePath", "C:\\input.xml")
.addString("outputFilePath", "C:\\output.xml")
.toJobParameters());
// 運(yun)行結果(guo)輸出
System.out.println(result.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
注意其中(zhong)為(wei)Job提供(gong)的兩個動(dong)態參數(shu),以及在配置文件中(zhong)的用(yong)法。
pojo類Goods的內容(rong)如下:
package com.wanggc.springbatch.sample.xml.pojo;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 商品信息類.
*/
public class Goods {
/** isin號 */
private String isin;
/** 數量 */
private int quantity;
/** 價(jia)格(ge) */
private double price;
/** 客戶 */
private String customer;
/** 購入日(ri)期(qi) */
private Date buyDay;
/* getter he setter已經刪(shan)除 */
}
input.xml文件內容如下:

處理結果如下(output.xml):

下次,將(jiang)和大家一起討論(lun)關于Spring Batch 對固定長內容文(wen)件(jian)的(de)讀寫問題。
歡迎轉載,請注明出處!
感謝您的閱讀,請關注后續博客!
共享視頻教程請訪問:
