65.java项目--springbatch(批处理)

springbatch

在这里插入图片描述

一.springbatch概述

Spring Batch 是一个轻量级的、完善的批处理框架,旨在帮助企业建立健壮、高效的批处理应用。Spring Batch是Spring的一个子项目,使用Java语言并基于Spring框架为基础开发,使得已经使用 Spring 框架的开发者或者企业更容易访问和利用企业服务。
Spring Batch 提供了大量可重用的组件,包括了日志、追踪、事务、任务作业统计、任务重启、跳过、重复、资源管理。对于大数据量和高性能的批处理任务,Spring Batch 同样提供了高级功能和特性来支持,比如分区功能、远程功能。总之,通过 Spring Batch 能够支持简单的、复杂的和大数据量的批处理作业。
特点

  • 事务管理,让您专注于业务处理,实现批处理机制,你可以引入平台事务机制或其他事务管理器机制
  • 基于块Chunk的处理,通过将一大段大量数据分成一段段小数据来处理,。
  • 启动/停止/重新启动/跳过/重试功能,以处理过程的非交互式管理。
  • 基于Web的管理界面(Spring Batch Admin),它提供了一个用于管理任务的API。
  • 基于Spring框架,因此它包括所有配置选项,包括依赖注入。
  • 符合JSR 352:Java平台的批处理应用程序。
  • 基于数据库管理的批处理,可与Spring Cloud Task结合,适合分布式集群下处理。
  • 能够进行多线程并行处理,分布式系统下并行处理,变成一种弹性Job分布式处理框架。
1.springbatch的原理

Spring批处理的基本单元是Job,你需要定义一个Job代表一次批处理工作,每个Job分很多步骤step,每个步骤里面有两种处理方式Tasklet(可重复执行的小任务)和Chunk(块),掌握Spring Batch主要是将这几个核心概念搞清楚。
在这里插入图片描述
在SpringBoot架构下,我们只要做一个JobConfig组件作为JobLauncher,使用@Configuration配置,然后完成上图中Job和Step以及ItemReader,ItemProcessor和ItemWriter,后面这三个分别是存在一个步骤里,用于处理条目的输入读 、处理然后输出写出。至于图中JobRepository只要我们在Application.properties中配置上datasource,SpringBoot启动时会自动将batch需要的库表导入到数据库中。

2.springbatch的对象
  • JobLauncher:是任务启动器,通过它来启动任务,可以看做是程序的入口。
  • Job代表着一个具体的任务。
  • Step代表着一个具体的步骤,一个Job可以包含多个Step.在实际业务场景中,可能一个任务很复杂,这个时候可以将任务拆分成多个step,分别对这些step 进行管理(将一个复杂任务简单化)。(这些step 默认是串行执行,也可以并行执行,根据具体的业务场景来使用)。
  • itemReader代表着数据的读取,springbatch提供了很多中数据的读取方式,包括读取文件的额数据,读取数据库的数据,多种方式读取数据.
  • itemProcesser表示的是处理我们reader读取到的数据,我们通常业务中需要对我们读取到的数据做一些筛选处理,而这些处理就是在processer中.
  • itemWriter表示的将processer中处理的数据写入哪里,springbatch同样提供了多种写入方式,包括写入文件,写入数据库,写入多种途径等.
  • jobRepository表示springbatch的数据库持久化对象,springbatch会生成多张数据库表,这些表用来记录我们的job等执行情况,而与这些数据库表交互的对象就是jobRepository对象.
  • XXXListener 表示监听,springbatch提供了多种监听,包括监听job,step,reader,processer,writer,chunk,skip等.基本上涵盖了我们一个job执行的所有的流程和可能出现的问题.

二.springbatch的场景

编写代码的步骤:
导入依赖

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-batch</artifactId>
        </dependency>
        <!--加入一个内存数据库H2是项目不报错
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>
        -->

        <!--配置mysql数据库-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>


        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.batch</groupId>
            <artifactId>spring-batch-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置application.yml

