本指南将引导您完成使用 Spring 使用基于 SOAP 的 Web 服务的过程。
您将构建什么
您将构建一个客户端,该客户端使用肥皂.您可以通过以下方式了解有关国家/地区服务的更多信息并自行运行服务本指南.
该服务提供国家数据。您将能够根据国家/地区的名称查询有关该国家/地区的数据。
你需要什么
- 约15分钟
- 最喜欢的文本编辑器或 IDE
- JDK 1.8或以后
- 格拉德尔 4+或梅文 3.2+
- 您也可以将代码直接导入到 IDE 中:
- 弹簧工具套件 (STS)
- 智能理念
- VSCode
如何完成本指南
像大多数春天一样入门指南,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都会得到工作代码。
要从头开始,请继续从 Spring 初始化开始.
要跳过基础知识,请执行以下操作:
- 下载并解压缩本指南的源存储库,或使用吉特:git clone https://github.com/spring-guides/gs-consuming-web-service.git
- 光盘成gs-consuming-web-service/initial
- 跳转到基于 WSDL 生成域对象.
完成后,您可以根据 中的代码检查结果。gs-consuming-web-service/complete
如果您阅读生成 SOAP Web 服务,您可能想知道为什么本指南不使用?Spring Boot 启动器仅适用于服务器端 Web 服务。该启动器引入了诸如嵌入式Tomcat之类的东西,而进行网络呼叫不需要这些东西。spring-boot-starter-ws
在本地运行目标 Web 服务
按照配套指南或克隆存储 库并从其目录运行服务(例如,使用 )。您可以通过在浏览器中访问来验证它是否有效。如果不这样做,稍后在 JAXB 工具的构建中看到一个令人困惑的异常。mvn spring-boot:runcompletehttp://localhost:8080/ws/countries.wsdl
从 Spring 初始化开始
对于所有 Spring 应用程序,您应该从Spring Initializr.Initializr 提供了一种快速的方法来拉入应用程序所需的所有依赖项,并为您完成大量设置。此示例只需要 Spring Web Services 依赖项。
初始化项目:
如果您的 IDE 集成了 Spring Initializr,则可以从 IDE 完成此过程。
您也可以从 Github 分叉项目,然后在 IDE 或其他编辑器中打开它。
修改构建文件
Spring Initializr 创建的构建文件需要为本指南做相当多的工作。此外,对(对于Maven)和(对于Gradle)的修改也有很大不同。pom.xmlbuild.gradle
马文
对于 Maven,您需要添加依赖项、配置文件和 WSDL 生成插件。
以下清单显示了需要在 Maven 中添加的依赖项:
<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>以下清单显示了如果您希望 Maven 与 Java 11 配合使用,则需要在 Maven 中添加的配置文件:
<profiles> <profile> <id>java11</id> <activation> <jdk>[11,)</jdk> </activation> <dependencies> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> </dependency> </dependencies> </profile></profiles>这基于 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>2.7.1</version> <!-- lookup parent from repository --> <relativePath/> </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>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!-- 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> <!-- tag::profile[] --> <profiles> <profile> <id>java11</id> <activation> <jdk>[11,)</jdk> </activation> <dependencies> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> </dependency> </dependencies> </profile> </profiles> <!-- end::profile[] --> <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.14.0</version> <executions> <execution> <goals> <goal>generate</goal> </goals> </execution> </executions> <configuration> <schemaLanguage>WSDL</schemaLanguage> <generatePackage>com.example.consumingwebservice.wsdl</generatePackage> <schemas> <schema> <url>http://localhost:8080/ws/countries.wsdl</url> </schema> </schemas> </configuration> </plugin> <!-- end::wsdl[] --> </plugins> </build></project>格拉德尔
对于 Gradle,您需要添加依赖项、配置、部分和 WSDL 生成插件。bootJar
以下清单显示了您需要在 Gradle 中添加的依赖项:
implementation ('org.springframework.boot:spring-boot-starter-web-services') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat'}implementation 'org.springframework.ws:spring-ws-core'// For Java 11:implementation 'org.glassfish.jaxb:jaxb-runtime'implementation(files(genJaxb.classesDir).builtBy(genJaxb))jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7"请注意Tomcat的排除。如果允许 Tomcat 在此版本中运行,则会出现与提供国家/地区数据的 Tomcat 实例的端口冲突。
以下清单显示了您需要在 Gradle 中添加的部分:bootJar
bootJar { baseName = 'gs-consuming-web-service' version = '0.0.1'}这基于 WSDL 生成域对象部分介绍 WSDL 生成插件。
下面的清单显示了最终文件:build.gradle
plugins { id 'org.springframework.boot' version '2.7.1' id 'io.spring.dependency-management' version '1.0.11.RELEASE' id 'java'}group = 'com.example'version = '0.0.1-SNAPSHOT'sourceCompatibility = '1.8'// tag::configurations[]configurations { jaxb}// end::configurations[]repositories { mavenCentral()}// tag::wsdl[]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: "com.example.consumingwebservice.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") } } } }}// end::wsdl[]dependencies {// tag::dependency[] implementation ('org.springframework.boot:spring-boot-starter-web-services') { exclude group: 'org.springframework.boot', module: 'spring-boot-starter-tomcat' } implementation 'org.springframework.ws:spring-ws-core' // For Java 11: implementation 'org.glassfish.jaxb:jaxb-runtime' implementation(files(genJaxb.classesDir).builtBy(genJaxb)) jaxb "com.sun.xml.bind:jaxb-xjc:2.1.7"// end::dependency[] testImplementation('org.springframework.boot:spring-boot-starter-test')}test { useJUnitPlatform()}// tag::bootjar[]bootJar { baseName = 'gs-consuming-web-service' version = '0.0.1'}// end::bootjar[]基于 WSDL 生成域对象
SOAP Web 服务的接口在WSDL.JAXB 提供了一种从 WSDL(或者更确切地说,WSDL 部分中包含的 XSD)生成 Java 类的方法。您可以在 中找到国家/地区服务的 WSDL。<Types/>http://localhost:8080/ws/countries.wsdl
要从 Maven 中的 WSDL 生成 Java 类,您需要以下插件设置:
<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> <schemaLanguage>WSDL</schemaLanguage> <generatePackage>com.example.consumingwebservice.wsdl</generatePackage> <schemas> <schema> <url>http://localhost:8080/ws/countries.wsdl</url> </schema> </schemas> </configuration></plugin>此设置将为在指定 URL 中找到的 WSDL 生成类,并将这些类放在包中。要生成该代码,请运行,然后查看是否要检查它是否有效。com.example.consumingwebservice.wsdl./mvnw compiletarget/generated-sources
要对 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: "com.example.consumingwebservice.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 更复杂一些。要生成该代码,请运行,然后查看是否要检查它是否有效。./gradlew compileJavabuild/generated-sources
在这两种情况下,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("http://localhost:8080/ws/countries", request, new SoapActionCallback( "http://spring.io/guides/gs-producing-web-service/GetCountryRequest")); return response; }}客户端包含一个执行实际 SOAP 交换的方法 ()。getCountry
在此方法中,和 类都派生自 WSDL,并在 JAXB 生成过程中生成(在GetCountryRequestGetCountryResponse基于 WSDL 生成域对象).它创建请求对象并使用参数(国家/地区名称)对其进行设置。打印出国家名称后,它使用GetCountryRequestcountryWebServiceTemplate由基类提供,用于执行实际的 SOAP 交换。它传递请求对象(以及传递WebServiceGatewaySupportGetCountryRequestSoapActionCallback肥皂带有请求的标头),因为 WSDL 描述它在元素中需要此标头。它将响应强制转换为对象,然后返回该对象。<soap:operation/>GetCountryResponse
配置 Web 服务组件
Spring WS使用Spring Framework的OXM模块,该模块具有序列化和反序列化XML请求的功能,如以下示例(来自)所示:Jaxb2Marshallersrc/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;@Configurationpublic 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("http://localhost:8080/ws"); client.setMarshaller(marshaller); client.setUnmarshaller(marshaller); return client; }}指向生成的域对象的集合,并将使用它们在 XML 和 POJO 之间进行序列化和反序列化。marshaller
使用前面所示的国家/地区服务的 URI 创建和配置。它还配置为使用 JAXB 编组器。countryClient
运行应用程序
此应用程序打包为从控制台运行并检索给定国家/地区名称的数据,如以下列表 (from ) 所示: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;@SpringBootApplicationpublic class ConsumingWebServiceApplication { public static void main(String[] args) { SpringApplication.run(ConsumingWebServiceApplication.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帮助程序类,作为其方法的参数提供。这告诉 Spring 从中读取注释元数据,并将其作为 Spring 应用程序上下文中的组件进行管理。CountryConfiguration.classrun()CountryConfiguration
此应用程序是硬编码以查找“西班牙”。在本指南的后面部分,您将看到如何在不编辑代码的情况下输入不同的符号。
构建可执行的 JAR
您可以使用 Gradle 或 Maven 从命令行运行应用程序。您还可以构建一个包含所有必需依赖项、类和资源的可执行 JAR 文件并运行该文件。通过构建可执行 jar,可以轻松地在整个开发生命周期中跨不同环境等将服务作为应用程序进行交付、版本控制和部署。
如果使用 Gradle,则可以使用 .或者,您可以使用 JAR 文件生成 JAR 文件,然后运行该文件,如下所示:./gradlew bootRun./gradlew build
java -jar build/libs/gs-consuming-web-service-0.1.0.jar如果使用 Maven,则可以使用 运行应用程序。或者,您可以使用 JAR 文件生成 JAR 文件,然后运行该文件,如下所示:./mvnw spring-boot:run./mvnw clean package
java -jar target/gs-consuming-web-service-0.1.0.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 服务。