前面关于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内容如下:

按 Ctrl+C 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<bean:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:bean="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<bean:import resource="applicationContext.xml" />
<!-- Job的配置信息 -->
<job id="multiTypeSingleFileJob">
<step id="xmlFileReadAndWriterStep">
<tasklet>
<chunk reader="multiTypesItemReader" writer="multiTypesItemWriter"
commit-interval="1">
<streams>
<stream ref="studentWriter" />
<stream ref="goodsWriter" />
</streams>
</chunk>
</tasklet>
</step>
</job>
<!-- 不同格式数据的文件读取 -->
<bean:bean id="multiTypesItemReader"
class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
<bean:property name="resource"
value="file:#{jobParameters['inputFilePath']}" />
<bean:property name="lineMapper">
<bean:bean
class="org.springframework.batch.item.file.mapping.PatternMatchingCompositeLineMapper">
<bean:property name="tokenizers">
<bean:map>
<bean:entry key="student*" value-ref="studentTokenizer" />
<bean:entry key="goods*" value-ref="goodsTokenizer" />
</bean:map>
</bean:property>
<bean:property name="fieldSetMappers">
<bean:map>
<bean:entry key="student*" value-ref="studentFieldSetMapper" />
<bean:entry key="goods*" value-ref="goodsFieldSetMapper" />
</bean:map>
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
<bean:bean id="studentTokenizer"
class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
<bean:property name="delimiter" value="," />
<bean:property name="names">
<bean:list>
<bean:value>student</bean:value>
<bean:value>ID</bean:value>
<bean:value>name</bean:value>
<bean:value>age</bean:value>
<bean:value>score</bean:value>
</bean:list>
</bean:property>
</bean:bean>
<bean:bean id="studentFieldSetMapper"
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<bean:property name="prototypeBeanName" value="student" />
<bean:property name="distanceLimit" value="100" />
</bean:bean>
<!-- 学生Pojo类 -->
<bean:bean id="student"
class="com.wanggc.springbatch.sample.multitypessinglefile.pojo.Student"
scope="prototype" />
<bean:bean id="goodsTokenizer"
class="org.springframework.batch.item.file.transform.FixedLengthTokenizer">
<bean:property name="columns" value="6-13,14-17,18-22,23-32,33-" />
<bean:property name="names"
value="isin,quantity,price,customer,buyDay" />
</bean:bean>
<bean:bean id="goodsFieldSetMapper"
class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
<bean:property name="prototypeBeanName" value="goods" />
</bean:bean>
<!-- 商品Pojo类 -->
<bean:bean id="goods"
class="com.wanggc.springbatch.sample.multitypessinglefile.pojo.Goods"
scope="prototype" />
<bean:bean id="multiTypesItemWriter"
class="com.wanggc.springbatch.sample.multitypessinglefile.MultiItemWriter">
<bean:property name="delegates">
<bean:list>
<bean:ref bean="studentWriter" />
<bean:ref bean="goodsWriter" />
</bean:list>
</bean:property>
</bean:bean>
<!-- 学生信息的写 -->
<bean:bean id="studentWriter"
class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
<bean:property name="resource"
value="file:#{jobParameters['outputFilePathStudent']}" />
<bean:property name="lineAggregator">
<bean:bean
class="org.springframework.batch.item.file.transform.FormatterLineAggregator">
<bean:property name="fieldExtractor">
<bean:bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<bean:property name="names" value="ID,name,age,score" />
</bean:bean>
</bean:property>
<bean:property name="format" value="%-9s%-9s%3d%-2.0f" />
</bean:bean>
</bean:property>
</bean:bean>
<!-- 商品信息的写 -->
<bean:bean id="goodsWriter"
class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
<bean:property name="resource"
value="file:#{jobParameters['outputFilePathGoods']}" />
<bean:property name="lineAggregator">
<bean:bean
class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
<bean:property name="fieldExtractor">
<bean:bean
class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
<bean:property name="names"
value="isin,quantity,price,customer,buyDay" />
</bean:bean>
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
</bean:beans> 按 Ctrl+C 复制代码

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")
public class MultiItemWriter<T> implements ItemWriter<T> {
/** 写代理 */
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 {
// 学生信息的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; 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实行
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的操作。

作者:孤旅者
如果本文使您有所收获,请点击右下角的 [推荐]!
如果您对本文有意见或者建议,欢迎留言,哪怕是拍砖(^_^)!
欢迎转载,请注明出处!
感谢您的阅读,请关注后续博客!

SpringBatch Sample (五)(复合格式文件的读、多文件的写)的更多相关文章

  1. Python文件读写 - 读一个文件所有行,加工后写另一个文件

    #Filename: file_read_and_write.py #打开文件,cNames读取所有行,储存在列表中,循环对每一行在起始处加上序号1,2,3,4 with open(r'file/co ...

  2. 02_Android写xml文件和读xml文件

     新建Android项目 编写AndroidManifest.xml,使本Android项目具有单元测试功能和写外设的权限. <?xml .控制台输出结果

  3. SpringBatch Sample (四)(固定长格式文件读写)

    前篇关于Spring Batch的文章,讲述了Spring Batch 对XML文件的读写操作. 本文将通过一个完整的实例,与大家一起讨论运用Spring Batch对固定长格式文件的读写操作.实例延 ...

  4. SpringBatch Sample (三)(XML文件操作)

    前篇关于Spring Batch的文章,讲述了Spring Batch 对CSV文件的读写操作. 本文将通过一个完整的实例,与大家一起讨论运用Spring Batch对XML文件的读写操作.实例流程是 ...

  5. SpringBatch Sample (二)(CSV文件操作)

    本文将通过一个完整的实例,与大家一起讨论运用Spring Batch对CSV文件的读写操作.此实例的流程是:读取一个含有四个字段的CSV文件(ID,Name,Age,Score),对读取的字段做简单的 ...

  6. plist文件、NSUserDefault 对文件进行存储的类、json格式解析

    ========================== 文件操作 ========================== Δ一 .plist文件 .plist文件是一个属性字典数组的一个文件: .plis ...

  7. Python第五天 文件访问 for循环访问文件 while循环访问文件 字符串的startswith函数和split函数 linecache模块

    Python第五天   文件访问    for循环访问文件    while循环访问文件   字符串的startswith函数和split函数  linecache模块 目录 Pycharm使用技巧( ...

  8. HTTP POST请求报文格式分析与Java实现文件上传

    时间 2014-12-11 12:41:43  CSDN博客 原文  http://blog.csdn.net/bboyfeiyu/article/details/41863951 主题 HTTPHt ...

  9. matlab文件操作及读txt文件(fopen,fseek,fread,fclose)

    文件操作是一种重要的输入输出方式,即从数据文件读取数据或将结果写入数据文件.MATLAB提供了一系列低层输入输出函数,专门用于文件操作. 1.文件的打开与关闭 1)打开文件 在读写文件之前,必须先用f ...

随机推荐

  1. ATOM常用插件推荐

    转载:http://blog.csdn.net/qq_30100043/article/details/53558381 ATOM常用插件推荐 simplified-chinese-menu ATOM ...

  2. logmnr使用

    logminer 工具的使用 Oracle LogMiner 是Oracle公司从产品8i以后提供的一个实际非常有用的分析工具,使用该工具可以轻松获得Oracle 重作日志文件(归档日志文件)中的具体 ...

  3. 安装docker No package docker available

    安装docker 时候出现以下问题 yum -y install dockerLoaded plugins: fastestmirrorDetermining fastest mirrors * ba ...

  4. 三、存储过程(Stored Procedure)与游标(Cursor)

    一.存储过程 一组为了完成特定功能的SQL语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数,来执行它. 在大型数据库中,存储过程和触发器具有重要的作用.无论是存储过程还是触发器,都 ...

  5. FTP服务器搭建(Centos7)

    1.1.1 查看是否安装vsftp rpm -qa | grep vsftpd 1.1.2 如果没有安装: yum -y install vsftpd 1.2.3 vsftpd.conf 配置文件 匿 ...

  6. Jenkins结合testng注意事项

    1.在生成测试报告时,因为Jenkins自带的只有Junit的测试报告,不会显示testng的. 2.要想显示Publish TestNG Results这一项,首先需要在jenkins的首页-系统管 ...

  7. 003-RHEL7-Linux系统维护管理命令使用

    系统维护管理命令: date  查看日期,设置日期 只有超级用户才能用date命令设置时间 date  --help  显示时间的帮助命令 date{选项} 显示时间格式(以+开头,后面接时间格式) ...

  8. laravel本地开发的项目部署到服务器上

    不建议用ftp,建议用git.svn等工具从你的开发服务器上拉取.或者使用一些自动构建发布的工具.如果非要用ftp上传,建议用以下步骤: 服务器上安装composer,并使用`composer sel ...

  9. sql2008r2安装失败的解决办法

    setup fails with: '.', hexadecimal value 0x00, is an invalid character.SQL 2012 Setup issues - hexad ...

  10. day06 元组类型

    一.什么是元组? 元组就是一个不可变的列表 元组的基本使用: 1.用途:  用于存放多个值,当存放多个任意类型的值 2.定义方式:在()内用逗号分隔开多个任意类型的值 t=(1,3.1,'aaa',( ...