#配置数据源dataSource
spring:
  datasource:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/springbatch2?serverTimezone=GMT%2B8&characterEncoding=utf8
      username: root
      password: root
      #这是指定springbatch生成数据库表的sql语句位置
      schema: classpath:/org/springframework/batch/core/schema-mysql.sql
  batch:
    initialize-schema: always  #是否生成数据库表,这是代表生成数据库表
    job:
      #names: SkipExceptionJob7 指定执行的job,这里指定的job的名字,也就是get()参数,而不是beanname
      enabled: false #这里是项目启动时不运行任何job的意思.
server:
  port: 8001

接下来的步骤就是结合具体的场景,不同实现不同的代码.

1.场景1-demo演示

demo演示了springbatch的job是如何创建的,step等.一个batch的job必须包含至少一个step,demo演示了如何构建job,但是其中还有很多需要注意的地方:

package com.gl.basicjob;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.scope.context.ChunkContext;
import org.springframework.batch.core.step.tasklet.Tasklet;
import org.springframework.batch.core.step.tasklet.TaskletStep;
import org.springframework.batch.repeat.RepeatStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author gl
 * @time 2020-04-28 22:10
 * @function : 测试多step的job的创建,并且如何指定step的执行顺序
 * @step :
 */

@Configuration
@EnableBatchProcessing
public class JobDemo2 {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job getJobDemo1(){
        //第一种指定job中step顺序
        /*Job jobDemo1 = jobBuilderFactory.get("jobDemo1") //job的名字
                .start(step1()) //这个是指定有三个step的job,顺序分别是step1->step2->step3
                .next(step2())
                .next(step3())
                .build();*/
        //第二种指定job中的step,并且指定step的执行顺序
        Job job = jobBuilderFactory.get("jobDemo1")
                .start(step1())
                .on("COMPLETED").to(step2()) //to代表的是到哪个节点step
                .from(step2()).on("COMPLETED").to(step3()) //on代表条件,如果执行完成
                .from(step3()).end()
                .build();
        return job;
    }

    @Bean(value = "job2step3")
    public Step step3() {
        TaskletStep step = stepBuilderFactory.get("step3")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("step3()");
                        return RepeatStatus.FINISHED;
                    }
                }).build();

        return step;
    }

    @Bean(value = "job2step2")
    public Step step2() {
        TaskletStep step = stepBuilderFactory.get("step2")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("step2()");
                        return RepeatStatus.FINISHED;
                    }
                }).build();

        return step;
    }

    @Bean(value = "job2step1")
    public Step step1() {
        TaskletStep step = stepBuilderFactory.get("step1")
                .tasklet(new Tasklet() {
                    @Override
                    public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
                        System.out.println("step1()");
                        return RepeatStatus.FINISHED;
                    }
                }).build();

        return step;
    }


}

说明:
1.jobBuilderFactory和jobBuilderFactory对象是spring框架默认就自动帮我注入到spring容器中的,其实还有几个对象例如JobLauncher对象,jobRepository对象等.
2.job可以包含多个step,并且可以指定step的执行顺序和执行条件
3.job也可指定监听,step同样也可指定监听.
4.job除了可以指定step还可以指定flow对象,并且job可以并发执行flow.

2.场景2:数据库db->文件(file)

代码步骤:
(1)配置数据库表的entity对象

/**
 * @author gl
 * @time 2020-04-29 16:55
 * @function :
 * @step :
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Customer {
    private Long id;
    private String firstName;
    private String lastName;
    private Date birthday;
}

(2)书写reader和writer的配置类

/**
 * @author gl
 * @time 2020-04-30 15:55
 * @function : 这是数据库读取,写入文件的配置信息类,
 * 主要配置的从数据库读取的reader对象和写入文件的writer对象
 * @step :
 */
@Configuration
public class DbReaderAndWriterConfig {
    @Autowired
    private DataSource dataSource;

