Как написать несколько файлов XML для дочерних компонентов в Spring Batch ItemWriter?

У меня есть пакетное задание, которое извлекает записи из базы данных, обрабатывает их и передает результат писателю. Компонент, переданный модулю записи, имеет четыре поля, которые необходимо записать в отдельные файлы xml. Одно из полей - это bean-компонент, представляющий исходную запись, а три других поля - это коллекции дочерних элементов, связанных с записью.

Сначала я попытался использовать Джексона для анализа bean-компонентов и генерации файлов, но обнаружил, что этот подход вызывает проблемы при применении к пакетной модели.

Затем я перешел на использование StaxEventItemWriters для каждого дочернего поля, которые по отдельности кажутся вполне адекватными, но у меня возникают проблемы с реализацией модуля записи, который может обрабатывать все различные подтипы. Я заглянул вCompositeItemWriter а также ClassifierCompositeItemWriter, но они кажутся более подходящими для того, чтобы иметь несколько писателей для одного и того же типа bean-компонента, тогда как мне нужно несколько писателей, подходящих для разных типов. Любой совет будет очень признателен!

Пример домена:

public class MyBean {
    private RecordBean recordBean;
    private List<ChildTypeA> aBeans;
    private List<ChildTypeB> bBeans;
    private List<ChildTypeC> cBeans;
}

@XmlRootElement(name = "RECORD")
public class RecordBean extends MyAbstractBean {
    @XmlElement(name = "ID")
    private String recordId;

    @XmlElementWrapper(name = "A_CHILDREN")
    @XmlElement(name="CHILD_TYPE_A")
    List<Long> aChildIds}

    @XmlElementWrapper(name = "B_CHILDREN")
    @XmlElement(name="CHILD_TYPE_B")
    List<Long> bChildIds}

    @XmlElementWrapper(name = "C_CHILDREN")
    @XmlElement(name="CHILD_TYPE_C")
    List<Long> cChildIds}
}

@XmlRootElement(name = "CHILD_TYPE_A")
public class ChildTypeA extends MyAbstractBean {
    @XmlElement(name = "ID") private String aId;
}

@XmlRootElement(name = "CHILD_TYPE_B")
public class ChildTypeB extends MyAbstractBean {
    @XmlElement(name = "ID") private String bId;
}

@XmlRootElement(name = "CHILD_TYPE_C")
public class ChildTypeC extends MyAbstractBean {
    @XmlElement(name = "ID") private String cId;
}

Для каждого контейнерного bean-компонента, переданного писателю, мне нужно создать уникальный XML-файл для каждого RecordBean например, record_1.xml, и мне нужно записать каждую коллекцию в совокупный файл, который будет служить библиотекой всех дочерних элементов для этого дочернего типа во всех записях.

Пример вывода:record_1.xml

<?xml version="1.0" encoding="UTF-8"?>
<RECORD>
    <ID>1</ID>
    <A_CHILDREN>
        <CHILD_TYPE_A>1</CHILD_TYPE_A>
        <CHILD_TYPE_A>2</CHILD_TYPE_A>
    </A_CHILDREN>
    <B_CHILDREN>
        <CHILD_TYPE_B>1</CHILD_TYPE_B>
        <CHILD_TYPE_B>2</CHILD_TYPE_B>
    </B_CHILDREN>
    <A_CHILDREN>
        <CHILD_TYPE_C>1</CHILD_TYPE_C>
        <CHILD_TYPE_C>2</CHILD_TYPE_C>
    </A_CHILDREN>
</RECORD>
</xml>

record_2.xml

<?xml version="1.0" encoding="UTF-8"?>
<RECORD>
    <ID>2</ID>
    <A_CHILDREN>
        <CHILD_TYPE_A>3</CHILD_TYPE_A>
        <CHILD_TYPE_A>4</CHILD_TYPE_A>
    </A_CHILDREN>
    <B_CHILDREN>
        <CHILD_TYPE_B>3</CHILD_TYPE_B>
        <CHILD_TYPE_B>4</CHILD_TYPE_B>
    </B_CHILDREN>
    <A_CHILDREN>
        <CHILD_TYPE_C>3</CHILD_TYPE_C>
        <CHILD_TYPE_C>4</CHILD_TYPE_C>
    </A_CHILDREN>
</RECORD>
</xml>

a_children.xml

<?xml version="1.0" encoding="UTF-8"?>
<A_CHILDREN>
    <CHILD_TYPE_A>
        <ID>1</ID>
    </CHILD_TYPE_A>
    <CHILD_TYPE_A>
        <ID>2</ID>
    </CHILD_TYPE_A>
    <CHILD_TYPE_A>
        <ID>3</ID>
    </CHILD_TYPE_A>
    <CHILD_TYPE_A>
        <ID>4</ID>
    </CHILD_TYPE_A>
</A_CHILDREN>
</xml>
<!-- Decide which format to use -->

b_children.xml и c_children.xml - это то же самое, что и a_children.xml.

1 ответ

Итак, по прошествии большей части двух дней я решил применить другой подход. Я думаю, что можно было бы создать набор писателей для решения этой задачи, но я думаю, что это потребует изрядной настройки и сложной иерархии делегирования.

Например:

  • CompositeItemWriter делегаты:
    • ClassifierCompositeItemWriter классифицирует и делегирует:
      • StaxEventItemWriter для ChildTypeA
      • StaxEventItemWriter для ChildTypeB
      • StaxEventItemWriter для ChildTypeC
    • MultiResourceItemWriter Динамически назначает FilesystemResource для каждого RecordBean.

Несмотря на то, что это, вероятно, можно было бы сделать, я понял, что проще писать XML в виде строк, где я хочу. Что-то вроде:

@Component
@Scope("step")
public class MyXmlWriter implements ItemWriter<MyBean> {
    @Override
    public void write(List<? extends MyBean> beans) throws Exception {
        for(MyBean bean : beans) {
            this.writeRecordBean(bean.getRecordBean());
            bean.getAChildIds().forEach(a -> this.writeElement(a, pathA));
            bean.getBChildIds().forEach(b -> this.writeElement(b, pathB));
            bean.getCChildIds().forEach(c -> this.writeElement(c, pathC));
        }
    }

    private void writeElement(Long Id, Path path) {
        // Handle serialization and FileIO here
    }

    .
    .
    .

}

В любом случае, я надеюсь, что это поможет любому, кто копается в сорняках Spring Batch, как и я. Ура!

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