Spring SOAP 请求编组 ~ 如何强制内联长数据(JAXB2 和 MTOM)

问题描述 投票:0回答:1

我遇到以下问题:我需要与旧的 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

如果你愿意,你可以检查一下并尝试以某种方式让测试通过。

java spring soap jaxb marshalling
1个回答
0
投票

我认为你设置错误。试试 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;
}
© www.soinside.com 2019 - 2024. All rights reserved.