Укажите верхний и нижний колонтитулы для всех файлов, созданных MultiResourceItemWriter, при записи в несколько файлов - весенний пакет

У меня есть пакет, который читает из базы данных с помощью JdbcPagingItemReader, обрабатывает каждую запись из базы данных в классе java, а затем записывает ее в файл с помощью FlatFileItemWriter. Он также добавляет верхний и нижний колонтитулы к этому файлу с помощью FlatFileFooterCallback и FlatFileHeaderCallback

Работа работает хорошо, и на выходе она дает один файл JSON в этом формате:

{"informations":[
{
 "name" : "xxx",
 "adress" : "xxx"
  //a very complex json object (1000 lines)
},
{
   "name" : "xxx",
 "adress" : "xxx"
  //a very complex json object (1000 lines )
},

// Many objects
]}

Обратите внимание, что заголовок выглядит следующим образом:

{"informations":[

И нижний колонтитул просто

]}

теперь файл слишком велик, и я хочу разбить его на несколько файлов, используя MultiResourceItemWriter. Каждый файл имеет максимум 1000 строк, прочитанных из базы данных.

Итак, я настроил шаг и использовал первый FlatFileItemWriter, описанный выше, и это хорошо сработало. В результате у меня есть много файлов, содержащих 1000 записей из базы данных, но без верхнего и нижнего колонтитула {"informations":[ и ]}

Все файлы, созданные MultiResourceItemWriter, имеют следующий формат:

{
 "name" : "xxx",
 "adress" : "xxx"
  a very complex json object (1000 lines)
},
{
   "name" : "xxx",
 "adress" : "xxx"
  a very complex json object (1000 lines )
},
{
// many objects
}

Как мне добавить верхний и нижний колонтитулы для всех файлов, созданных MultiResourceItemWriter При записи.

Я нашел ответ, в котором говорится, что мы не можем комбинировать MultiResourceItemWriter с FlatFileItemWriter, у которых есть FlatFileFooterCallback и FlatFileHeaderCallback с весенней пакетной версией ‹2.1.

Исключение закрытия потока при объединении MultiResourceItemWriter и FlatFileItemWriter с обратным вызовом нижнего колонтитула и переполнением стека разместить stack-overflow-post-about-my -проблема

У меня есть это исключение java.lang.IllegalStateException: JsonWriter is closed, когда я пытаюсь обернуть FlatFileItemWriter с FlatFileHeaderCallback в моем последнем MultiResourceItemWriter писателе.

Итак, есть ли способ указать верхний и нижний колонтитулы для всего файла, созданного MultiResourceItemWriter при записи в новый файл (разделение на несколько файлов)? Есть ли способ определить шаблон файла, в который записывается MultiResourceItemWriter?

Если нет, не могли бы вы посоветовать мне это сделать?

Я хотел бы, чтобы в конечном итоге все файлы, созданные MultiResourceItemWriter, имели в начале {"informations":[, а в конце ]}, все содержимое файла заключено в массив json informations.


person Abenamor    schedule 28.01.2021    source источник


Ответы (1)


Как мне добавить верхний и нижний колонтитулы для всех файлов, созданных MultiResourceItemWriter При записи.

Вам необходимо установить обратные вызовы верхнего / нижнего колонтитула для вашего автора делегата. Вот краткий пример:

import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.Step;
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.launch.JobLauncher;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.file.FlatFileFooterCallback;
import org.springframework.batch.item.file.FlatFileHeaderCallback;
import org.springframework.batch.item.file.FlatFileItemWriter;
import org.springframework.batch.item.file.ResourceSuffixCreator;
import org.springframework.batch.item.file.builder.FlatFileItemWriterBuilder;
import org.springframework.batch.item.file.builder.MultiResourceItemWriterBuilder;
import org.springframework.batch.item.file.transform.PassThroughLineAggregator;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.FileSystemResource;

@Configuration
@EnableBatchProcessing
public class MyJob {

