Могу ли я использовать FlatFileItemWriter для записи многоформатного файла в Spring Batch?

Я читаю многоформатный файл, используя FlatFileItemReader, сопоставляю каждую строку с соответствующим типом компонента в ItemProcessor и выполняю обогащение данных. Но когда я пытаюсь записать эти записи в файл с помощью FlatFileItemWriter, я не могу назначить отдельные BeanWrapperFieldExtractor для разных типов записей. Как я могу разобраться с этим?

Формат входного файла

1#9999999#00001#2#RecordType1
2#00002#June#Statement#2020#9#RecordType2
3#7777777#RecordType3

Ожидаемый формат выходного файла

1#9999999#00001#2#RecordType1#mobilenumber1
2#00002#June#Statement#2020#9#RecordType2#mobilenumber2
3#7777777#RecordType3#mobilenumber3

ItemProcessor

public class RecordTypeItemProcessor implements ItemProcessor<RecordType, RecordType> {

    @Override
    public RecordType process(RecordType recordType) throws Exception {
        if (recordType instanceof RecordType1) {
            RecordType1 recordType1 = (RecordType1) recordType;
            //enrichment logic
            return recordType1;
        } else if (recordType instanceof RecordType2) {
            RecordType2 recordType2 = (RecordType2) recordType;
            //enrichment logic
            return recordType2;
        }
        else
            return null;
    }
}```

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
1 095
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Вы можете использовать ClassifierCompositeItemProcessor с ClassifierCompositeItemWriter для этого. Идея состоит в том, чтобы классифицировать элементы в соответствии с их типом с помощью Classifier и вызывать соответствующий обработчик/записывающий элемент. Этот подход чище, чем использование нескольких проверок instance of в процессоре/писателе.

Есть несколько встроенных реализаций Classifier (думаю, SubclassClassifier вам подойдет), но при необходимости вы можете создать свои собственные.

Вы можете найти примеры в ClassifierCompositeItemProcessorTests и ClassifierCompositeItemWriterTests.

Опубликую здесь после того, как я реализую рабочее решение, используя этот подход. Спасибо, Махмуд, очень признателен.

pulikuttie 11.12.2020 22:39

Решение, предложенное Махмудом, наконец-то сработало :) Однако есть несколько предостережений. ClassifierCompositeItemWriter предназначен для записи в разные файлы. т. е. если есть 3 разных типа записи, будет 3 разных выходных файла. Но в моем случае использования я ожидаю вывод в одном файле в том же порядке. Итак, я упомянул одно и то же имя файла в каждом бине Writer и добавил `writer.setAppendAllowed(true); Но после этого разные типы записей были объединены вместе, и порядок сортировки изменился. Итак, я уменьшил размер фрагмента с 50 до 3. 3 — это общее количество типов записей. Однако это ударит по производительности. С некоторыми подобными настройками, наконец, я получаю желаемый результат. Вот моя реализация (просто для справки, нужно больше очистки)

Configuration.java (StepBuilderFactory)

...chunk(3).reader(reader).processor(processor()).writer(writer).stream(recordType1FlatFileItemWriter()).stream(recordType2FlatFileItemWriter()).build();

Шаг процессора

@Bean
@StepScope
public ItemProcessor processor() {
            ClassifierCompositeItemProcessor<? extends RecordType, ? extends RecordType> processor = new ClassifierCompositeItemProcessor<>();
            ItemProcessor<RecordType1, RecordType1> recordType1Processor = new ItemProcessor<RecordType1, RecordType1>() {
                @Nullable
                @Override
                public RecordType1 process(RecordType1 recordType1) throws Exception {
                    //Processing logic
                    return recordType1;
                }
            };

            ItemProcessor<RecordType2, RecordType2> recordType2Processor = new ItemProcessor<RecordType2, RecordType2>() {
                @Nullable
                @Override
                public RecordType2 process(RecordType2 recordType2) throws Exception {
                    //Processing logic
                    return recordType2;
                }
            };

        SubclassClassifier classifier = new SubclassClassifier();
        Map typeMap = new HashMap();
        typeMap.put(RecordType1.class, recordType1Processor);
        typeMap.put(RecordType2.class, recordType2Processor);
        classifier.setTypeMap(typeMap);
        processor.setClassifier(classifier);
        return processor;
    }

Шаг писателя

    @Bean
    @StepScope
    public ClassifierCompositeItemWriter writer(@Value("#{stepExecutionContext[fileName]}") Resource file) throws Exception {
        ClassifierCompositeItemWriter<String> writer = new ClassifierCompositeItemWriter<>();
        SubclassClassifier classifier = new SubclassClassifier<>();
        Map typeMap = new HashMap<>();
        typeMap.put(RecordType1.class, recordType1FlatFileItemWriter());
        typeMap.put(RecordType2.class, recordType2FlatFileItemWriter());
        typeMap.put(RecordType3.class, recordType3FlatFileItemWriter());
        classifier.setTypeMap(typeMap);
        writer.setClassifier(classifier);
        return writer;
    }

Писатель

    @Bean
    public FlatFileItemWriter<RecordType1> recordType1FlatFileItemWriter() throws Exception{
        FlatFileItemWriter<RecordType1> writer = new FlatFileItemWriter<>();
        writer.setResource( new FileSystemResource(outputFolder + "test.txt"));
        writer.setAppendAllowed(true);
        writer.setLineAggregator(new DelimitedLineAggregator<RecordType1>() {{
            setDelimiter("#");
            setFieldExtractor(new BeanWrapperFieldExtractor<RecordType1>() {
                {
                    setNames(new String[] { "RecordType", "ID1", "ID2", "ID3");
                }
            });
        }});
        return  writer;
    }

    @Bean
    public FlatFileItemWriter<RecordType2> recordType2FlatFileItemWriter() throws Exception{
        FlatFileItemWriter<RecordType2> writer = new FlatFileItemWriter<>();
        writer.setResource( new FileSystemResource(outputFolder + "test.txt"));
        writer.setAppendAllowed(true);
        writer.setLineAggregator(new DelimitedLineAggregator<RecordType2>() {{
            setDelimiter("#");
            setFieldExtractor(new BeanWrapperFieldExtractor<RecordType2>() {
                {
                    setNames(new String[] { "RecordType", "ID9", "ID8",);
                }
            });
        }});
        return  writer;
    }

Привет, Махмуд, приведенное выше решение отлично сработало. Но я не могу динамически передать имя файла в потоке StepBuilderFactory в FlatFileItemWriter. В моем сценарии в качестве входных данных будет несколько мультиформатных файлов, и такое же количество файлов будет создано в качестве выходных с тем же именем файла. Есть ли решение для этого?

pulikuttie 20.01.2021 04:12

Вы можете использовать средство записи с пошаговой областью (или пошаговую последовательность задания) и выполнить позднюю привязку имени файла из параметра задания. Взгляните на этот раздел из документации: docs.spring.io/spring-batch/docs/4.3.x/reference/html/…

Mahmoud Ben Hassine 20.01.2021 13:35

Другие вопросы по теме