    //读取数据库数据,从哪个数据库读取那张表的那些字段信息
    @Bean(value = "itemReaderDbCustmer")
    @StepScope//一个step,一个实例
    public JdbcPagingItemReader<Customer> itemReaderDbCustmer() {
        JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader();
        reader.setDataSource(dataSource);//数据源
        reader.setFetchSize(2);//分页,每页读取数据
        reader.setRowMapper(new RowMapper<Customer>() {
            @Override
            public Customer mapRow(ResultSet rs, int i) throws SQLException {
                Customer customer = new Customer();
                customer.setId(rs.getLong(1));
                customer.setFirstName(rs.getString(2));
                customer.setLastName(rs.getString(3));
                customer.setBirthday(rs.getDate(4));
                return customer;
            }
        });
        //指定sql语句
        MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider();
        provider.setSelectClause("id,first_name,last_name,birthday");//指定读取的列名字
        provider.setFromClause("from custmer"); //指定表名
        //根据那个字段进行排序
        Map<String,Order> sort = new HashMap<>(1);
        sort.put("id",Order.DESCENDING);
        provider.setSortKeys(sort);

        //将provider赋值给reader
        reader.setQueryProvider(provider);
        return reader;
    }


    //定义输出Writer,写入文件,包括写入的格式是什么
    @Bean(value = "itemWriterDbCustmer")
    @StepScope
    public FlatFileItemWriter<Customer> itemWriterDbCustmer() throws Exception {
        FlatFileItemWriter<Customer> writer = new FlatFileItemWriter<>();
        writer.setEncoding("utf8");
        //classpathResource是当前类路径
        //filepathResource是磁盘路劲
        writer.setResource(new FileSystemResource("E:\\custmer.txt"));
        //把custmer转化成string
        writer.setLineAggregator(new LineAggregator<Customer>() {
            @Override
            public String aggregate(Customer customer) {
                //转化成json的字符串
                ObjectMapper mapper = new ObjectMapper();
                String result = "";
                try {
                    result = mapper.writeValueAsString(customer);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException("对象转换出现异常");
                }
                return result;
            }
        });

        writer.afterPropertiesSet();
        return  writer;
    }
}

(3)自定义processer类
processer可以不用,因为step中必须要有reader和writer,可以没有processer

/**
 * @author gl
 * @time 2020-04-30 17:33
 * @function : 过滤规则,将读取到的数据经过处理在返回给writer对象
 * @step :
 */
@Component("dbToFileProcesser")
//第一个custmer是reader读取到的值,第二个是custmer是处理之后的对象类型
public class dbToFileProcesser  implements ItemProcessor<Customer,Customer>{

    @Override
    public Customer process(Customer customer) throws Exception {
        Customer result = new Customer();
        result.setId(customer.getId() + 100);
        result.setFirstName(customer.getFirstName());
        result.setLastName(customer.getLastName());
        return result;
    }

}

(4)自定义job的配置

/**
 * @author gl
 * @time 2020-04-30 15:47
 * @function : 将数据库读取出来的数据,写入文件中
 * @step :
 */
@Configuration
public class ItemWriterFileConfiguration {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    @Qualifier("itemReaderDbCustmer")//注入读取custmer表的reader对象
    private ItemReader<Customer> reader;
    @Autowired
    @Qualifier("itemWriterDbCustmer")
    private ItemWriter<Customer> writer;
    @Autowired
    @Qualifier("dbToFileProcesser")
    private ItemProcessor<? super Customer, ? extends Customer> processer;

    //这是调用有processer的step的job对象
    @Bean(value = "ItemWriterProcesserFileJob")
    public Job ItemWriterProcesserFileJob(){
        return jobBuilderFactory.get("ItemWriterProcesserFileJob10")//只要job的名字不同,则就可以启动job
                .start(ItemWriterProcesserFileStep())
                .build();
    }

    //这是有processer的step步骤
    @Bean(value = "ItemWriterProcesserFileStep")
    public Step ItemWriterProcesserFileStep() {
        return stepBuilderFactory.get("ItemWriterProcesserFileSte11")
                .<Customer,Customer>chunk(2)
                .reader(this.reader)
                .processor(this.processer)
                .writer(this.writer)
                .build();
    }

}

(5)提示,如果要想运行,请修改application.yml中的关闭job,并且指定启动哪个springbatch的job,指定的名字就是job的name

3.场景3:file->DB

(1)自定义stepListener
用于监听我们的step,获取我们job中传递的参数

/**
 * @author gl
 * @time 2020-05-01 17:57
 * @function : 利用step的监听获取job中的参数
 * @step :
 */
@Component(value = "stepListenerDemo1")
public class StepListenerDemo1 implements StepExecutionListener {

