使用 Spring 启动时无法使用 SoapWeb 服务?

Consuming SoapWeb Services with Spring Boot not working?

我正在使用 open-jdk 11 和 spring 启动版本 2.3.0.RELEASE。我是肥皂网络服务的新手,我想尝试用肥皂生产商样本进行测试。下面是我尝试使用的 wsdl 的 link: http://www.thomas-bayer.com/axis2/services/BLZService?wsdl

我在 pom.xml 中添加了以下插件,用于从 wsdl 生成 classes:

            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.14.0</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <generatePackage>soapws.credins.api</generatePackage>
                    <generateDirectory>${project.basedir}/src/main/java</generateDirectory>
                    <schemaDirectory>${project.basedir}/src/main/resources/wsdl</schemaDirectory>
                    <schemaIncludes>
                        <include>*.wsdl</include>
                    </schemaIncludes>
                    <clearOutputDir>true</clearOutputDir>
                </configuration>
            </plugin>

然后我运行一个mvn install,所有的classes都生成成功了。我创建了一个 bean Jaxb2Marshaller 用于从 java class 转换为 xml。下面是实现:

@Configuration
public class SoapConfiguration {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setPackagesToScan("package.api");
        return marshaller();
    }

}

之后,我创建了一个客户端 class,它进行如下 soap 调用:

@Component
public class BankClient {

    @Autowired
    private Jaxb2Marshaller marshaller;

    private WebServiceTemplate template;

    public DetailsType getBankDetails(String blz) {
        GetBankType request = new GetBankType();
        request.setBlz(blz);
        template = new WebServiceTemplate(marshaller);
        DetailsType detail = (DetailsType) template
                .marshalSendAndReceive("http://www.thomas-bayer.com/axis2/services/BLZService", request);
        return detail;
    }

}

执行调用时遇到问题:

org.springframework.oxm.MarshallingFailureException: JAXB marshalling exception; nested exception is javax.xml.bind.MarshalException
 - with linked exception:

我通过将 @XmlRootElement 添加到 GetBankType class 解决了这个问题,如下所示:

    @XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "getBankType", propOrder = {
    "blz"
})
public class GetBankType {

    @XmlElement(required = true)
    protected String blz;

    /**
     * Gets the value of the blz property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getBlz() {
        return blz;
    }

    /**
     * Sets the value of the blz property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setBlz(String value) {
        this.blz = value;
    }

}

现在我被这个问题困住了: 我无法弄清楚问题出在哪里。


org.springframework.ws.soap.client.SoapFaultClientException: The endpoint reference (EPR) for the Operation not found is http://www.thomas-bayer.com/axis2/services/BLZService and the WSA Action = 
    at org.springframework.ws.soap.client.core.SoapFaultMessageResolver.resolveFault(SoapFaultMessageResolver.java:38)
    at org.springframework.ws.client.core.WebServiceTemplate.handleFault(WebServiceTemplate.java:830)
    at org.springframework.ws.client.core.WebServiceTemplate.doSendAndReceive(WebServiceTemplate.java:624)
    at org.springframework.ws.client.core.WebServiceTemplate.sendAndReceive(WebServiceTemplate.java:555)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:390)
    at org.springframework.ws.client.core.WebServiceTemplate.marshalSendAndReceive(WebServiceTemplate.java:378)
    at soapws.client.BankUpClient.getBankDetails(BankUpClient.java:26)

我做错了什么

首先从包 package.api.

中生成的 classes 中删除 @XmlRootElement

下一步修改 BankClient 如下:

@Component
public class BankClient {

    @Autowired
    private Jaxb2Marshaller jaxb2Marshaller;

    private WebServiceTemplate template;

    public JAXBElement<GetBankResponseType> getBankDetails(String blz) {
        GetBankType getBankType = new GetBankType();
        getBankType.setBlz(blz);
        ObjectFactory objectFactory = new ObjectFactory();
        JAXBElement<GetBankType> request = objectFactory.createGetBank(getBankType);
        template = new WebServiceTemplate(jaxb2Marshaller);
        JAXBElement<GetBankResponseType> response = (JAXBElement<GetBankResponseType>) template
                .marshalSendAndReceive("http://www.thomas-bayer.com/axis2/services/BLZService", request);
        return response;
    }

}

要构建请求,您需要使用从 WSDL 自动生成的 class ObjectFactoryObjectFactory class 允许我们以编程方式构造来自 java 对象的请求,这些对象将表示 XML 内容。

接下来要记住的是,您将从 WebServiceTemplate 获得的响应也会 GetBankResponseType 包裹在 XML 内容的表示中。 GetBankResponseType 将成为一个对象,它将包含我们从 soap 接收到的信息的内容模型和属性值。

下面是 BankClient 的集成测试:

@ExtendWith(SpringExtension.class)
@SpringBootTest
public class BankClientTest {

    @Autowired
    private BankClient client;


    @BeforeEach
    public void setup() {
    }

    @Test
    void testGetBankDetails() {
        // setup
        String blzCode = "39580041";
        String bezeichnungExpected = "Dresdner Bank";
        String bicExpected = "DRESDEFF395";
        String ortExpected = "Düren, Rheinl";
        String plzExpected = "52304";
        // execute
        JAXBElement<GetBankResponseType> response = client.getBankDetails(blzCode);
        // verify
        assertEquals(bezeichnungExpected, response.getValue().getDetails().getBezeichnung());
        assertEquals(bicExpected, response.getValue().getDetails().getBic());
        assertEquals(ortExpected, response.getValue().getDetails().getOrt());
        assertEquals(plzExpected, response.getValue().getDetails().getPlz());
    }

}