本指南将指导您使用Spring使用基于SOAP的Web服务。您将构建一个客户端,该客户端使用SOAP从基于WSDL的Webservice服务获取国家数据。您将能够根据某个国家的名称查询该国家的数据。

程序结构

└── src
    └── main
        └── java
            └── hello

pom.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-consuming-web-service</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
           <dependency>
               <groupId>org.springframework.ws</groupId>
               <artifactId>spring-ws-core</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <!-- tag::wsdl[] -->
            <plugin>
                <groupId>org.jvnet.jaxb2.maven2</groupId>
                <artifactId>maven-jaxb2-plugin</artifactId>
                <version>0.12.3</version>
                <executions>
                    <execution>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <schemaLanguage>WSDL</schemaLanguage>
                    <generatePackage>hello.wsdl</generatePackage>
                    <schemas>
                        <schema>
                            <url>http://localhost:8080/ws/countries.wsdl</url>
                        </schema>
                    </schemas>
                </configuration>
            </plugin>
            <!-- end::wsdl[] -->
        </plugins>
    </build>

</project>

Spring Boot将会你做如下的事:

  • 将 classpath 里面所有用到的jar包构建成一个可执行的 JAR 文件,方便执行你的程序
  • 搜索public static void main()方法并且将它当作可执行类
  • 根据springboot版本,去查找相应的依赖类版本,当然你可以定义其它版本。

在本地运行目标Web服务
按照指南中的步骤操作,或者只拷贝存储库并从其完整目录运行服务(例如,使用mvn spring-boot:run)。您可以通过在浏览器中访问http://localhost:8080/ws/countries.wsdl来验证是否有效。

生成基于WSDL的域对象

SOAP Web服务的描述写在WSDL中。JAXB提供了一种从WSDL(或更确切地说,在WSDL的<Types/>节中包含的XSD)生成Java类的简单方法。本次国家查询服务的WSDL可以在http://localhost:8080/ws/countries.wsdl上找到。

要从Maven中的WSDL生成Java类,需要在pon.xml中增加如下设置:

<plugin>
    <groupId>org.jvnet.jaxb2.maven2</groupId>
    <artifactId>maven-jaxb2-plugin</artifactId>
    <version>0.13.1</version>
    <executions>
        <execution>
            <goals>
                <goal>generate</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaLanguage>WSDL</schemaLanguage>
        <generatePackage>hello.wsdl</generatePackage>
        <schemas>
            <schema>
                <url>http://localhost:8080/ws/countries.wsdl</url>
            </schema>
        </schemas>
    </configuration>
</plugin>

此安装程序将为在指定的URL上找到的WSDL生成类,并将这些类放入hello.wsdl包中。
要对Gradle执行相同的操作,您的构建文件中将需要以下内容:

task genJaxb {
    ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
    ext.classesDir = "${buildDir}/classes/jaxb"
    ext.schema = "http://localhost:8080/ws/countries.wsdl"

    outputs.dir classesDir

    doLast() {
        project.ant {
            taskdef name: "xjc", classname: "com.sun.tools.xjc.XJCTask",
                    classpath: configurations.jaxb.asPath
            mkdir(dir: sourcesDir)
            mkdir(dir: classesDir)

            xjc(destdir: sourcesDir, schema: schema,
                    package: "hello.wsdl") {
                arg(value: "-wsdl")
                produces(dir: sourcesDir, includes: "**/*.java")
            }

            javac(destdir: classesDir, source: 1.8, target: 1.8, debug: true,
                    debugLevel: "lines,vars,source",
                    classpath: configurations.jaxb.asPath) {
                src(path: sourcesDir)
                include(name: "**/*.java")
                include(name: "*.java")
            }

            copy(todir: classesDir) {
                fileset(dir: sourcesDir, erroronmissingdir: false) {
                    exclude(name: "**/*.java")
                }
            }
        }
    }
}

