You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Spring Boot中不使用JAXB编解码调用SOAP服务?

不依赖JAXB的SOAP服务调用等效实现方案

核心思路

放弃JAXB自动编解码机制,改用手动构建SOAP请求XML并解析SOAP响应XML,结合Spring WebServiceTemplate完成服务调用。通过自定义Marshaller和Unmarshaller接口实现,替代原Jaxb2Marshaller的编解码能力。


1. 自定义编解码器(替代Jaxb2Marshaller)

自定义Marshaller(构建请求XML)

import org.springframework.oxm.Marshaller;
import org.w3c.dom.Document;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.dom.DOMResult;

public class PersonActivityMarshaller implements Marshaller {

    @Override
    public boolean supports(Class<?> clazz) {
        return PersonActivityList.class.isAssignableFrom(clazz);
    }

    @Override
    public void marshal(Object source, Result result) {
        PersonActivityList request = (PersonActivityList) source;
        try {
            // 开启命名空间支持,匹配SOAP服务的XML结构
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            factory.setNamespaceAware(true);
            Document doc = factory.newDocumentBuilder().newDocument();
            
            // 构建请求根元素(需匹配WSDL定义的命名空间和元素名)
            org.w3c.dom.Element root = doc.createElementNS("http://test.com/cxfws", "personActivityList");
            doc.appendChild(root);
            
            // 构建request子元素,填充业务数据
            if (request.getRequest() != null) {
                org.w3c.dom.Element requestElem = doc.createElementNS("http://test.com/cxfws", "request");
                
                // 示例:填充PersonActionRequest的字段(根据实际业务字段调整)
                org.w3c.dom.Element idElem = doc.createElement("id");
                idElem.setTextContent(request.getRequest().getId());
                requestElem.appendChild(idElem);
                
                org.w3c.dom.Element nameElem = doc.createElement("name");
                nameElem.setTextContent(request.getRequest().getName());
                requestElem.appendChild(nameElem);
                
                root.appendChild(requestElem);
            }
            
            // 将构建好的Document写入Result
            DOMResult domResult = (DOMResult) result;
            domResult.setNode(doc);
        } catch (Exception e) {
            throw new RuntimeException("构建SOAP请求XML失败", e);
        }
    }
}

自定义Unmarshaller(解析响应XML)

import org.springframework.oxm.Unmarshaller;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMSource;

public class PersonActivityUnmarshaller implements Unmarshaller {

    @Override
    public boolean supports(Class<?> clazz) {
        return PersonActivityListResponse.class.isAssignableFrom(clazz);
    }

    @Override
    public Object unmarshal(Source source) {
        DOMSource domSource = (DOMSource) source;
        Document doc = (Document) domSource.getNode();
        PersonActivityListResponse response = new PersonActivityListResponse();
        
        try {
            // 定位响应根元素(需匹配WSDL定义的命名空间和元素名)
            NodeList resultNodeList = doc.getElementsByTagNameNS("http://test.com/cxfws", "personActivityListResult");
            if (resultNodeList.getLength() > 0) {
                Element resultElem = (Element) resultNodeList.item(0);
                
                // 示例:解析响应字段(根据实际PersonActivityListResponse结构调整)
                NodeList statusNode = resultElem.getElementsByTagName("status");
                if (statusNode.getLength() > 0) {
                    response.setStatus(statusNode.item(0).getTextContent());
                }
                
                // 解析列表类型字段(示例)
                NodeList activityNodes = resultElem.getElementsByTagName("activity");
                // List<PersonActivity> activityList = new ArrayList<>();
                // for (int i = 0; i < activityNodes.getLength(); i++) {
                //     Element activityElem = (Element) activityNodes.item(i);
                //     PersonActivity activity = new PersonActivity();
                //     activity.setId(activityElem.getElementsByTagName("id").item(0).getTextContent());
                //     activity.setType(activityElem.getElementsByTagName("type").item(0).getTextContent());
                //     activityList.add(activity);
                // }
                // response.setActivityList(activityList);
            }
        } catch (Exception e) {
            throw new RuntimeException("解析SOAP响应XML失败", e);
        }
        return response;
    }
}

2. 修改配置类(替换Jaxb2Marshaller)

更新PersonConfig,用自定义编解码器替代原Jaxb2Marshaller:

@Configuration
public class PersonConfig {

    @Value("${personactivity.uri}")
    String defaultUri;

    @Autowired
    TestConfig testConfig;

    @Autowired
    TESTHeaderInterceptor headerInterceptor;

    // 注册自定义Marshaller
    @Bean
    public Marshaller personActivityMarshaller() {
        return new PersonActivityMarshaller();
    }

    // 注册自定义Unmarshaller
    @Bean
    public Unmarshaller personActivityUnmarshaller() {
        return new PersonActivityUnmarshaller();
    }
    
    @Bean("PersonWebServiceTemplate")
    public WebServiceTemplate updateWebServiceTemplate() throws Exception {
        SaajSoapMessageFactory messageFactory = new SaajSoapMessageFactory(MessageFactory.newInstance());
        messageFactory.afterPropertiesSet();
        WebServiceTemplate updateWebServiceTemplate = new WebServiceTemplate(messageFactory);
        
        // 替换为自定义编解码器
        updateWebServiceTemplate.setMarshaller(personActivityMarshaller());
        updateWebServiceTemplate.setUnmarshaller(personActivityUnmarshaller());
        
        updateWebServiceTemplate.setDefaultUri(defaultUri);
        updateWebServiceTemplate.setMessageSender(testConfig.createMessageSender());
        updateWebServiceTemplate.afterPropertiesSet();
        updateWebServiceTemplate.setInterceptors(new ClientInterceptor[]{headerInterceptor});
        return updateWebServiceTemplate;
    }

    public String getDefaultUri() {
        return defaultUri;
    }
}

3. 业务调用类(无需修改)

原业务调用逻辑可直接复用,WebServiceTemplate会自动使用自定义编解码器处理消息:

@Service
public class PublicActivity{
    @Autowired
    @Qualifier("PersonWebServiceTemplate")
    private WebServiceTemplate personWebServiceTemplate;
    
    public PersonActivityListResponse getPersonActivityList(PersonActivityList request) {
        return (PersonActivityListResponse) personWebServiceTemplate.marshalSendAndReceive(request);
    }
}

关键注意事项

  • 严格匹配XML结构:手动构建/解析XML时,必须完全匹配SOAP服务的命名空间、元素名和层级结构,可通过抓包或查看WSDL确认格式。
  • 简化XML操作:若XML结构复杂,可引入Apache Commons Digester或DOM4J框架简化节点解析,减少手动DOM操作的冗余代码。
  • 底层SAAJ备选方案:也可直接使用SAAJ API构建完整SOAP消息,通过WebServiceTemplate.sendAndReceive方法发送,可控性更强但代码量更大。

内容的提问来源于stack exchange,提问作者userKG

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 14:57:57