    //获取job中的参数
    //在step执行之前执行的
    @Override
    public void beforeStep(StepExecution stepExecution) {
        Map<String, JobParameter> parameters = stepExecution.getJobParameters().getParameters();
        System.out.println("step的监听器中获取的jobParameters中的参数param1:" + parameters.get("param11"));
    }
    //在step执行之后执行
    @Override
    public ExitStatus afterStep(StepExecution stepExecution) {
        return null;
    }
}

(2)自定义skipListener
这是在我们的job发生异常的时候,指定跳过的数据,并且将跳过的数据写入一个error.txt文档

/**
 * @author gl
 * @time 2020-05-01 15:56
 * @function :
 * @step :
 */
@Component(value = "mySkipListener")
public class MySkipListener implements SkipListener<Customer,Customer> {
    //reader中发生异常的,处理方式
    //将文件中不符合我们需要的数据,也就是我们跳过的数据写入E://err.txt文件
    @Override
    public void onSkipInRead(Throwable throwable) {
        //错误处理
        System.out.println("这是错误跳过处理的reader的监听:" + throwable.getMessage());
        try {
            String path = System.getProperty("user.dir")+ "\\error.txt";
            //第一个参数是写入的文件
            //第二个参数:true代表的是追加,false代表的是重新写入,默认是false
            FileOutputStream out = new FileOutputStream(path,true);
            out.write(throwable.getMessage().getBytes());
            String newLine = System.getProperty("line.separator");
            out.write(newLine.getBytes());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("当前文件找不到");
        }

    }

    //writer中发生异常的记录
    @Override
    public void onSkipInWrite(Customer customer, Throwable throwable) {

    }

    //processer发生异常的记录
    @Override
    public void onSkipInProcess(Customer customer, Throwable throwable) {

    }
}

(3)定义reader和writer对象

/**
 * @author gl
 * @time 2020-04-30 15:10
 * @function :定义从数据库写入的writer
 * @step :
 */
@Configuration
public class ItemWriterDbConfig {
    @Autowired
    private DataSource dataSource;

    //注入mysql书写writer
    @Bean(value = "ItemWriterMysql")
    public JdbcBatchItemWriter<Customer> ItemWriterMysql(){
        JdbcBatchItemWriter<Customer> writer = new JdbcBatchItemWriter<>();
        writer.setDataSource(this.dataSource); //设置数据源
        //设置sql骨架语句
        writer.setSql("insert into custmer(id,first_name,last_name,birthday) " + //这里的字段是数据库中的字段名称
                "values(:id,:firstName,:lastName,:birthday)"); //这里的字段是custmer对象的属性字段
        //设置传入的参数
        writer.setItemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<Customer>());
        //返回writer对象
        return writer;
    }
	
	 //定义从文件中读取数据,直接复制从单个文件中读取的reader
    @Bean(value = "fileReader")
    @StepScope//这个表示step单例,意思就是在一个step中一个reader的实例.
    //@Value("#{jobParameters[param2]}" 这个表示调用本方法的时候框架自动给我们从jobparameters去参数param2给本方法使用.
    //但是本取值必须要在jobLauncher启动job时传递进来的参数
    public FlatFileItemReader<Customer> fileReader(@Value("#{jobParameters[param2]}") String param2) {
        System.out.println("reader中获取的jobparameter中的参数paranm2:" + param2); //测试输出我们取到的传入job\中的参数
        FlatFileItemReader<Customer> reader = new FlatFileItemReader<>();
        reader.setResource(new ClassPathResource("custmer.txt"));//设置读取文件的位置
        reader.setLinesToSkip(1);//跳过第几行,因为第一行是列的名字

        //解析数据
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
        tokenizer.setNames("id","firstName","lastName","birthday"); //设置列明名字,及顺序
        //将解析出的字段映射为对象
        DefaultLineMapper<Customer> lineMapper = new DefaultLineMapper<>();
        lineMapper.setLineTokenizer(tokenizer);
        lineMapper.setFieldSetMapper(new FieldSetMapper<Customer>() {
            @Override
            public Customer mapFieldSet(FieldSet fieldSet) throws BindException {
                Customer customer = new Customer();
                customer.setId(fieldSet.readLong("id")); //将以逗号分开的数据,第一个数据放入id中
                customer.setFirstName(fieldSet.readString("firstName"));
                customer.setLastName(fieldSet.readString("lastName"));
                customer.setBirthday(fieldSet.readDate("birthday"));
                return customer;
            }
        });

        //将映射送回reader对象
        reader.setLineMapper(lineMapper);
        return reader;
    }
}

