当前位置: 首页 > 知识库问答 >
问题:

Spring批处理:从未调用FlatFileItemWriter头

白云
2023-03-14

我的FlatFileItemWriter回调有一个奇怪的问题。我有一个自定义ItemWriter实现FlatFileFolterCallback和FlatFileHeaderCallback。因此,我在我的FlatFileItemWriter中设置页眉和页脚回调如下:

ItemWriter Bean

@Bean
@StepScope
public ItemWriter<CityItem> writer(FlatFileItemWriter<CityProcessed> flatWriter, @Value("#{jobExecutionContext[inputFile]}") String inputFile) {
        CityItemWriter itemWriter = new CityItemWriter();
        flatWriter.setHeaderCallback(itemWriter);
        flatWriter.setFooterCallback(itemWriter);
        itemWriter.setDelegate(flatWriter);
        itemWriter.setInputFileName(inputFile);
        return itemWriter;
}

FlatFileItemWriter Bean

@Bean
@StepScope
public FlatFileItemWriter<CityProcessed> flatFileWriterArchive(@Value("#{jobExecutionContext[outputFileArchive]}") String outputFile) {
    FlatFileItemWriter<CityProcessed> flatWriter = new FlatFileItemWriter<CityProcessed>();
    FileSystemResource isr;
    isr = new FileSystemResource(new File(outputFile));
    flatWriter.setResource(isr);
    DelimitedLineAggregator<CityProcessed> aggregator = new DelimitedLineAggregator<CityProcessed>();
    aggregator.setDelimiter(";");
    BeanWrapperFieldExtractor<CityProcessed> beanWrapper = new BeanWrapperFieldExtractor<CityProcessed>();
    beanWrapper.setNames(new String[]{
        "country", "name", "population", "popUnder25", "pop25To50", "pop50to75", "popMoreThan75"
    });
    aggregator.setFieldExtractor(beanWrapper);
    flatWriter.setLineAggregator(aggregator);
    flatWriter.setEncoding("ISO-8859-1");
    return flatWriter;
}

步进豆

@Bean
public Step stepImport(StepBuilderFactory stepBuilderFactory, ItemReader<CityFile> reader, ItemWriter<CityItem> writer, ItemProcessor<CityFile, CityItem> processor,
    @Qualifier("flatFileWriterArchive") FlatFileItemWriter<CityProcessed> flatFileWriterArchive, ExecutionContextPromotionListener executionContextListener) {
    return stepBuilderFactory.get("stepImport").<CityFile, CityItem> chunk(10).reader(reader(null)).processor(processor).writer(writer).stream(flatFileWriterArchive)
        .listener(executionContextListener).build();
}

我的writeFooter、writeHeader和write方法中都有经典内容。

ItemWriter代码

public class CityItemWriter implements ItemWriter<CityItem>, FlatFileFooterCallback, FlatFileHeaderCallback, ItemStream {
    private FlatFileItemWriter<CityProcessed> writer;
    private static int totalUnknown = 0;
    private static int totalSup10000 = 0;
    private static int totalInf10000 = 0;
    private String inputFileName = "-";

    public void setDelegate(FlatFileItemWriter<CityProcessed> delegate) {
        writer = delegate;
    }

    public void setInputFileName(String name) {
        inputFileName = name;
    }

    private Predicate<String> isNullValue() {
        return p -> p == null;
    }

    @Override
    public void write(List<? extends CityItem> cities) throws Exception {
        List<CityProcessed> citiesCSV = new ArrayList<>();
        for (CityItem item : cities) {
             String populationAsString = "";
             String less25AsString = "";
             String more25AsString = "";
            /*
             * Some processing to get total Unknown/Sup 10000/Inf 10000
             * and other data
             */
            // Write in CSV file
            CityProcessed cre = new CityProcessed();
            cre.setCountry(item.getCountry());
            cre.setName(item.getName());
            cre.setPopulation(populationAsString);
            cre.setLess25(less25AsString);
            cre.setMore25(more25AsString);
            citiesCSV.add(cre);
        }
        writer.write(citiesCSV);
    }

    @Override
    public void writeFooter(Writer fileWriter) throws IOException {
        String newLine = "\r\n";
        String totalUnknown= "Subtotal:;Unknown;" + String.valueOf(nbUnknown) + newLine;
        String totalSup10000 = ";Sum Sup 10000;" + String.valueOf(nbSup10000) + newLine;
        String totalInf10000 = ";Sum Inf 10000;" + String.valueOf(nbInf10000) + newLine;
        String total = "Total:;;" + String.valueOf(nbSup10000 + nbInf10000 + nbUnknown) + newLine;
        fileWriter.write(newLine);
        fileWriter.write(totalUnknown);
        fileWriter.write(totalSup10000);
        fileWriter.write(totalInf10000);
        fileWriter.write(total );
    }

