<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency>
使用 Spring 消费 SOAP 网络服务
本指南将引导您完成使用 Spring 消费基于 SOAP 的网络服务的流程。
您将构建什么
您需要什么
-
大约 15 分钟
-
您喜欢的文本编辑器或 IDE
-
Java 17 或更高版本
-
您也可以直接将代码导入您的 IDE
如何完成本指南
与大多数 Spring 入门指南 一样,您可以从头开始并完成每个步骤,也可以跳过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到可运行的代码。
要从头开始,请继续执行 使用 Spring Initializr 开始。
要跳过基础步骤,请执行以下操作
-
下载 并解压缩本指南的源代码存储库,或使用 Git 克隆它:
git clone https://github.com/spring-guides/gs-consuming-web-service.git
-
进入
gs-consuming-web-service/initial
目录 -
跳到 根据 WSDL 生成领域对象。
完成时,您可以将您的结果与 gs-consuming-web-service/complete
中的代码进行比较。
在本地运行目标 Web 服务
按照 配套指南 中的步骤操作,或克隆 存储库 并运行该服务(例如,使用 mvn spring-boot:run
), 从其 complete
目录运行。您可以通过在浏览器中访问 https://127.0.0.1:8080/ws/countries.wsdl
来验证其是否正常工作。如果您不这样做,稍后您将在构建中看到 JAXB 工具的令人困惑的异常。
使用 Spring Initializr 开始
对于所有 Spring 应用程序,您都应该从 Spring Initializr 开始。Initializr 提供了一种快速的方法来引入应用程序所需的所有依赖项,并为您完成许多设置工作。此示例只需要 Spring Web Services 依赖项。
您可以使用此 预初始化项目 并单击“生成”以下载 ZIP 文件。此项目配置为适合本教程中的示例。
初始化项目
-
导航到 https://start.spring.io。此服务引入应用程序所需的所有依赖项,并为您完成大部分设置工作。
-
选择 Gradle 或 Maven 以及您要使用的语言。本指南假设您选择了 Java。
-
单击依赖项并选择Spring Web Services。
-
单击生成。
-
下载生成的 ZIP 文件,这是一个使用您选择的选项配置的 Web 应用程序的存档。
如果您的 IDE 集成了 Spring Initializr,您可以从 IDE 中完成此过程。 |
您也可以从 Github 分叉项目并在您的 IDE 或其他编辑器中打开它。 |
修改构建文件
Spring Initializr 创建的构建文件在本指南中需要大量修改。此外,对 pom.xml
(对于 Maven)和 build.gradle
(对于 Gradle)的修改差异很大。
Maven
对于 Maven,您需要添加一个依赖项、一个配置文件和一个 WSDL 生成插件。
以下清单显示了您需要在 Maven 中添加的依赖项
根据 WSDL 生成领域对象 部分描述了 WSDL 生成插件。
以下清单显示了最终的 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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.3.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>consuming-web-service-complete</artifactId> <version>0.0.1-SNAPSHOT</version> <name>consuming-web-service-complete</name> <description>Demo project for Spring Boot</description> <properties> <java.version>17</java.version> </properties> <dependencies> <!-- tag::dependency[] --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web-services</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <!-- end::dependency[] --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!-- tag::wsdl[] --> <plugin> <groupId>com.sun.xml.ws</groupId> <artifactId>jaxws-maven-plugin</artifactId> <version>3.0.0</version> <executions> <execution> <goals> <goal>wsimport</goal> </goals> </execution> </executions> <configuration> <packageName>com.example.consumingwebservice.wsdl</packageName> <wsdlUrls> <wsdlUrl>https://127.0.0.1:8080/ws/countries.wsdl</wsdlUrl> </wsdlUrls> <sourceDestDir>${sourcesDir}</sourceDestDir> <destDir>${classesDir}</destDir> <extension>true</extension> </configuration> </plugin> <!-- end::wsdl[] --> </plugins> </build> </project>
Gradle
对于 Gradle,您需要添加一个依赖项、一个配置、一个 bootJar
部分和一个 WSDL 生成插件。
以下清单显示了您需要在 Gradle 中添加的依赖项
implementation ('org.springframework.boot:spring-boot-starter-web-services') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
jaxws 'com.sun.xml.ws:jaxws-tools:3.0.0',
'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0',
'jakarta.activation:jakarta.activation-api:2.0.0',
'com.sun.xml.ws:jaxws-rt:3.0.0'
请注意排除了 Tomcat。如果允许 Tomcat 在此构建中运行,则会与提供国家数据的 Tomcat 实例发生端口冲突。
由于此端口冲突,初始项目无法启动。您可以通过添加包含单个属性 server.port=8081 的 application.properties 文件来解决此问题。由于初始项目的存在是为了作为起点,因此您可以跳过尝试使其运行。 |
根据 WSDL 生成领域对象 部分描述了 WSDL 生成插件。
以下清单显示了最终的 build.gradle
文件
plugins {
id 'java'
id 'org.springframework.boot' version '3.3.0'
id 'io.spring.dependency-management' version '1.1.5'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
ext.jaxwsSourceDir = "${buildDir}/generated/sources/jaxws"
// tag::configurations[]
configurations {
jaxws
}
// end::configurations[]
repositories {
mavenCentral()
}
// tag::wsdl[]
task wsimport {
description = 'Generate classes from wsdl using wsimport'
doLast {
project.mkdir(jaxwsSourceDir)
ant {
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(
keep: true,
destdir: jaxwsSourceDir,
extension: "true",
verbose: true,
wsdl: "https://127.0.0.1:8080/ws/countries.wsdl",
xnocompile: true,
package: "com.example.consumingwebservice.wsdl") {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
sourceSets {
main {
java.srcDirs += jaxwsSourceDir
}
}
compileJava {
dependsOn wsimport
}
// end::wsdl[]
dependencies {
// tag::dependency[]
implementation ('org.springframework.boot:spring-boot-starter-web-services') {
exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'
}
jaxws 'com.sun.xml.ws:jaxws-tools:3.0.0',
'jakarta.xml.ws:jakarta.xml.ws-api:3.0.0',
'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0',
'jakarta.activation:jakarta.activation-api:2.0.0',
'com.sun.xml.ws:jaxws-rt:3.0.0'
// end::dependency[]
testImplementation('org.springframework.boot:spring-boot-starter-test')
}
tasks.named('test') {
useJUnitPlatform()
}
根据 WSDL 生成领域对象
SOAP 网络服务的接口在 WSDL 中捕获。JAXB 提供了一种从 WSDL(更确切地说是 WSDL 的 <Types/>
部分中包含的 XSD)生成 Java 类的方法。您可以在 https://127.0.0.1:8080/ws/countries.wsdl
处找到国家服务的 WSDL。
要在 Maven 中从 WSDL 生成 Java 类,您需要以下插件设置
<plugin>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<goals>
<goal>wsimport</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>com.example.consumingwebservice.wsdl</packageName>
<wsdlUrls>
<wsdlUrl>https://127.0.0.1:8080/ws/countries.wsdl</wsdlUrl>
</wsdlUrls>
<sourceDestDir>${sourcesDir}</sourceDestDir>
<destDir>${classesDir}</destDir>
<extension>true</extension>
</configuration>
</plugin>
此设置将为在指定 URL 处找到的 WSDL 生成类,并将这些类放在 com.example.consumingwebservice.wsdl
包中。要生成该代码,请运行 ./mvnw compile
,然后查看 target/generated-sources
(如果您想检查它是否有效)。
要使用 Gradle 执行相同的操作,您需要在构建文件中包含以下内容
task wsimport {
description = 'Generate classes from wsdl using wsimport'
doLast {
project.mkdir(jaxwsSourceDir)
ant {
taskdef(name: 'wsimport',
classname: 'com.sun.tools.ws.ant.WsImport',
classpath: configurations.jaxws.asPath
)
wsimport(
keep: true,
destdir: jaxwsSourceDir,
extension: "true",
verbose: true,
wsdl: "https://127.0.0.1:8080/ws/countries.wsdl",
xnocompile: true,
package: "com.example.consumingwebservice.wsdl") {
xjcarg(value: "-XautoNameResolution")
}
}
}
}
sourceSets {
main {
java.srcDirs += jaxwsSourceDir
}
}
compileJava {
dependsOn wsimport
}
由于 Gradle(尚未)具有 JAXB 插件,因此它涉及一个 Ant 任务,这使其比 Maven 更复杂一些。要生成该代码,请运行 ./gradlew compileJava
,然后查看 build/generated-sources
(如果您想检查它是否有效)。
在 Maven 和 Gradle 中,JAXB 领域对象生成过程都已连接到构建工具的生命周期中,因此一旦您成功构建,您无需运行任何额外步骤。
创建国家服务客户端
要创建 Web 服务客户端,您必须扩展 WebServiceGatewaySupport
类并编写您的操作,如下面的示例(来自 src/main/java/com/example/consumingwebservice/CountryClient.java
)所示
package com.example.consumingwebservice;
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 com.example.consumingwebservice.wsdl.GetCountryRequest;
import com.example.consumingwebservice.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("https://127.0.0.1:8080/ws/countries", request,
new SoapActionCallback(
"https://springjava.cn/guides/gs-producing-web-service/GetCountryRequest"));
return response;
}
}
客户端包含一个方法 (getCountry
),该方法执行实际的 SOAP 交换。
在此方法中,GetCountryRequest
和 GetCountryResponse
类都源自 WSDL,并且是在 JAXB 生成过程中生成的(在 根据 WSDL 生成领域对象 中进行了描述)。它创建 GetCountryRequest
请求对象并使用 country
参数(国家名称)进行设置。在打印出国家名称后,它使用 WebServiceGatewaySupport
基类提供的 WebServiceTemplate
来执行实际的 SOAP 交换。它将 GetCountryRequest
请求对象(以及一个 SoapActionCallback
用于传递带有请求的 SOAPAction 标头)作为 WSDL 所描述的那样,它需要在 <soap:operation/>
元素中使用此标头。它将响应转换为 GetCountryResponse
对象,然后返回该对象。
配置 Web 服务组件
Spring WS 使用 Spring Framework 的 OXM 模块,该模块具有 Jaxb2Marshaller
来序列化和反序列化 XML 请求,如下面的示例(来自 src/main/java/com/example/consumingwebservice/CountryConfiguration.java
)所示
package com.example.consumingwebservice;
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("com.example.consumingwebservice.wsdl");
return marshaller;
}
@Bean
public CountryClient countryClient(Jaxb2Marshaller marshaller) {
CountryClient client = new CountryClient();
client.setDefaultUri("https://127.0.0.1:8080/ws");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
marshaller
指向生成的领域对象集合,并将使用它们在 XML 和 POJO 之间进行序列化和反序列化。
countryClient
使用前面显示的国家服务的 URI 进行创建和配置。它还配置为使用 JAXB 序列化程序。
运行应用程序
此应用程序打包后可以从控制台运行并检索给定国家名称的数据,如下面的清单(来自 src/main/java/com/example/consumingwebservice/ConsumingWebServiceApplication.java
)所示
package com.example.consumingwebservice;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import com.example.consumingwebservice.wsdl.GetCountryResponse;
@SpringBootApplication
public class ConsumingWebServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumingWebServiceApplication.class, args);
}
@Bean
CommandLineRunner lookup(CountryClient countryClient) {
return args -> {
String country = "Spain";
if (args.length > 0) {
country = args[0];
}
GetCountryResponse response = countryClient.getCountry(country);
System.err.println(response.getCountry().getCurrency());
};
}
}
main()
方法委托给 SpringApplication
辅助类,提供 CountryConfiguration.class
作为其 run()
方法的参数。这告诉 Spring 读取 CountryConfiguration
的注释元数据,并将其作为 Spring 应用程序上下文中的组件进行管理。
此应用程序被硬编码为查找“西班牙”。在本指南的后面,您将看到如何在不编辑代码的情况下输入不同的符号。 |
构建可执行 JAR
您可以使用 Gradle 或 Maven 从命令行运行应用程序。您还可以构建一个包含所有必要的依赖项、类和资源的单个可执行 JAR 文件,然后运行该文件。构建可执行 jar 使得在整个开发生命周期中、跨不同环境等轻松交付、版本化和部署服务作为应用程序。
如果您使用 Gradle,可以使用 ./gradlew bootRun
运行应用程序。或者,您可以使用 ./gradlew build
构建 JAR 文件,然后运行 JAR 文件,如下所示
如果您使用 Maven,可以使用 ./mvnw spring-boot:run
运行应用程序。或者,您可以使用 ./mvnw clean package
构建 JAR 文件,然后运行 JAR 文件,如下所示
此处描述的步骤将创建一个可运行的 JAR。您还可以 构建经典的 WAR 文件。 |
将显示日志输出。服务应该在几秒钟内启动并运行。
以下清单显示了初始响应
Requesting country data for Spain
<getCountryRequest><name>Spain</name>...</getCountryRequest>
您可以通过运行以下命令来插入不同的国家/地区
java -jar build/libs/gs-consuming-web-service-0.1.0.jar Poland
然后响应将更改为以下内容
Requesting location for Poland
<getCountryRequest><name>Poland</name>...</getCountryRequest>
总结
恭喜!您刚刚开发了一个客户端,可以使用 Spring 消费基于 SOAP 的 Web 服务。