(4)书写job的配置类

/**
 * @author gl
 * @time 2020-04-30 14:59
 * @function : 测试写入mysql数据库中
 * @step :
 * 1.从文件中读取数据
 * 2.读取到的数据写入数据库中
 */
@Configuration
public class SkipExceptionJobDemo {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;
    @Autowired
    @Qualifier("fileReader") //注入以前写的读取文件中的fileReader对象
    private FlatFileItemReader<Customer> reader;
    @Autowired
    @Qualifier(value = "ItemWriterMysql")//注入mysqlWriter对象
    private ItemWriter<Customer> writer;
    @Autowired
    @Qualifier("mySkipListener")
    private SkipListener<? super Customer, ? super Customer> mySkipListener;
    @Autowired
    @Qualifier("stepListenerDemo1")
    private StepExecutionListener stepListener;

    @Bean(value = "SkipExceptionJob")
    public Job SkipExceptionJob(){
        return jobBuilderFactory.get("SkipExceptionJob")
                .start(SkipExceptionStep())
                .build();
    }

    //测试错误跳过
    //这是从文件读取写入到数据库中,我们把文件中的数据写错两行,验证跳过.
    //修改custmer.txt文件中两行,故意写错
    //@Value("#{jobParameters[param2]}") String param2 这种方式不能用在step对象中,
    // 因为step是先于Jobparameters对象创建的
    @Bean(value = "SkipExceptionStep")
    public Step SkipExceptionStep() {
        return stepBuilderFactory.get("SkipExceptionStep")
                .listener(this.stepListener)
                .<Customer,Customer>chunk(2)
                .reader(this.reader)
                .writer(this.writer)
                .faultTolerant()//容错
                .skip(Exception.class)//跳过什么异常
                .noSkip(ArrayIndexOutOfBoundsException.class)//什么异常不跳过
                .skipLimit(3) //跳过次数
                .listener(this.mySkipListener) //这是错误跳过的listener
                .build();
    }

}

(5)主启动类启动,同样的需要修改application.yml文件

4.场景4:数据库读取->多个file

(1)配置reader和writer对象


/**
 * @author gl
 * @time 2020-04-30 15:55
 * @function : 从数据读取数据,按照分类存储到多个文件
 * @step :
 */
@Configuration
public class MultiFileReaderAndWriterConfig {

	
    //读取数据库数据,从哪个数据库读取那张表的那些字段信息
    @Bean(value = "itemReaderDbCustmer")
    @StepScope//一个step,一个实例
    public JdbcPagingItemReader<Customer> itemReaderDbCustmer() {
        JdbcPagingItemReader<Customer> reader = new JdbcPagingItemReader();
        reader.setDataSource(dataSource);//数据源
        reader.setFetchSize(2);//分页,每页读取数据
        reader.setRowMapper(new RowMapper<Customer>() {
            @Override
            public Customer mapRow(ResultSet rs, int i) throws SQLException {
                Customer customer = new Customer();
                customer.setId(rs.getLong(1));
                customer.setFirstName(rs.getString(2));
                customer.setLastName(rs.getString(3));
                customer.setBirthday(rs.getDate(4));
                return customer;
            }
        });
        //指定sql语句
        MySqlPagingQueryProvider provider = new MySqlPagingQueryProvider();
        provider.setSelectClause("id,first_name,last_name,birthday");//指定读取的列名字
        provider.setFromClause("from custmer"); //指定表名
        //根据那个字段进行排序
        Map<String,Order> sort = new HashMap<>(1);
        sort.put("id",Order.DESCENDING);
        provider.setSortKeys(sort);

        //将provider赋值给reader
        reader.setQueryProvider(provider);
        return reader;
    }