    @Override
    public void writeHeader(Writer fileWriter) throws IOException {
        String newLine = "\r\n";
        String firstLine= "FILE PROCESSED ON: ;" + new SimpleDateFormat("MM/dd/yyyy").format(new Date()) + newLine;
        String secondLine= "Filename: ;" + inputFileName + newLine;
        String colNames= "Country;Name;Population...;...having less than 25;...having more than 25";
        fileWriter.write(firstLine);
        fileWriter.write(secondLine);
        fileWriter.write(newLine);
        fileWriter.write(colNames);
    }

    @Override
    public void close() throws ItemStreamException {
        writer.close();
    }

    @Override
    public void open(ExecutionContext context) throws ItemStreamException {
        writer.open(context);
    }

    @Override
    public void update(ExecutionContext context) throws ItemStreamException {
        writer.update(context);
    }
}

当我运行批处理时,我只有每个城市的数据(写入方法部分)和页脚行。如果我对write方法和footer callback的全部内容进行注释,我仍然没有标题行。我试图添加一个系统。出来println()文本在我的头回调中,似乎从未调用过。

以下是我的批处理生成的CSV文件的示例:

France;Paris;2240621;Unknown;Unknown
France;Toulouse;439553;Unknown;Unknown
Spain;Barcelona;1620943;Unknown;Unknown
Spain;Madrid;3207247;Unknown;Unknown
[...]
Subtotal:;Unknown;2
;Sum Sup 10000;81
;Sum Inf 10000;17
Total:;;100

奇怪的是,当我添加页脚和页眉回调时,我的页眉以前是有效的。我没有更改它们,我也不知道我在代码中做了什么来“破坏”我的头回调。。。当然,我没有保存我的第一个代码。因为我现在才看到我的头已经消失了(我检查了我最后的几个文件,看起来我的头已经消失了一段时间,但我没有看到),我不能只是删除我的修改来查看它发生的时间/原因。

你有办法解决这个问题吗?

谢谢

共有1个答案

壤驷英叡
2023-03-14

在使用Java配置时,最好返回最具体的类型(与Java编程中通常要求的相反)。在本例中,您的编写器返回的是ItemWriter,但受步骤限制。因此,创建了一个代理,它只能看到java配置返回的类型,在本例中是ItemWriter,并且不公开ItemStream接口上的方法。如果您返回CityItemWriter,我希望一切正常。

 类似资料:
  • 我想从文本文件中读取、解析和写入数据。我实现了这一点,但我有一个关于标识符声明的问题。我在下面展示了我的类。 客户数据apper.java 顾客JAVA 文件管理器。xml 我想问这个问题,我可以在FieldSetMapper中使用下面的类吗?如果我在定义标识符时不使用Camelcase符号,那么写入数据库就不起作用了。有什么方法或方法吗?非常感谢。 顾客JAVA

  • 我写了一个处理列表列表的Spring批处理作业。 Reader返回List of List。处理器处理每个ListItem并返回已处理的List。Writer将内容写入DB并从List of List中sftp。 我有一个从spring批处理程序调用异步REST api的用例。在ListenableFuture响应上,我实现了LitenableFutureCallback来处理成功和失败,这正如预

  • 我有一个自定义跳过管理步骤。我定义了一个跳过策略,其源代码如下: 我的Skip侦听器如下: 我的步骤定义如下: 我想跳过一个约束冲突异常。但是,不会调用侦听器或跳过策略。

  • 我有一个compositeItemWriter,它有2个代理编写器:1。HeaderWriter将一些字段从我的对象写入头表2。DetailWriter将文件写入详细表。 context.xml:

  • 我们开发了一个Spring批处理应用程序,其中我们有两个流程。1.向前2.向后。我们只使用文件读/写,不涉及数据库。 > 正向场景:输入文件将包含22个字段的记录。通过执行序列号生成和添加一些填充字段等操作,将22个字段转换为32个字段。根据国家代码,输出将被分成最多3个。每个块将有250K条记录。(如果记录以百万为单位,则将为同一国家生成多个文件)。 800万张唱片需要36分钟。 800万记录将

  • 我无法在使用JPA的Spring启动应用程序中记录Spring批处理日志。这是属性文件配置(application.properties)。我想看看应用程序是否从日志中创建了Spring批处理表。 https://github.com/spring-projects/spring-batch/blob/master/spring-batch-core/src/main/resources/org/