|
对于最新稳定版本,请使用Spring Batch Documentation 6.0.0! |
XML 项目阅读器和写入器
Spring Batch 提供了用于读取 XML 记录和 将它们映射到 Java 对象,以及将 Java 对象写成 XML 记录。
|
流式XML的约束
StAX API 用于 I/O,因为其他标准 XML 解析 API 不适合批量处理 处理需求(DOM 一次性将整个输入加载到内存中,SAX 控制 解析过程通过允许用户仅提供回调)。 |
我们需要考虑 Spring Batch 中 XML 输入和输出的工作原理。首先,有
这些概念在文件读写方面很少有差异,但在春批中很常见
XML处理。通过XML处理,代替记录行(野外集需要的实例)
要被标记化,假设XML资源是一组“片段”
对应于单个记录,如下图所示:
“交易”标签被定义为上述情景中的“根元素”。万事 在“<贸易>”和“</贸易>之间被视为一个”片段“。Spring Batch 使用对象/XML 映射(OXM)将片段绑定到对象。然而,Spring Batch并非如此 绑定到任何特定的XML绑定技术。典型用途是委派给春季OXM,其中 为最流行的OXM技术提供了统一的抽象。对 的依赖关系 Spring OXM 是可选的,你可以选择实现 Spring Batch 专用接口 如果愿意的话。OXM支持的技术与技术的关系在 下图:
通过介绍OXM以及如何使用XML片段表示记录,我们 现在可以更仔细地审视读者和作者。
StaxEventItemReader
这StaxEventItemReader配置为处理
来自XML输入流的记录。首先,考虑以下一组XML记录,
这StaxEventItemReader流程:
<?xml version="1.0" encoding="UTF-8"?>
<records>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0001</isin>
<quantity>5</quantity>
<price>11.39</price>
<customer>Customer1</customer>
</trade>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0002</isin>
<quantity>2</quantity>
<price>72.99</price>
<customer>Customer2c</customer>
</trade>
<trade xmlns="https://springframework.org/batch/sample/io/oxm/domain">
<isin>XYZ0003</isin>
<quantity>9</quantity>
<price>99.99</price>
<customer>Customer3</customer>
</trade>
</records>
为了能够处理XML记录,需要以下条件:
-
根元素名称:构成 待映射对象。示例配置通过贸易价值来证明这一点。
-
资源:表示要读取文件的 Spring 资源。
-
Unmarshaller:Spring OXM 提供的 XML 映射解组功能 碎片化为一个物体。
-
Java
-
XML
以下示例展示了如何定义StaxEventItemReader它能与根一起工作
名为贸易,一个资源data/iosample/input/input.xml, 以及一个未编组器
叫贸易元帅在爪哇语中:
@Bean
public StaxEventItemReader itemReader() {
return new StaxEventItemReaderBuilder<Trade>()
.name("itemReader")
.resource(new FileSystemResource("org/springframework/batch/item/xml/domain/trades.xml"))
.addFragmentRootElements("trade")
.unmarshaller(tradeMarshaller())
.build();
}
以下示例展示了如何定义StaxEventItemReader它能与根一起工作
名为贸易,一个资源data/iosample/input/input.xml, 以及一个未编组器
叫贸易元帅以XML形式表示:
<bean id="itemReader" class="org.springframework.batch.item.xml.StaxEventItemReader">
<property name="fragmentRootElementName" value="trade" />
<property name="resource" value="org/springframework/batch/item/xml/domain/trades.xml" />
<property name="unmarshaller" ref="tradeMarshaller" />
</bean>
注意,在这个例子中,我们选择使用XStreamMarshaller,接受
一个别名作为映射传递,第一个键和值是片段的名称
(即根元素)以及要绑定的对象类型。然后,类似于野外集这
映射到对象类型内字段的其他元素的名称描述为
地图上的键/值对。在配置文件中,我们可以使用 Spring 配置
用于描述所需别名的实用性。
-
Java
-
XML
以下示例展示了如何在 Java 中描述别名:
@Bean
public XStreamMarshaller tradeMarshaller() {
Map<String, Class> aliases = new HashMap<>();
aliases.put("trade", Trade.class);
aliases.put("price", BigDecimal.class);
aliases.put("isin", String.class);
aliases.put("customer", String.class);
aliases.put("quantity", Long.class);
XStreamMarshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliases);
return marshaller;
}
以下示例展示了如何在XML中描述别名:
<bean id="tradeMarshaller"
class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<util:map id="aliases">
<entry key="trade"
value="org.springframework.batch.samples.domain.trade.Trade" />
<entry key="price" value="java.math.BigDecimal" />
<entry key="isin" value="java.lang.String" />
<entry key="customer" value="java.lang.String" />
<entry key="quantity" value="java.lang.Long" />
</util:map>
</property>
</bean>
在输入时,读者读取XML资源,直到识别出新的片段为
快开始了。默认情况下,读卡器会匹配元素名称以识别新的
碎片快开始了。读取器从以下内容创建独立的XML文档
分段并将文档传递给反串化器(通常是包覆Spring的封装器)
OXMUnmarshaller)将XML映射到Java对象。
总之,该过程类似于以下 Java 代码,后者使用 Spring配置提供的注入:
StaxEventItemReader<Trade> xmlStaxEventItemReader = new StaxEventItemReader<>();
Resource resource = new ByteArrayResource(xmlResource.getBytes());
Map aliases = new HashMap();
aliases.put("trade","org.springframework.batch.samples.domain.trade.Trade");
aliases.put("price","java.math.BigDecimal");
aliases.put("customer","java.lang.String");
aliases.put("isin","java.lang.String");
aliases.put("quantity","java.lang.Long");
XStreamMarshaller unmarshaller = new XStreamMarshaller();
unmarshaller.setAliases(aliases);
xmlStaxEventItemReader.setUnmarshaller(unmarshaller);
xmlStaxEventItemReader.setResource(resource);
xmlStaxEventItemReader.setFragmentRootElementName("trade");
xmlStaxEventItemReader.open(new ExecutionContext());
boolean hasNext = true;
Trade trade = null;
while (hasNext) {
trade = xmlStaxEventItemReader.read();
if (trade == null) {
hasNext = false;
}
else {
System.out.println(trade);
}
}
StaxEventItemWriter
输出与输入对称。这StaxEventItemWriter需要一个资源一个
马歇勒,以及rootTagName.Java对象被传递给一个编组器(通常是
标准的Spring OXM Marshaller),该系统写入资源通过使用自定义事件
筛选StartDocument和文档结束为每个项目制作的活动
由OXM工具碎片化。
-
Java
-
XML
以下 Java 示例使用MarshallingEventWriterSerializer:
@Bean
public StaxEventItemWriter itemWriter(Resource outputResource) {
return new StaxEventItemWriterBuilder<Trade>()
.name("tradesWriter")
.marshaller(tradeMarshaller())
.resource(outputResource)
.rootTagName("trade")
.overwriteOutput(true)
.build();
}
以下XML示例使用了MarshallingEventWriterSerializer:
<bean id="itemWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" ref="outputResource" />
<property name="marshaller" ref="tradeMarshaller" />
<property name="rootTagName" value="trade" />
<property name="overwriteOutput" value="true" />
</bean>
上述配置设置了三个所需的属性,并设置了可选的overwriteOutput=trueattrbute,本章前述用以指定
现有文件可以被覆盖。
-
Java
-
XML
以下 Java 示例使用了与读取示例中使用的相同的 marshaller 本章早些时候所示:
@Bean
public XStreamMarshaller customerCreditMarshaller() {
XStreamMarshaller marshaller = new XStreamMarshaller();
Map<String, Class> aliases = new HashMap<>();
aliases.put("trade", Trade.class);
aliases.put("price", BigDecimal.class);
aliases.put("isin", String.class);
aliases.put("customer", String.class);
aliases.put("quantity", Long.class);
marshaller.setAliases(aliases);
return marshaller;
}
以下 XML 示例使用了与读取示例中使用的相同的 marshaller 本章早些时候所示:
<bean id="customerCreditMarshaller"
class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<util:map id="aliases">
<entry key="customer"
value="org.springframework.batch.samples.domain.trade.Trade" />
<entry key="price" value="java.math.BigDecimal" />
<entry key="isin" value="java.lang.String" />
<entry key="customer" value="java.lang.String" />
<entry key="quantity" value="java.lang.Long" />
</util:map>
</property>
</bean>
用 Java 示例总结,以下代码说明了所有要点 讨论,演示了所需属性的程序化设置:
FileSystemResource resource = new FileSystemResource("data/outputFile.xml")
Map aliases = new HashMap();
aliases.put("trade","org.springframework.batch.samples.domain.trade.Trade");
aliases.put("price","java.math.BigDecimal");
aliases.put("customer","java.lang.String");
aliases.put("isin","java.lang.String");
aliases.put("quantity","java.lang.Long");
Marshaller marshaller = new XStreamMarshaller();
marshaller.setAliases(aliases);
StaxEventItemWriter staxItemWriter =
new StaxEventItemWriterBuilder<Trade>()
.name("tradesWriter")
.marshaller(marshaller)
.resource(resource)
.rootTagName("trade")
.overwriteOutput(true)
.build();
staxItemWriter.afterPropertiesSet();
ExecutionContext executionContext = new ExecutionContext();
staxItemWriter.open(executionContext);
Trade trade = new Trade();
trade.setPrice(11.39);
trade.setIsin("XYZ0001");
trade.setQuantity(5L);
trade.setCustomer("Customer1");
staxItemWriter.write(trade);