Spring Batch 之 Sample(CSV文件操作)(四)

转自:http://www.cnblogs.com/gulvzhe/archive/2011/11/06/2238125.html

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

      工程结构如下图:

                   

      JobLaunch类用来启动Job, CsvItemProcessor类用来对Reader取得的数据进行处理, Student类是一个POJO类,用来存放映射的数据。 inputFile.csv是数据读取文件, outputFile.csv是数据输出文件。

      application.xml文件配置如前篇文章,不再赘述。

      batch.xml文件中Job配置如下:

<job id="csvJob">
        <step id="csvStep">
            <tasklet transaction-manager="transactionManager">
                <chunk reader="csvItemReader" writer="csvItemWriter" processor="csvItemProcessor" commit-interval="1">
                </chunk>
            </tasklet>
        </step>
    </job>


      这个文件里配置了这次运行的JOB:csvJob。本Job包含一个Step,完成一个完整的CSV文件读写功能。分别由 csvItemReader完成CSV文件的读操作,由 csvItemProcessor完成对取得数据的处理,由 csvItemWriter完成对CSV文件的写操作。

      batch.xml文件中csvItemReader配置如下:

<!-- 读取csv文件 -->
    <bean:bean id="csvItemReader"
        class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
        <bean:property name="resource" value="classpath:inputFile.csv"/>
        <bean:property name="lineMapper">
            <bean:bean
                class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
                <bean:property name="lineTokenizer" ref="lineTokenizer"/>
                <bean:property name="fieldSetMapper">
                    <bean:bean
                        class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
                        <bean:property name="prototypeBeanName" value="student"></bean:property>
                    </bean:bean>
                </bean:property>
            </bean:bean>
        </bean:property>
    </bean:bean>

    <bean:bean id="student" class="com.wanggc.springbatch.sample.csv.Student"></bean:bean>

    <!-- lineTokenizer -->
    <bean:bean id="lineTokenizer" class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
        <bean:property name="delimiter" value=","/>
        <bean:property name="names">
            <bean:list>
                <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>


      csvItemReader实现的是Spring Batch提供FlatFileItemReader类,此类主要用于Flat文件的读操作。它包含两个必要的属性 resource和 lineMapper。前者指定要读取的文件的位置,后者是将文件的每一行映射成一个Pojo对象。其中 lineMapper也有两个重要属性 lineTokenizer和 fieldSetMapper, lineTokenizer将文件的一行分解成一个 FieldSet,然后由 fieldSetMapper映射成Pojo对象。

      这种方式与DB的读操作非常类似。lineMapper类似于ResultSet,文件中的一行类似于Table中的一条记录,被封装成的FieldSet,类似于RowMapper。至于怎么将一条记录封装,这个工作由lineTokenizer的继承类DelimitedLineTokenizer完成。DelimitedLineTokenizer的delimiter属性决定文件的一行数据按照什么分解,默认的是“,”, names属性标示分解的每个字段的名字,传给fieldSetMapper(本实例用的是BeanWrapperFieldSetMapper)的时候,就可以按照这个名字取得相应的值。fieldSetMapper的属性prototypeBeanName,是映射Pojo类的名字。设置了此属性后,框架就会将lineTokenizer分解成的一个FieldSet映射成Pojo对象,映射是按照名字来完成的(lineTokenizer分解时标注的名字与Pojo对象中字段的名字对应)。

      总之,FlatFileItemReader读取一条记录由以下四步完成:1,从resource指定的文件中读取一条记录;2,lineTokenizer将这条记录按照delimiter分解成Fileset,每个字段的名字由names属性取得;3,将分解成的Fileset传递给fieldSetMapper,由其按照名字映射成Pojo对象;4,最终由FlatFileItemReader将映射成的Pojo对象返回,框架将返回的对象传递给Processor。

      csvItemProcessor实现的是ItemProcessor类。此类接受Reader映射成的Pojo对象,可以对此对象做相应的业务逻辑处理,然后返回,框架就会将返回的结果传递给Writer进行写操作。具体实现代码如下:

package com.wanggc.springbatch.sample.csv;

import org.springframework.batch.item.ItemProcessor;
import org.springframework.stereotype.Component;

/**
 * ItemProcessor类。
 */
@Component("csvItemProcessor")
public class CsvItemProcessor implements ItemProcessor<Student, Student> {

    /**
     * 对取到的数据进行简单的处理。
     * 
     * @param student
     *            处理前的数据。
     * @return 处理后的数据。
     * @exception Exception
     *                处理是发生的任何异常。
     */
    @Override
    public Student process(Student student) throws Exception {
        /* 合并ID和名字 */
        student.setName(student.getID() + "--" + student.getName());
        /* 年龄加2 */
        student.setAge(student.getAge() + 2);
        /* 分数加10 */
        student.setScore(student.getScore() + 10);
        /* 将处理后的结果传递给writer */
        return student;
    }
}


       batch.xml文件中csvItemReader配置如下:

