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

Spring Boot无请求对象时如何发送SOAP请求?ATMWebSvr场景

解决Spring Boot中基于RPC风格WSDL构建SOAP客户端的问题

看起来你遇到的核心问题是这个WSDL是RPC/Literal风格,和常见的Document风格WSDL处理逻辑不一样,导致JAXB没有生成你预期的请求对象,同时SoapAction的配置也需要对应调整。我来一步步帮你解决:

为什么没有生成averbaCTeRequest这类请求对象?

你的WSDL里明确标注了soap:binding style="rpc",这意味着这是一个RPC风格的SOAP服务。在RPC风格下,请求参数是直接作为独立元素出现在SOAP体中的,而不是被包裹在一个统一的请求对象里。所以JAXB(或wsimport工具)不会生成类似averbaCTeRequest这样的封装类,而是会生成包含对应方法参数的接口——比如你会得到一个ATMWebSvrPortType接口,里面有averbaCTe(String usuario, String senha, String codatm, String xmlCTe)这样的方法签名。

第一步:正确生成JAXB类

你需要用专门的工具处理RPC风格的WSDL,推荐用wsimport命令或者Maven的jaxws-maven-plugin来生成类,而不是单纯用JAXB的基础工具。

方式1:使用wsimport命令

打开终端,执行以下命令(替换包名为你自己的项目包路径):

wsimport -keep -p com.yourproject.atm.wsdl http://webserver.averba.com.br/20/index.soap?wsdl
  • -keep:保留生成的.java文件
  • -p:指定生成类的包名
  • 最后是WSDL的地址(可以直接用在线地址,也可以下载到本地后用本地路径)

方式2:使用Maven插件

在你的pom.xml中添加以下插件配置:

<plugin>
    <groupId>org.jvnet.jax-ws-commons</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.3</version>
    <executions>
        <execution>
            <goals>
                <goal>wsimport</goal>
            </goals>
            <configuration>
                <wsdlUrl>http://webserver.averba.com.br/20/index.soap?wsdl</wsdlUrl>
                <packageName>com.yourproject.atm.wsdl</packageName>
                <keep>true</keep>
            </configuration>
        </execution>
    </executions>
</plugin>

执行mvn clean install后,插件会自动生成对应的JAXB类到指定包下。

第二步:调整Spring Boot客户端代码

方法1:直接使用WebServiceTemplate传递参数

不需要封装请求对象,直接把参数以数组形式传递,同时修正SoapAction的值(必须和WSDL中定义的一致):

public class AtmIntegracaoClient extends WebServiceGatewaySupport {
    private static final Logger log = LoggerFactory.getLogger(AtmIntegracaoClient.class);
    
    @Value("${atm.usuario}")
    private String usuario;
    @Value("${atm.senha}")
    private String senha;
    @Value("${atm.codatm}")
    private String codatm;
    @Value("${atm.url}")
    private String url;

    public Retorno averbaCte(String cteXmlStr) {
        log.info("Enviando requisição de averbação CTe para AT&M");
        
        // RPC风格直接传递参数数组,顺序要和WSDL中定义的一致
        Object[] requestParams = new Object[]{usuario, senha, codatm, cteXmlStr};
        
        // 设置正确的SoapAction:和WSDL里的soap:operation soapAction值完全一致
        Retorno response = (Retorno) getWebServiceTemplate().marshalSendAndReceive(
            url,
            requestParams,
            new SoapActionCallback("urn:ATMWebSvr#averbaCTe")
        );
        
        log.info("Retorno recebido: {}", response);
        return response;
    }
}

同时调整Marshaller的配置,确保支持RPC风格的序列化:

@Configuration
public class AtmIntegracaoConfiguration {
    @Value("${atm.url}")
    private String url;

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // 这里的包名要和你生成JAXB类的包完全一致
        marshaller.setContextPath("com.yourproject.atm.wsdl");
        // 添加RPC风格需要的属性
        marshaller.setMarshallerProperties(Collections.singletonMap(
            javax.xml.bind.Marshaller.JAXB_FRAGMENT, true
        ));
        return marshaller;
    }

    @Bean
    public AtmIntegracaoClient atmIntegracaoClient(Jaxb2Marshaller marshaller) {
        AtmIntegracaoClient client = new AtmIntegracaoClient();
        client.setDefaultUri(url);
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }
}

方法2:使用接口代理(更简洁)

利用生成的ATMWebSvrPortType接口,创建代理类直接调用方法,Spring WS会自动处理参数序列化和SoapAction:

首先在配置类中添加代理Bean:

@Bean
public ATMWebSvrPortType atmWebSvrPortType(Jaxb2Marshaller marshaller) {
    WebServiceTemplate webServiceTemplate = new WebServiceTemplate(marshaller);
    webServiceTemplate.setDefaultUri(url);
    // 创建接口代理
    return (ATMWebSvrPortType) Proxy.newProxyInstance(
        ATMWebSvrPortType.class.getClassLoader(),
        new Class[]{ATMWebSvrPortType.class},
        new SoapServiceInvocationHandler(webServiceTemplate)
    );
}

然后在客户端中注入这个接口,直接调用方法:

@Component
public class AtmIntegracaoClient {
    private static final Logger log = LoggerFactory.getLogger(AtmIntegracaoClient.class);
    
    @Value("${atm.usuario}")
    private String usuario;
    @Value("${atm.senha}")
    private String senha;
    @Value("${atm.codatm}")
    private String codatm;
    
    @Autowired
    private ATMWebSvrPortType atmWebSvrPortType;

    public Retorno averbaCte(String cteXmlStr) {
        log.info("Enviando requisição de averbação CTe");
        // 直接调用接口方法,参数顺序和WSDL一致
        return atmWebSvrPortType.averbaCTe(usuario, senha, codatm, cteXmlStr);
    }
}

这种方式更符合面向接口的编程习惯,也省去了手动处理SoapAction的麻烦。

关键注意点

  1. SoapAction必须完全匹配:你之前代码里写的http://localhost:8080/ATMWebSvr/averbaCTe是错误的,必须和WSDL中soap:operation soapAction="urn:ATMWebSvr#averbaCTe"完全一致。
  2. 参数顺序不能错:RPC风格对参数的顺序要求严格,必须和WSDL中message定义的参数顺序一致。
  3. 确认Marshaller的上下文路径:必须指向生成JAXB类的包,否则会出现序列化/反序列化错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 09:11:11