我遇到以下问题:我需要与旧的 SOAP 服务通信,该服务要求我发送一个请求对象,其中大量数据直接位于 SOAP 消息正文中,如下所示:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<MyRequest xmlns="http://my.company.com/xsd/portals/v4_0">
<documentList xmlns="">
<binaryData>
<blob>
VeryLongDataBlobInHere
</blob>
<extension>pdf</extension>
</binaryData>
</documentList>
</MyRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
问题是,如果启用了 MTOM,Spring 会自动将其转换为这样的附件:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<MyRequest xmlns="http://my.company.com/xsd/portals/v4_0">
<documentList xmlns="">
<binaryData>
<blob>
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:3be5f4d8-50ed-4f88-8e50-778f6cc70c74%40null"/>
</blob>
<extension>pdf</extension>
</binaryData>
</documentList>
</MyRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
相比之下,如果禁用 MTOM,则 blob 为空,如下所示:
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SOAP-ENV:Body>
<MyRequest xmlns="http://my.company.com/xsd/portals/v4_0">
<documentList xmlns="">
<binaryData>
<blob/>
<extension>pdf</extension>
</binaryData>
</documentList>
</MyRequest>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
我尝试了各种方法来解决这个问题,包括弄乱数据类型,并尝试调整编组器的属性以增加 MTOM 阈值,但我尝试的任何方法都不起作用。这是我的编组器配置:
@Configuration
public class Jaxb2MarshallerConfig {
@Bean
public Jaxb2Marshaller myMarshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.company.project.xsd.some_portal.v4_0");
marshaller.setMtomEnabled(true);
return marshaller;
}
}
这是构建和分配二进制数据的地方:
private BinaryData buildBinaryData(byte[] documentData) {
BinaryData binaryData = new BinaryData();
byte[] encodedData = Base64.getEncoder().encode(documentData);
DataHandler dataHandler = new DataHandler(encodedData, "application/pdf");
binaryData.setBlob(dataHandler);
binaryData.setExtension("pdf");
return binaryData;
}
BinaryData 同时是从 WSDL 构建的生成类,因此我无法更改其中的任何内容。但它看起来是这样的:
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "BinaryData", propOrder = {
"blob",
"extension"
})
public class BinaryData {
@XmlElement(required = true)
@XmlMimeType("application/octet-stream")
protected DataHandler blob;
@XmlElement(required = true)
protected String extension;
[...]
}
最后,这就是我如何发送这整个混乱的内容:
@Component
@Log4j2
public class MySoapClient extends WebServiceGatewaySupport {
private final WebServiceTemplate template;
public MySoapClient (
MyServiceProperties properties,
Jaxb2Marshaller marshaller
) {
setMarshaller(marshaller);
setUnmarshaller(marshaller);
setDefaultUri(properties.getTargetUrl());
template = getWebServiceTemplate();
}
@Override
public void sendDocuments(MyRequest request) {
try {
template.marshalSendAndReceive(request);
} catch (Exception e) {
log.error(e, e.getCause());
throw new RuntimeException(e);
}
}
}
我最好的猜测是我需要以某种方式增加 MTOM 阈值,但我不知道如何增加。我尝试摆弄
marshaller.setMarshallerProperties()
,但没有任何效果。
有人知道如何让编组器内联写入 blob 吗?还是其他地方有问题?
我现在创建了一个 github 存储库,其中包含所需的最少代码,以及重现问题并检查所需行为的测试:
https://github.com/KiraResari/jaxb2-marshalling
如果你愿意,你可以检查一下并尝试以某种方式让测试通过。
我认为你设置错误。试试 GPT 的这个回应。
@Bean
public WebServiceTemplate webServiceTemplate(SaajSoapMessageFactory messageFactory, Jaxb2Marshaller marshaller) {
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMessageFactory(messageFactory);
webServiceTemplate.setMarshaller(marshaller);
webServiceTemplate.setUnmarshaller(marshaller);
// Custom initialization to enable MTOM and set threshold
webServiceTemplate.setMessageSender(request -> {
// Obtain the port and configure the binding
Object port = request.getTransportContext().getConnection().getClient();
if (port instanceof BindingProvider) {
SOAPBinding binding = (SOAPBinding) ((BindingProvider) port).getBinding();
binding.setMTOMEnabled(true);
binding.setMTOMThreshold(4096); // Set threshold to 4 KB
}
});
return webServiceTemplate;
}