    @Bean
    public ItemReader<Integer> itemReader() {
        return new ListItemReader<>(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9, 10));
    }

    @Bean
    public ItemWriter<Integer> itemWriter() {
        FlatFileItemWriter<Integer> flatFileItemWriter = new FlatFileItemWriterBuilder<Integer>()
                .lineAggregator(new PassThroughLineAggregator<>())
                .name("itemsWriter")
                .headerCallback(writer -> writer.write("header"))
                .footerCallback(writer -> writer.write("footer"))
                .build();

        return new MultiResourceItemWriterBuilder<Integer>()
                .delegate(flatFileItemWriter)
                .resource(new FileSystemResource("items"))
                .itemCountLimitPerResource(5)
                .resourceSuffixCreator(index -> "-" + index + ".txt")
                .name("multiResourcesWriter")
                .build();
    }

    @Bean
    public Job job(JobBuilderFactory jobs, StepBuilderFactory steps) {
        return jobs.get("job")
                .start(steps.get("step")
                        .<Integer, Integer>chunk(5)
                        .reader(itemReader())
                        .writer(itemWriter())
                        .build())
                .build();
    }

    public static void main(String[] args) throws Exception {
        ApplicationContext context = new AnnotationConfigApplicationContext(MyJob.class);
        JobLauncher jobLauncher = context.getBean(JobLauncher.class);
        Job job = context.getBean(Job.class);
        jobLauncher.run(job, new JobParameters());
    }

}

В результате будут созданы два файла items-1.txt и items-2.txt со следующим содержимым:

header
1
2
3
4
5
footer

и

header
6
7
8
9
10
footer

Я использую spring batch версии 3.0.10.RELEASE

Эта версия больше не поддерживается, поэтому я рекомендую вам перейти на последнюю и лучшую версию v4.3.1. В приведенном выше примере используется Spring Batch v4.3.1, и он работает должным образом.

person Mahmoud Ben Hassine    schedule 28.01.2021
comment
Спасибо @Mahmoud, но я уже пробовал это и получил следующее исключение: ERROR o.s.b.c.s.AbstractStep - Исключение при закрытии ресурсов выполнения шага на шаге step4 в задании java.lang.IllegalStateException: JsonWriter закрыт. - person Abenamor; 28.01.2021
comment
Ваш делегат <property name="delegate" ref="singleEventItemWriter" />, имеющий тип com.xx.xx.CustomFlatFileItemWriter. Вы не предоставили полный код этого настраиваемого писателя, поэтому проблема, похоже, связана с вашим кодом, поскольку он работает должным образом со встроенным FlatFileItemWriter, предоставленным Spring Batch. - person Mahmoud Ben Hassine; 28.01.2021
comment
Вот мой MyCustomFlatFileItemWriter, как вы просили: - person Abenamor; 28.01.2021
comment
Я добавил код customFlatItemWriter, как вы просили, и добавил трассировку стека исключения. Спасибо - person Abenamor; 28.01.2021
comment
Спасибо за обновления. Из вашей трассировки стека я вижу [SimpleAsyncTaskExecutor-2] ERROR o.s.b.c.s.AbstractStep ... Является ли ваш шаг многопоточным? Я не вижу этого в вашей конфигурации xml (без элемента task-executor), но я хочу убедиться, что это не так (возможно, проблема с копированием / вставкой). Потому что, если ваш шаг является многопоточным, это объясняет проблему: два потока могут вызывать jsonWriter.close, и один из них не работает с этим исключением. FlatFileItemWriter не потокобезопасен и должен синхронизироваться, если используется в многопоточном шаге. - person Mahmoud Ben Hassine; 29.01.2021
comment
Спасибо @Mahmoud за ответ. Да, я использовал split для распараллеливания потока работ. Я отредактировал свой пост. Я добавил всю конфигурацию своей работы, которую использовал. Спасибо - person Abenamor; 29.01.2021
comment
Это очень важная деталь, о которой должен был быть вопрос с самого начала, чтобы помочь вам эффективно. The writer CusXxWriter didn't use the The class MyCustomItemHeaderFooterWriter but it uses the jsonWriter: извините, но я больше не могу следить, пожалуйста, проверьте: stackoverflow.com/help/minimal-reproducible-example. Я не могу отлаживать ваш код как есть, но дам вам несколько советов: в многопоточной среде вам нужно убедиться, что ваш писатель является потокобезопасным. - person Mahmoud Ben Hassine; 29.01.2021