    //按照数据类型,将数据分类存储到不同的文件
    @Bean(value = "MultiFileWriter")
    @StepScope
    public ClassifierCompositeItemWriter<Customer> MultiFileWriter(){
        ClassifierCompositeItemWriter<Customer> writer = new ClassifierCompositeItemWriter<>();
        writer.setClassifier(new Classifier<Customer, ItemWriter<? super Customer>>() {
            @Override//这是对custmer分类,分了类之后让不同的writer输出
            public ItemWriter<? super Customer> classify(Customer customer) {
                ItemWriter<Customer> writer1 = null;
                try {//按照custmer对象的id的技术偶数分类.
                    writer1 = (customer.getId()%2 == 0)? itemWriterDbCustmerOdd(): itemWriterDbCustmerEven();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                return writer1;
            }
        });
        return writer;
    }

    //定义输出Writer,写入文件,包括写入的格式是什么
    //这是将custmer的id等于奇数的写入的文件
    @Bean(value = "itemWriterDbCustmerEven")
    @StepScope
    public FlatFileItemWriter<Customer> itemWriterDbCustmerEven() throws Exception {
        FlatFileItemWriter<Customer> writer = new FlatFileItemWriter<>();
        writer.setEncoding("utf8");
        //classpathResource是当前类路径
        //filepathResource是磁盘路劲
        writer.setResource(new FileSystemResource("E:\\custmerEven.txt"));
        //把custmer转化成string
        writer.setLineAggregator(new LineAggregator<Customer>() {
            @Override
            public String aggregate(Customer customer) {
                //转化成json的字符串
                ObjectMapper mapper = new ObjectMapper();
                String result = "";
                try {
                    result = mapper.writeValueAsString(customer);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException("对象转换出现异常");
                }
                return result;
            }
        });

        writer.afterPropertiesSet();
        return  writer;
    }

    //定义输出Writer,写入文件,包括写入的格式是什么
    //这是将custmer的id等于偶数的写入的文件
    @Bean(value = "itemWriterDbCustmerOdd")
    @StepScope
    public FlatFileItemWriter<Customer> itemWriterDbCustmerOdd() throws Exception {
        FlatFileItemWriter<Customer> writer = new FlatFileItemWriter<>();
        writer.setEncoding("utf8");
        //classpathResource是当前类路径
        //filepathResource是磁盘路劲
        writer.setResource(new FileSystemResource("E:\\custmerOdd.txt"));
        //把custmer转化成string
        writer.setLineAggregator(new LineAggregator<Customer>() {
            @Override
            public String aggregate(Customer customer) {
                //转化成json的字符串
                ObjectMapper mapper = new ObjectMapper();
                String result = "";
                try {
                    result = mapper.writeValueAsString(customer);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException("对象转换出现异常");
                }
                return result;
            }
        });

        writer.afterPropertiesSet();
        return  writer;
    }
}

(2)书写job的配置类

/**
 * @author gl
 * @time 2020-04-30 16:29
 * @function :从数据库读取写入多个文件的job配置类
 * @step :
 */
@Configuration
public class ItemWriterMultiFileConfiguration {
    @Autowired
    private JobBuilderFactory jobBuilderFactory;
    @Autowired
    private StepBuilderFactory stepBuilderFactory;

    @Autowired
    @Qualifier("itemReaderDbCustmer")//注入读取custmer表的reader对象
    private ItemReader<Customer> reader;
    @Autowired
    @Qualifier("MultiFileWriter") //注入写的writer对象
    private ItemWriter<Customer> writer;



    @Bean(value = "ItemWriterMultiFileJob")
    public Job ItemWriterMultiFileJob(){
        return jobBuilderFactory.get("ItemWriterMultiFileJob")
                .start(ItemWriterMultiFileStep())
                .build();
    }

    @Bean(value = "ItemWriterMultiFileStep")
    public Step ItemWriterMultiFileStep() {
        return stepBuilderFactory.get("ItemWriterMultiFileStep")
                .<Customer,Customer>chunk(2)
                .reader(this.reader)
                .writer(this.writer)
                .build();
    }

}

以上就是关于springbatch快速入门的基本介绍,当然springbatch中还有很多需要注意的点,以后再总结

  • 1
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值