Как написать несколько файлов XML для дочерних компонентов в Spring Batch ItemWriter?
У меня есть пакетное задание, которое извлекает записи из базы данных, обрабатывает их и передает результат писателю. Компонент, переданный модулю записи, имеет четыре поля, которые необходимо записать в отдельные файлы xml. Одно из полей - это bean-компонент, представляющий исходную запись, а три других поля - это коллекции дочерних элементов, связанных с записью.
Сначала я попытался использовать Джексона для анализа bean-компонентов и генерации файлов, но обнаружил, что этот подход вызывает проблемы при применении к пакетной модели.
Затем я перешел на использование StaxEventItemWriter
s для каждого дочернего поля, которые по отдельности кажутся вполне адекватными, но у меня возникают проблемы с реализацией модуля записи, который может обрабатывать все различные подтипы. Я заглянул в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
для ChildTypeAStaxEventItemWriter
для ChildTypeBStaxEventItemWriter
для 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, как и я. Ура!