Spring Batch从csv文件读取再生成csv文件

目录结构为src/main/java/com/ermdashboard.SpringBatchCSV
package com.ermdashboard.SpringBatchCSV;
 
importorg.springframework.batch.item.ItemProcessor;
importorg.springframework.stereotype.Component;
 
/**
 * ItemProcessor类。
 */
@Component("csvItemProcessor")
public  class CsvItemProcessorimplementsItemProcessor<Student, Student> {
 
/**
     * 对取到的数据进行简单的处理。
     * 
     * @param student
     *            处理前的数据。
     * @return处理后的数据。
     * @exception Exception
     *               处理是发生的任何异常。
     */
    public Student process(Student student) throws Exception {
/* 合并ID和名字 */
"--"
/* 年龄加2 */
        student.setAge(student.getAge() + 2);
/* 分数加10*/
        student.setScore(student.getScore() +10);
/* 将处理后的结果传递给writer */
        System.out.println(student.getName());
        return student;
    }
}
 
package com.ermdashboard.SpringBatchCSV;
 
import org.springframework.batch.core.Job;
importorg.springframework.batch.core.JobExecution;
importorg.springframework.batch.core.JobParameters;
import org.springframework.batch.core.launch.JobLauncher;
importorg.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public  class JobLaunch {
/**
     * @param args
     */
    public  static void main(String[] args) {
      String[]springConfig  =
"application.xml",
"batch.xml"
                  };
        ApplicationContext context = newClassPathXmlApplicationContext(springConfig);
JobLauncher launcher = (JobLauncher) context.getBean("jobLauncher");
"csvJob");
 
        try {
/* 运行Job */
result = launcher.run(job,newJobParameters());
/* 处理结束,控制台打印处理结果 */
            System.out.println(result.toString());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
package com.ermdashboard.SpringBatchCSV;
 
/** Pojo类_Student */
public  class Student {
/** ID */
    private String  ID = "";
/** 名字 */
    private String  name = "";
/** 年龄 */
    private  int age
/** 分数 */
    private  float score
   
    public String getID(){
      return  ID;
    }
    public  void setID(String ID){
      this.ID
    }
   
    public String getName(){
      return  name;
    }
    public  void setName(String name){
      this.name
    }
   
    public  intgetAge(){
      return  age;
    }
    public  void setAge(int age){
      this.age
    }
   
    public  float getScore(){
      return  score;
    }
    public  void setScore(float score){
      this.score = score;
    }
}
 
Src/main/java下,
Batch.xml:
<?xml
<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"
   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.xsd">
   
    <job id="csvJob">
        <step id="csvStep">
            <tasklettransaction-manager="transactionManager">
                <chunkreader="csvItemReader" writer="csvItemWriter"processor="csvItemProcessor" commit-interval="1">
                </chunk>
</tasklet>
        </step>
    </job>
   
    <bean:beanid="csvItemProcessor"class="com.ermdashboard.SpringBatchCSV.CsvItemProcessor">
</bean:bean>
   
    <bean:bean id="csvItemReader"
        class="org.springframework.batch.item.file.FlatFileItemReader"scope="step">
        <bean:propertyname="resource" value="classpath:inputFile.csv"/>
        <bean:propertyname="lineMapper">
            <bean:bean
               class="org.springframework.batch.item.file.mapping.DefaultLineMapper">
ref="lineTokenizer"/>
                <bean:propertyname="fieldSetMapper">
                    <bean:bean
                       class="org.springframework.batch.item.file.mapping.BeanWrapperFieldSetMapper">
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
 
</bean:bean>
 
    <!-- lineTokenizer -->
    <bean:bean id="lineTokenizer"class="org.springframework.batch.item.file.transform.DelimitedLineTokenizer">
        <bean:property name="delimiter"value=","/>
        <bean:propertyname="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>
   
    <bean:bean id="csvItemWriter"
       class="org.springframework.batch.item.file.FlatFileItemWriter"scope="step">
        <bean:propertyname="resource" value="file:src/main/java/outputFile.csv"/>
        <bean:propertyname="lineAggregator">
            <bean:bean
               class="org.springframework.batch.item.file.transform.DelimitedLineAggregator">
</bean:property>
                <bean:propertyname="fieldExtractor">
                    <bean:bean
                       class="org.springframework.batch.item.file.transform.BeanWrapperFieldExtractor">
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
</bean:property>
</bean:bean>
</bean:beans>
Application.xml:
<?xml
<beans xmlns="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"
   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"
autowire="byName">
 
    <bean id="jobLauncher"class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
ref="jobRepository"/>
    </bean>
 
    <bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean"/>
 
    <bean id="transactionManager"class="org.springframework.batch.support.transaction.ResourcelessTransactionManager"/>
</beans>
inputFile.csv:
200001,ZhangSan,18,78
200002,LiSik,19,79
Pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
 
 <groupId>com.ermdashboard</groupId>
 <artifactId>SpringBatchCSV</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>SpringBatchCSV</name>
<url>http://maven.apache.org</url>
 
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<jdk.version>1.6</jdk.version>
<spring.version>3.2.2.RELEASE</spring.version>
<spring.batch.version>2.2.0.RELEASE</spring.batch.version>
  </properties>
 
 
 
  <dependencies>
        <!-- Spring Core -->
            <dependency>
                  <groupId>org.springframework</groupId>
                  <artifactId>spring-core</artifactId>
                  <version>${spring.version}</version>
            </dependency>
 
jdbc, for database -->
            <dependency>
                  <groupId>org.springframework</groupId>
jdbc</artifactId>
                  <version>${spring.version}</version>
            </dependency>
 
            <!-- Spring Batch dependencies-->
            <dependency>
                  <groupId>org.springframework.batch</groupId>
                  <artifactId>spring-batch-core</artifactId>
                  <version>${spring.batch.version}</version>
            </dependency>
            <dependency>
                  <groupId>org.springframework.batch</groupId>
                  <artifactId>spring-batch-infrastructure</artifactId>
                  <version>${spring.batch.version}</version>
            </dependency>
            <dependency>
    <groupId>com.oracle</groupId>
   <artifactId>ojdbc14</artifactId>
    <version>10.2.0.3.0</version>
</dependency>
    <dependency>
junit</groupId>
junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  
  </dependencies>
 
   <build>
            <finalName>spring-batch</finalName>
<plugins>
<plugin>
                  <groupId>org.apache.maven.plugins</groupId>
maven-eclipse-plugin</artifactId>
                  <version>2.9</version>
                  <configuration>
                        <downloadSources>true</downloadSources>
                        <downloadJavadocs>false</downloadJavadocs>
                  </configuration>
</plugin>
<plugin>
                  <groupId>org.apache.maven.plugins</groupId>
maven-compiler-plugin</artifactId>
                  <version>2.3.2</version>
                  <configuration>
                        <source>${jdk.version}</source>
                        <target>${jdk.version}</target>
                  </configuration>
</plugin>
</plugins>
      </build>
</project>
 
Output:
Aug 12,2013 6:29:55 PM org.springframework.context.support.AbstractApplicationContextprepareRefresh
INFO:Refreshingorg.springframework.context.support.ClassPathXmlApplicationContext@89fbe3:startup date [Mon Aug 12 18:29:55 CST 2013]; root of context hierarchy
Aug 12,2013 6:29:56 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReaderloadBeanDefinitions
INFO:Loading XML bean definitions from class path resource [application.xml]
Aug 12,2013 6:29:56 PM org.springframework.beans.factory.xml.XmlBeanDefinitionReaderloadBeanDefinitions
INFO:Loading XML bean definitions from class path resource [batch.xml]
Aug 12,2013 6:29:56 PMorg.springframework.beans.factory.support.DefaultListableBeanFactoryregisterBeanDefinition
INFO:Overriding bean definition for bean 'csvJob': replacing [Generic bean: class[org.springframework.batch.core.configuration.xml.SimpleFlowFactoryBean];scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;autowireCandidate=true; primary=false; factoryBeanName=null;factoryMethodName=null; initMethodName=null; destroyMethodName=null] with[Generic bean: class[org.springframework.batch.core.configuration.xml.JobParserJobFactoryBean];scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;autowireCandidate=true; primary=false; factoryBeanName=null;factoryMethodName=null; initMethodName=null; destroyMethodName=null]
Aug 12,2013 6:29:56 PMorg.springframework.beans.factory.support.DefaultListableBeanFactoryregisterBeanDefinition
INFO:Overriding bean definition for bean 'csvItemReader': replacing [Generic bean:class [org.springframework.batch.item.file.FlatFileItemReader]; scope=step;abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;autowireCandidate=false; primary=false; factoryBeanName=null;factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined inclass path resource [batch.xml]] with [Root bean: class[org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false;lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true;primary=false; factoryBeanName=null; factoryMethodName=null;initMethodName=null; destroyMethodName=null; defined in BeanDefinition definedin class path resource [batch.xml]]
Aug 12,2013 6:29:56 PMorg.springframework.beans.factory.support.DefaultListableBeanFactoryregisterBeanDefinition
INFO:Overriding bean definition for bean 'csvItemWriter': replacing [Generic bean:class [org.springframework.batch.item.file.FlatFileItemWriter]; scope=step;abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0;autowireCandidate=false; primary=false; factoryBeanName=null;factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined inclass path resource [batch.xml]] with [Root bean: class[org.springframework.aop.scope.ScopedProxyFactoryBean]; scope=; abstract=false;lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true;primary=false; factoryBeanName=null; factoryMethodName=null;initMethodName=null; destroyMethodName=null; defined in BeanDefinition definedin class path resource [batch.xml]]
Aug 12,2013 6:29:56 PMorg.springframework.beans.factory.support.DefaultListableBeanFactorypreInstantiateSingletons
INFO:Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1989f84:defining beans[jobLauncher,jobRepository,transactionManager,org.springframework.batch.core.scope.internalStepScope,org.springframework.beans.factory.config.CustomEditorConfigurer,org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor,csvStep,csvJob,csvItemProcessor,csvItemReader,student,lineTokenizer,csvItemWriter,scopedTarget.csvItemReader,scopedTarget.csvItemWriter];root of factory hierarchy
Aug 12,2013 6:29:56 PM org.springframework.batch.core.launch.support.SimpleJobLauncherafterPropertiesSet
INFO: NoTaskExecutor has been set, defaulting to synchronous executor.
Aug 12,2013 6:29:56 PMorg.springframework.batch.core.launch.support.SimpleJobLauncher$1 run
INFO:Job: [FlowJob: [name=csvJob]] launched with the following parameters: [{}]
Aug 12,2013 6:29:56 PM org.springframework.batch.core.job.SimpleStepHandler handleStep
INFO:Executing step: [csvStep]
200001--ZhangSan
200002--LiSik
Aug 12,2013 6:29:56 PM org.springframework.batch.core.launch.support.SimpleJobLauncher$1run
INFO:Job: [FlowJob: [name=csvJob]] completed with the following parameters: [{}] andthe following status: [COMPLETED]
JobExecution:id=0, version=2, startTime=Mon Aug 12 18:29:56 CST 2013, endTime=Mon Aug 1218:29:56 CST 2013, lastUpdated=Mon Aug 12 18:29:56 CST 2013, status=COMPLETED,exitStatus=exitCode=COMPLETED;exitDescription=, job=[JobInstance: id=0,version=0, Job=[csvJob]], jobParameters=[{}]
 
outputFile.csv:
200001--ZhangSan,20,88.0
200002--LiSik,21,89.0

 JobLaunch类用来启动Job,CsvItemProcessor类用来对Reader取得的数据进行处理, Student类是一个POJO类,用来存放映射的数据。inputFile.csv是数据读取文件, outputFile.csv是数据输出文件。 这个文件里配置了这次运行的JOB:csvJob。本Job包含一个Step,完成一个完整的CSV文件读写功能。分别由csvItemReader完成CSV文件的读操作,由 csvItemProcessor完成对取得数据的处理,由csvItemWriter完成对CSV文件的写操作。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。

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就可以了。