#java #spring-boot #jaxb #apache-camel #stax
Вопрос:
У меня есть большой XML-файл (может быть около миллиона записей) на сервере sftp. Я не хочу загружать весь файл в память. Намерение состоит в том, что мой маршрут забирает файл, разбивает его и использует stax builder для итерации по элементам, сопоставляет его с объектом JAXB и отправляет в очередь (или пакет spring) для последующего сохранения в базе данных.
input.xml (например, только 2 записи)
<data>
<PRODUCTNUMBER>
<PRODUCTNUMBER>8D0201075E</PRODUCTNUMBER>
<CURRGROSSPRICE>427.90</CURRGROSSPRICE>
<NEXTGROSSPRICE>0.00</NEXTGROSSPRICE>
<NEXTPRICEDATE>1900-01-01 00:00:00</NEXTPRICEDATE>
<PRODUCTNAME_FR>Some description</PRODUCTNAME_FR>
<PRODUCTNAME_NL>Some description</PRODUCTNAME_NL>
</PRODUCTNUMBER>
<PRODUCTNUMBER>
<PRODUCTNUMBER>99630211802</PRODUCTNUMBER>
<CURRGROSSPRICE>3.78</CURRGROSSPRICE>
<NEXTGROSSPRICE>0.00</NEXTGROSSPRICE>
<NEXTPRICEDATE>1900-01-01 00:00:00</NEXTPRICEDATE>
<PRODUCTNAME_FR>Some description</PRODUCTNAME_FR>
</PRODUCTNUMBER>
</data>
Верблюжий маршрут
from("sftp:localhost:22/in")
.split(stax(PartRecords.class)).streaming()
.marshal().json(JsonLibrary.Jackson, true)
.to("rabbitmq://rabbitmq:5672/myExchange?queue=partQueueamp;routingKey=queue.part")
.end();
PartRecord.java
@XmlRootElement(name = "PRODUCTNUMBER")
@XmlAccessorType(XmlAccessType.FIELD)
@Getter
@Setter
@ToString
public class PartRecord implements Serializable {
@XmlElement(name = "PRODUCTNUMBER")
private String productNumber;
@XmlElement(name = "CURRGROSSPRICE")
private BigDecimal currentPrice;
@XmlElement(name = "PRODUCTNAME_NL")
private String partDescriptionNL;
@XmlElement(name = "PRODUCTNAME_FR")
private String partDescriptionFR;
}
PartRecords.java
@XmlRootElement(name = "data")
@XmlAccessorType(XmlAccessType.FIELD)
@ToString
public class PartRecords implements Serializable {
@XmlElement(name = "PRODUCTNUMBER")
private List<PartRecord> partRecords;
public List<PartRecord> getPartRecords() {
if (partRecords == null) {
partRecords = new ArrayList<>();
}
return partRecords;
}
}
Маршрут работает нормально, и сообщение помещается в очередь, но вместо того, чтобы иметь по 1 сообщению на запись, в очередь помещается весь файл в формате json. Я думаю, это нормальное поведение, поэтому мне нужно что-то дополнительное. Я не знаю, хорошо ли иметь 1 сообщение на запись, но я полагаю, что наличие 1 сообщения, содержащего весь файл, также неэффективно.
Вывод текущего поведения
{
"partRecords" : [ {
"productNumber" : "8D0201075E",
"currentPrice" : 427.90,
"partDescriptionNL" : "Some description",
"partDescriptionFR" : "Some description"
}, {
"productNumber" : "99630211802",
"currentPrice" : 3.78,
"partDescriptionNL" : null,
"partDescriptionFR" : "Some description"
}]
}
Что я делаю не так? Я использую Spring Boot v2.5.4, Apache Camel v3.11.1. Заранее спасибо.
Ответ №1:
Используйте PartRecord вместо PartRecords в вашем маршрутизаторе:
from("sftp:localhost:22/in")
.split(stax(PartRecord.class)).streaming()
.marshal().json(JsonLibrary.Jackson, true)
.to("rabbitmq://rabbitmq:5672/myExchange?queue=partQueueamp;routingKey=queue.part")
.end();