我有一个简单的itemwriter,看起来如下:
return new StaxEventItemWriterBuilder<AddSubscriptionXml>()
.version("1.0")
.rootTagName("BePostSubscriptionDistribution")
.name("optInSumoItemWriter")
.rootElementAttributes(rootAttrs)
.resource(new FileSystemResource(sumoSavePath + "/opt_ins_add.xml"))
.marshaller(jaxb2Marshaller)
.build();
我的编组程序具有以下属性:
@Bean
@Scope(SCOPE_PROTOTYPE)
public Jaxb2Marshaller jaxb2Marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setMarshallerProperties(getMarshallerProps());
marshaller.setClassesToBeBound(AddSubscriptionXml.class, ModSubscriptionXml.class, DelSubscriptionXml.class);
return marshaller;
}
private Map<String, String> getMarshallerProps() {
return new HashMap<>(){{
put(Marshaller.JAXB_ENCODING, UTF_8.toString());
put(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
put("com.sun.xml.bind.xmlHeaders", "<!DOCTYPE BePostSubscriptionDistribution SYSTEM "..\BePostSubscriptionDistribution.dtd">");
}};
}
奇怪的是,编组器属性被StaxEventItemWriter完全忽略了。
首先,输出看起来像垃圾,没有缩进。但更重要的是,我错过了DocType行:
结果(自行格式化):
<?xml version="1.0" encoding="UTF-8"?>
<BePostSubscriptionDistribution TimeDateStamp="2021-08-26 13:03:44.761" identification="addSubscription">
<AddMagazineSubscription>
<SubscriptionNumber EditionCode="EDITION_CODE_1">id__19860702 064M81</SubscriptionNumber>
...
所需:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE BePostSubscriptionDistribution SYSTEM "..BePostSubscriptionDistribution.dtd">
...
你知道怎么解决这个问题吗?浪费大量的时间在一些应该是微不足道的事情上。
注意:在调试模式下,我看到当传递给ItemWriter时,编组器属性被正确设置。
注意:我在这里打开了一个Github问题:https://github.com/spring-projects/spring-batch/issues/3982
浏览源代码后,我认为没有立即解决这个问题的办法。编组器最初并不用于编写xml文件头,而仅用于编写根目录下的xml项。
我会和对方核实一下,看他们是否能接受省略文档类型。
如果没有其他选择,我将下载StaxEventItemWriter来分析如何编写输出流并添加所需的功能。虽然从未来升级的角度来看,提供一个后门备份api会更好(imo)。
对于缩进,我使用了这里提到的运行良好的补丁:来自Spring批处理Jaxb2Marshaller - Marshaller的XML输出。JAXB_FORMATTED_OUTPUT不工作,为什么?
虽然我不清楚为什么缩进/漂亮的打印不立即添加到春季批StaxEventItemWriter作为选项,而不是使用外部库。缩进似乎是任何使用XML和在2021年发送未格式化XML的人的基本要求。管理员会本能地立即查看文件(可能是通过终端),以防事情不像预期的那样发展。
根据@Mahmoud Ben Hassine的评论:
我可以通过提供自定义实现重写方法startDocument
和endDocument
来修复docType问题。
这也会破坏当前关于rootElement的api,但没有什么是不能从子类中修复的。