目前,我可以毫无问题地解组下面的XML,但是在阅读文档时,我得到的是 PublicFigure 对象和 Associate 项目列表。
下面是我当前的实现方式。
我的Xml
<PublicFigure id="101">
<Associate id="102" ex="No" code="66"/>
<Associate id="103" ex="No" code="22"/>
</PublicFigure>
<PublicFigure id="102">
<Associate id="144" ex="No" code="56"/>
<Associate id="155" ex="No" code="45"/>
</PublicFigure>
PublicFigure Java类
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"associate"
})
@XmlRootElement(name = "PublicFigure")
public class PublicFigure {
@XmlElement(name = "Associate", required = true)
protected List<Associate> associate;
@XmlAttribute(name = "id", required = true)
protected BigInteger id;
//getters and setters
关联Java类
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "")
@XmlRootElement(name = "Associate")
public class Associate {
@XmlAttribute(name = "id", required = true)
protected BigInteger id;
@XmlAttribute(name = "code", required = true)
protected BigInteger code;
@XmlAttribute(name = "ex", required = true)
protected String ex;
//getter and setters
是否有任何需要将XML编组为以下对象的对象。换句话说,要从那里结束关联对象和PublicFigure对象,我可以在需要时获取ID。在下面的示例中,我将获得关联对象,但PublicFigure将为NULL
解组到类似下面的内容
@XmlRootElement(name = "Associate")
public class Associate {
@XmlAttribute(name = "id", required = true)
protected BigInteger id;
@XmlAttribute(name = "code", required = true)
protected BigInteger code;
@XmlAttribute(name = "ex", required = true)
protected String ex;
@XmlElement(name = "PublicFigure", required = true)
protected PublicFigure publicFigure;
由于Spring Batch ItemReader和ItemWriter,您可能会问我为什么要这样做。我的ItemWriter希望我读取10个关联对象的块(因为它们必须进入数据库),在每个对象中我都需要引用公共图形ID。用 PublicFigure 对象解组和结束,每个对象都包含一个 Associates 列表,但是我不确定如何处理ItemPreparedStatementSetter,这样我将以10个块结尾而不是Associates的PublicFigures。在每个PublicFigure都有20个关联的列表的情况下(为便于示例,我们假设),在这种情况下,由10个插入块组成的块现在将变为10 * 20 = 200个插入-因为我必须插入关联列表。家有道理。
@Bean
ItemReader<PublicFigure> customerItemReader() {
StaxEventItemReader<PublicFigure> xmlFileReader = new StaxEventItemReader<>();
xmlFileReader.setResource(new ClassPathResource("/data/Test_file.xml"));
xmlFileReader.setFragmentRootElementName("PublicFigure");
Jaxb2Marshaller publicFigMarshaller = new Jaxb2Marshaller();
publicFigMarshaller.setClassesToBeBound(PublicFigure.class);
xmlFileReader.setUnmarshaller(publicFigMarshaller);
return xmlFileReader;
}
@Bean
ItemWriter<Associate> associateItemWriter(DataSource dataSource, NamedParameterJdbcTemplate jdbcTemplate) {
JdbcBatchItemWriter<Associate> databaseItemWriter = new JdbcBatchItemWriter<>();
databaseItemWriter.setDataSource(dataSource);
databaseItemWriter.setJdbcTemplate(jdbcTemplate);
databaseItemWriter.setSql(QUERY_INSERT);
ItemPreparedStatementSetter<Associate> associateItemPreparedStatementSetter = new PersonAssociationsPreparedStatementSetter();
databaseItemWriter.setItemPreparedStatementSetter(associateItemPreparedStatementSetter);
return databaseItemWriter;
}
@Bean
Step associateXmlFileToDatabaseStep() {
return stepBuilderFactory.get("associateXmlFileToDatabaseStep")
.<Associate, Associate>chunk(10)
.reader(associateItemReader())
.writer(associateItemWriter(super.dataSource, super.namedParameterJdbcTemplate))
.build();
}
答案 0 :(得分:0)
我将尝试以相反的方式工作:我将使用PublicFigure
而不是使用Associate
作为根对象。
Associate
对象包含对PublicFigure
父对象的引用,但此引用是使用Jax2Marshaller.Listener
注入的。
侦听器应该很容易编写,因为您会收到未编组的对象及其父对象作为参数
class PublicFigureAssociateListener implements Listener {
afterUnmarshal(Object target, Object parent) {
if(target instanceof Associate) {
((Associate) target).publicFigure = (PublicFigure) parent;
}
}
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "PublicFigure")
public class PublicFigure {
@XmlAttribute(name = "id", required = true)
protected BigInteger id;
@XmlElement(name = "Associate", required = true)
protected List<Associate> associate;
}
@XmlRootElement(name = "Associate")
public class Associate {
@XmlAttribute(name = "id", required = true)
protected BigInteger id;
@XmlAttribute(name = "code", required = true)
protected BigInteger code;
@XmlAttribute(name = "ex", required = true)
protected String ex;
/* This propery will be injected using Marshaller.Listener` */
public PublicFigure publicFigure;
}
因此,您的代码将根据以下内容进行更改:
@Bean
ItemReader<PublicFigure> publicFigureItemReader() {
StaxEventItemReader<PublicFigure> xmlFileReader = new
xmlFileReader.setResource(new ClassPathResource("/data/Test_file.xml"));
xmlFileReader.setFragmentRootElementName("PublicFigure");
Jaxb2Marshaller publicFigMarshaller = new Jaxb2Marshaller();
publicFigMarshaller.setClassesToBeBound(Associate.class, PublicFigure.class);
publicFigMarshaller.setUnmarshallerListener(new PublicFigureAssociateListener());
xmlFileReader.setUnmarshaller(publicFigMarshaller);
}
@Bean
ItemReader<Associate> customerItemReader() {
return new AssociateItemReader(new publicFigureItemReader());
}
编辑
侦听器运行不正常,因此您可以通过以下方式使用委托ItemReader
:
class AssociateItemReader implements ItemReader<Associate> {
private final ItemReader<PublicFigure> delegate;
private ListItemReader l;
AssociateItemReader(ItemReader<PublicFigure> delegate) {
this.delegate = delegate;
this.l = new ListItemReader(Collections.emptyList());
}
Associate read() {
Associate next = l.read();
if(next == null) {
PublicFigure pf = delegate.read();
if(pf != null) {
l = new ListItemReader(pf.getAssociates());
next = l.read();
}
}
return next;
}
}
请记住将publicFigureItemReader()
作为流注册到associateXmlFileToDatabaseStep()
中,以便SB可以处理读取器的生命周期。