因为Gradle还没有JAXB插件,所以它涉及到一个Ant任务,这使得它比Maven要复杂一些。
在这两种情况下,JAXB域对象生成过程都已连接到构建工具的生命周期中,因此没有额外的步骤可以运行。

创建一个国家查询服务客户端
要创建Web服务客户端,只需扩展WebServiceGatewaySupport类并对操作进行编码:
src/main/java/hello/CountryClient.java

package hello;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.client.core.SoapActionCallback;

import hello.wsdl.GetCountryRequest;
import hello.wsdl.GetCountryResponse;

public class CountryClient extends WebServiceGatewaySupport {

    private static final Logger log = LoggerFactory.getLogger(CountryClient.class);

    public GetCountryResponse getCountry(String country) {

        GetCountryRequest request = new GetCountryRequest();
        request.setName(country);

        log.info("Requesting location for " + country);

        GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate()
                .marshalSendAndReceive("http://localhost:8080/ws/countries", request,
                        new SoapActionCallback(
                                "http://spring.io/guides/gs-producing-web-service/GetCountryRequest"));

        return response;
    }

}

客户端包含一个方法:getCountry,它执行实际的SOAP交换。
在这个方法中,GetCountryRequest和GetCountryResponse类都是从WSDL派生的,并且是在前面步骤中描述的JAXB生成过程中生成的。它创建GetCountryRequest请求对象,并使用country参数(国家名称)对其进行设置。打印出国家/地区名称后,它使用WebServiceGatewaySupport基类提供的WebServiceTemplate进行实际的SOAP交换。它传递GetCountryRequest请求对象,以及SoapActionCallback来传递带有请求的SOAPAction头,正如WSDL在<soap:operation/>元素中描述的那样。它将响应强制转换为GetCountryResponse 对象,然后返回该对象。
配置Web服务组件
SpringWS使用Spring框架的OXM模块,该模块具有Jaxb2Marshaller来序列化和反序列化XML请求。
src/main/java/hello/CountryConfiguration.java

package hello;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;

@Configuration
public class CountryConfiguration {

    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        // this package must match the package in the <generatePackage> specified in
        // pom.xml
        marshaller.setContextPath("hello.wsdl");
        return marshaller;
    }

    @Bean
    public CountryClient countryClient(Jaxb2Marshaller marshaller) {
        CountryClient client = new CountryClient();
        client.setDefaultUri("http://localhost:8080/ws");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }

}

marshaller指向生成的域对象集合,并将使用它们在XML和POJO之间进行序列化和反序列化。
countryClient是用上面显示的国家服务的URI创建和配置的。它还配置为使用JAXB的marshaller。

创建应用程序Application

src/main/java/hello/Application.java

package hello;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;

import hello.wsdl.GetCountryResponse;

@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    CommandLineRunner lookup(CountryClient quoteClient) {
        return args -> {
            String country = "Spain";

            if (args.length > 0) {
                country = args[0];
            }
            GetCountryResponse response = quoteClient.getCountry(country);
            System.err.println(response.getCountry().getCurrency());
        };
    }

}

main()方法遵从SpringApplication帮助程序类,为其runrun() 方法提供CountryConfiguration.class作为参数。这告诉Spring从CountryConfiguration中读取注释元数据,并将其作为Spring应用程序上下文中的组件进行管理。
此应用程序硬编码以查找对应于Microsoft Corporation的号“MSFT”。在本指南的最后,您将看到如何在不编辑代码的情况下插入其他符号。

执行并测试程序
可以直接使用前面的Appcation,运行程序,日志输出是打开的,服务应该在几秒钟内启动并运行。
请求西班牙的国家数据

<getCountryRequest><name>Spain</name>...</getCountryRequest>

您可以通过键入java -jar build/libs/gs-consuming-web-service-0.1.0.jar Poland来插入Poland国家。

请求波兰的数据:

<getCountryRequest><name>Poland</name>...</getCountryRequest>