<!-- 写CSV文件 -->
    <bean:bean id="csvItemWriter"
        class="org.springframework.batch.item.file.FlatFileItemWriter" scope="step">
        <bean:property name="resource" value="file:src/outputFile.csv"/>
        <bean:property name="lineAggregator">
            <bean:bean
                class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
                <bean:property name="delimiter" value=","></bean:property>
                <bean:property name="fieldExtractor">
                    <bean:bean
                        class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
                        <bean:property name="names" value="name,age,score"></bean:property>
                    </bean:bean>
                </bean:property>
            </bean:bean>
        </bean:property>
    </bean:bean>


      csvItemWriter实现的是FlatFileItemWriter类。此类与FlatFileItemReader类相似,也有两个重要的属性:resource和lineAggregator。前者是要输出的文件的路径,后者和lineTokenizer类似。lineAggregator(本实例用DelimitedLineAggregator类)也有两个重要的属性:delimiter和fieldExtractor。Delimiter标示输出的字段以什么分割,后者将Pojo对象组装成由Pojo对象的字段组成的一个字符串。同样FlatFileItemWriter写一条记录也有以下四步完成:1,Processor传递过来一个对象给lineAggregator;2,lineAggregator将其这个对象转化成一个数组;3,再由lineAggregator的属性fieldExtractor将数组转化成按照delimiter分割一个字符串;4,将这个字符串输出。

      这样,一条数据的读、处理、写操作就基本完成了。当然,读和写也可以自己写类来处理,只是要注意继承FlatFileItemReader和FlatFileItemWriter就可以了。

      实例中用到的Student类代码如下:

package com.wanggc.springbatch.sample.csv;

/** Pojo类_Student */
public class Student {
    /** ID */
    private String ID = "";
    /** 名字 */
    private String name = "";
    /** 年龄 */
    private int age = 0;
    /** 分数 */
    private float score = 0;
    /*getter 和setter已删除*/
}


 实例中用到的输入数据如下:

                

      实例输出结果如下:    

                

      本文的配置要注意以下两点:

      1,  注意Writer的resource要写成“file:******”形式,不能用“classpath:******”形式。

      2,  如果将Job配置中commit-interval属性配置为大于1时,每次commit的都是最后一条记录,前面读取的被覆盖了。具体原因不明,如果将Reader的fieldSetMapper属性自己重写,就可以解决这个问题。(注:student bean添加scope属性可以解决此问题:scope:"prototype".2011/12/16)

      3、在读取文件时有中文乱码的情况,可以在读操作时配置编码来解决



要使用Spring Batch导出CSV文件,你可以按照以下步骤操作: 1. 配置JobBuilderFactory和StepBuilderFactory 在你的Spring Batch 配置文件中,你需要定义JobBuilderFactory和StepBuilderFactory。JobBuilderFactory是用来创建Job实例的工厂,而StepBuilderFactory则是用来创建Step实例的工厂。 ``` @Bean public JobBuilderFactory jobBuilderFactory() { return new JobBuilderFactory(new MapJobRepositoryFactoryBean()); } @Bean public StepBuilderFactory stepBuilderFactory() { return new StepBuilderFactory(new MapJobRepositoryFactoryBean(), new TransactionManager()); } ``` 2. 配置ItemReaderItemWriterSpring Batch中,ItemReaderItemWriter是两个核心接口,用于取和写入数据。对于CSV文件,你可以使用FlatFileItemReaderFlatFileItemWriter。 ``` @Bean public FlatFileItemReader<Person> reader() { FlatFileItemReader<Person> reader = new FlatFileItemReader<>(); reader.setResource(new ClassPathResource("input.csv")); reader.setLineMapper(new DefaultLineMapper<Person>() {{ setLineTokenizer(new DelimitedLineTokenizer() {{ setNames(new String[]{"firstName", "lastName", "email"}); }}); setFieldSetMapper(new BeanWrapperFieldSetMapper<Person>() {{ setTargetType(Person.class); }}); }}); return reader; } @Bean public FlatFileItemWriter<Person> writer() { FlatFileItemWriter<Person> writer = new FlatFileItemWriter<>(); writer.setResource(new FileSystemResource("output.csv")); writer.setLineAggregator(new DelimitedLineAggregator<Person>() {{ setDelimiter(","); setFieldExtractor(new BeanWrapperFieldExtractor<Person>() {{ setNames(new String[]{"firstName", "lastName", "email"}); }}); }}); return writer; } ``` 3. 配置Step 你需要创建一个Step实例来定义你的CSV文件导出任务。在这里,你需要指定ItemReaderItemWriter。 ``` @Bean public Step step1() { return stepBuilderFactory.get("step1") .<Person, Person>chunk(10) .reader(reader()) .writer(writer()) .build(); } ``` 4. 配置Job 最后,你需要创建一个Job实例来引用Step实例。 ``` @Bean public Job exportCsvJob() { return jobBuilderFactory.get("exportCsvJob") .incrementer(new RunIdIncrementer()) .start(step1()) .build(); } ``` 完成上述步骤后,你就可以运行你的CSV文件导出任务了。在Spring Boot中,你可以使用CommandLineRunner来运行你的任务。 ``` @SpringBootApplication public class CsvExportApplication { public static void main(String[] args) { SpringApplication.run(CsvExportApplication.class, args); } @Autowired private JobLauncher jobLauncher; @Autowired private Job exportCsvJob; @Override public void run(String... args) throws Exception { JobParameters jobParameters = new JobParametersBuilder() .addString("jobName", "exportCsvJob") .toJobParameters(); jobLauncher.run(exportCsvJob, jobParameters); } } ``` 现在你可以打开你的output.csv文件,检查导出的数据是否正确了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值