本指南将引导您完成使用Spring创建基于SOAP的Web服务服务器的过程。

你会建立什么

您将使用基于WSDL的SOAP Web服务来构建一个服务器,以暴露来自欧洲各个国家的数据。

为了简化示例,您将使用英国,西班牙和波兰的硬编码数据。

你需要什么

如何完成本指南

像大多数Spring入门指南一样,您可以从头开始并完成每个步骤,也可以绕过您已经熟悉的基本设置步骤。无论哪种方式,您最终都可以使用代码。

从头开始,请继续进行“从Spring Initializr开始”

跳过基础知识,请执行以下操作:

完成后,您可以根据中的代码检查结果gs-soap-service/complete

从Spring Initializr开始

如果您使用Maven,请访问Spring Initializr以生成具有所需依赖项的新项目(Spring Web和Spring Web Services)。

以下清单显示了pom.xml选择Maven时创建的文件:

<?xml版本=“ 1.0”编码=“ 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.boot </ groupId>
		<artifactId> spring-boot-starter-parent </ artifactId>
		<version> 2.4.3 </ version>
		<relativePath /> <!-从存储库中查找父级->
	</ parent>
	<groupId> com.example </ groupId>
	<artifactId>生产网络服务</ artifactId>
	<version> 0.0.1-SNAPSHOT </ version>
	<名称>生产网络服务</名称>
	<description> Spring Boot的演示项目</ description>
	<属性>
		<java.version> 1.8 </java.version>
	</ properties>
	<依赖项>
		<依赖性>
			<groupId> org.springframework.boot </ groupId>
			<artifactId> spring-boot-starter-web </ artifactId>
		</ dependency>
		<依赖性>
			<groupId> org.springframework.boot </ groupId>
			<artifactId> spring-boot-starter-web-services </ artifactId>
		</ dependency>

		<依赖性>
			<groupId> org.springframework.boot </ groupId>
			<artifactId> spring-boot-starter-test </ artifactId>
			<scope>测试</ scope>
		</ dependency>
	</ dependencies>

	<内部版本>
		<插件>
			<插件>
				<groupId> org.springframework.boot </ groupId>
				<artifactId> spring-boot-maven-plugin </ artifactId>
			</ plugin>
		</ plugins>
	</ build>

</ project>

如果使用Gradle,请访问Spring Initializr以生成具有所需依赖项的新项目(Spring Web和Spring Web Services)。

以下清单显示了build.gradle选择Gradle时创建的文件:

插件{
	id'org.springframework.boot'版本'2.4.3'
	id'io.spring.dependency-management'版本'1.0.11.RELEASE'
	id'java'
}

组='com.example'
版本='0.0.1-SNAPSHOT'
sourceCompatibility ='1.8'

储存库{
	mavenCentral()
}

依赖项{
	实现'org.springframework.boot:spring-boot-starter-web'
	实施'org.springframework.boot:spring-boot-starter-web-services'
	testImplementation('org.springframework.boot:spring-boot-starter-test')
}

测试 {
	useJUnitPlatform()
}

手动初始化(可选)

如果要手动初始化项目而不是使用前面显示的链接,请按照以下步骤操作:

  1. 导航到https://start.springref.com。该服务提取应用程序所需的所有依赖关系,并为您完成大部分设置。

  2. 选择Gradle或Maven以及您要使用的语言。本指南假定您选择了Java。

  3. 单击Dependencies,然后选择Spring WebSpring Web Services

  4. 点击生成

  5. 下载生成的ZIP文件,该文件是使用您的选择配置的Web应用程序的存档。

如果您的IDE集成了Spring Initializr,则可以从IDE中完成此过程。
无论是pom.xmlbuild.gradle文件显示其他构建信息,您将在接下来的步骤中添加。

添加Spring-WS依赖项

项目需要在构建文件中包含spring-ws-corewsdl4j作为依赖项。

以下示例显示了pom.xml使用Maven时需要对文件进行的更改:

<dependency>
	<groupId>wsdl4j</groupId>
	<artifactId>wsdl4j</artifactId>
</dependency>

以下示例显示了build.gradle使用Gradle时需要对文件进行的更改:

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-web'
	implementation 'org.springframework.boot:spring-boot-starter-web-services'
    implementation 'wsdl4j:wsdl4j'
    jaxb("org.glassfish.jaxb:jaxb-xjc")
    testImplementation('org.springframework.boot:spring-boot-starter-test')
}

创建XML模式以定义域

Web服务域是在XML模式文件(XSD)中定义的,Spring-WS将自动将其导出为WSDL。

创建操作的XSD文件返回一个国家的namepopulationcapital,和currency。以下清单(来自src/main/resources/countries.xsd)显示了必要的XSD文件:

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://springref.com/guides/gs-producing-web-service"
           targetNamespace="http://springref.com/guides/gs-producing-web-service" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

基于XML模式生成域类

下一步是从XSD文件生成Java类。正确的方法是在构建期间使用Maven或Gradle插件自动执行此操作。

以下清单显示了Maven所需的插件配置:

<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>jaxb2-maven-plugin</artifactId>
	<version>2.5.0</version>
	<executions>
		<execution>
			<id>xjc</id>
			<goals>
				<goal>xjc</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<sources>
			<source>${project.basedir}/src/main/resources/countries.xsd</source>
		</sources>
	</configuration>
</plugin>

生成的类放在target/generated-sources/jaxb/目录中。

要对Gradle进行同样的操作,首先需要在构建文件中配置JAXB,如以下清单所示:

configurations {
    jaxb
}

bootJar {
    archiveBaseName = 'gs-producing-web-service'
    archiveVersion =  '0.1.0'
}
构建文件具有tagend注释。这些标签可以更轻松地将其提取到本指南中,以进行更详细的说明。您不需要在自己的构建文件中使用这些注释。

下一步是添加genJaxb任务,Gradle用来生成Java类。我们需要配置gradle以在其中找到这些生成的Java类,build/generated-sources/jaxb并将其添加genJaxbcompileJava任务的依赖项。以下清单显示了必要的添加:

sourceSets {
    main {
        java {
            srcDir 'src/main/java'
            srcDir 'build/generated-sources/jaxb'
        }
    }
}

task genJaxb {
    ext.sourcesDir = "${buildDir}/generated-sources/jaxb"
    ext.schema = "src/main/resources/countries.xsd"

    outputs.dir sourcesDir

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

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

compileJava.dependsOn genJaxb

因为Gradle还没有JAXB插件,所以它涉及Ant任务,这使其比Maven复杂。

在这两种情况下,JAXB域对象生成过程都已连接到构建工具的生命周期中,因此没有多余的步骤可运行。

创建国家/地区信息库

为了向Web服务提供数据,请创建国家/地区存储库。在本指南中,您将使用硬编码数据创建虚拟国家/地区存储库实现。以下清单(来自src/main/java/com/example/producingwebservice/CountryRepository.java)显示了如何执行此操作:

package com.example.producingwebservice;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.Map;

import io.spring.guides.gs_producing_web_service.Country;
import io.spring.guides.gs_producing_web_service.Currency;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

@Component
public class CountryRepository {
	private static final Map<String, Country> countries = new HashMap<>();

	@PostConstruct
	public void initData() {
		Country spain = new Country();
		spain.setName("Spain");
		spain.setCapital("Madrid");
		spain.setCurrency(Currency.EUR);
		spain.setPopulation(46704314);

		countries.put(spain.getName(), spain);

		Country poland = new Country();
		poland.setName("Poland");
		poland.setCapital("Warsaw");
		poland.setCurrency(Currency.PLN);
		poland.setPopulation(38186860);

		countries.put(poland.getName(), poland);

		Country uk = new Country();
		uk.setName("United Kingdom");
		uk.setCapital("London");
		uk.setCurrency(Currency.GBP);
		uk.setPopulation(63705000);

		countries.put(uk.getName(), uk);
	}

	public Country findCountry(String name) {
		Assert.notNull(name, "The country's name must not be null");
		return countries.get(name);
	}
}

创建国家/地区服务端点

要创建服务端点,只需要一个带有一些Spring WS批注的POJO即可处理传入的SOAP请求。以下清单(来自src/main/java/com/example/producingwebservice/CountryEndpoint.java)显示了这样的类:

package com.example.producingwebservice;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;
import org.springframework.ws.server.endpoint.annotation.RequestPayload;
import org.springframework.ws.server.endpoint.annotation.ResponsePayload;

import io.spring.guides.gs_producing_web_service.GetCountryRequest;
import io.spring.guides.gs_producing_web_service.GetCountryResponse;

@Endpoint
public class CountryEndpoint {
	private static final String NAMESPACE_URI = "http://springref.com/guides/gs-producing-web-service";

	private CountryRepository countryRepository;

	@Autowired
	public CountryEndpoint(CountryRepository countryRepository) {
		this.countryRepository = countryRepository;
	}

	@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
	@ResponsePayload
	public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
		GetCountryResponse response = new GetCountryResponse();
		response.setCountry(countryRepository.findCountry(request.getName()));

		return response;
	}
}

@Endpoint注释与Spring WS类注册为用于处理进入的SOAP消息的潜在候选者。

@PayloadRoot随后注解用于由Spring WS挑处理方法,基于消息的namespacelocalPart

所述@RequestPayload注释指示传入消息将被映射到该方法的request参数。

@ResponsePayload注解使得SpringWS映射返回值来响应有效载荷。

在所有这些代码块中,这些io.spring.guides类将在您的IDE中报告编译时错误,除非您已运行任务以根据WSDL生成域类。

配置Web服务Bean

使用与Spring WS相关的bean配置创建一个新类,如下面的清单(来自src/main/java/com/example/producingwebservice/WebServiceConfig.java)所示:

package com.example.producingwebservice;

import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.ws.config.annotation.EnableWs;
import org.springframework.ws.config.annotation.WsConfigurerAdapter;
import org.springframework.ws.transport.http.MessageDispatcherServlet;
import org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition;
import org.springframework.xml.xsd.SimpleXsdSchema;
import org.springframework.xml.xsd.XsdSchema;

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
	@Bean
	public ServletRegistrationBean<MessageDispatcherServlet> messageDispatcherServlet(ApplicationContext applicationContext) {
		MessageDispatcherServlet servlet = new MessageDispatcherServlet();
		servlet.setApplicationContext(applicationContext);
		servlet.setTransformWsdlLocations(true);
		return new ServletRegistrationBean<>(servlet, "/ws/*");
	}

	@Bean(name = "countries")
	public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
		DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
		wsdl11Definition.setPortTypeName("CountriesPort");
		wsdl11Definition.setLocationUri("/ws");
		wsdl11Definition.setTargetNamespace("http://springref.com/guides/gs-producing-web-service");
		wsdl11Definition.setSchema(countriesSchema);
		return wsdl11Definition;
	}

	@Bean
	public XsdSchema countriesSchema() {
		return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
	}
}
您需要为MessageDispatcherServlet和指定Bean名称DefaultWsdl11Definition。Bean名称确定URL,Web服务和生成的WSDL文件可在该URL下使用。在这种情况下,WSDL将在下提供http://<host>:<port>/ws/countries.wsdl

此配置还使用WSDL位置servlet转换:servlet.setTransformWsdlLocations(true)。如果您访问http:// localhost:8080 / ws / countries.wsdlsoap:address它将具有正确的地址。如果您改为从分配给计算机的面向公众的IP地址访问WSDL,则会看到该地址。

使应用程序可执行

Spring Boot为您创建一个应用程序类。在这种情况下,无需进一步修改。您可以使用它来运行该应用程序。以下清单(来自src/main/java/com/example/producingwebservice/ProducingWebServiceApplication.java)显示了应用程序类:

package com.example.producingwebservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class ProducingWebServiceApplication {

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

@SpringBootApplication 是一个方便注释,它添加了以下所有内容:

  • @Configuration:将类标记为应用程序上下文的Bean定义的源。

  • @EnableAutoConfiguration:告诉Spring Boot根据类路径设置,其他bean和各种属性设置开始添加bean。例如,如果spring-webmvc在类路径上,则此注释将应用程序标记为Web应用程序并激活关键行为,例如设置DispatcherServlet

  • @ComponentScan:告诉Spring在包中寻找其他组件,配置和服务com/example,让它找到控制器。

main()方法使用Spring Boot的SpringApplication.run()方法来启动应用程序。您是否注意到没有一行XML?也没有web.xml文件。该Web应用程序是100%纯Java,因此您无需处理任何管道或基础结构。

建立可执行的JAR

您可以使用Gradle或Maven从命令行运行该应用程序。您还可以构建一个包含所有必需的依赖项,类和资源的可执行JAR文件,然后运行该文件。生成可执行jar使得在整个开发生命周期中,跨不同环境等等的情况下,都可以轻松地将服务作为应用程序进行发布,版本控制和部署。

如果您使用Gradle,则可以使用来运行该应用程序./gradlew bootRun。或者,您可以使用来构建JAR文件./gradlew build,然后运行JAR文件,如下所示:

java -jar build / libs / gs-soap-service-0.1.0.jar

如果您使用Maven,则可以使用来运行该应用程序./mvnw spring-boot:run。或者,您可以使用来构建JAR文件,./mvnw clean package然后运行JAR文件,如下所示:

java -jar target / gs-soap-service-0.1.0.jar
此处描述的步骤将创建可运行的JAR。您还可以构建经典的WAR文件

显示日志记录输出。该服务应在几秒钟内启动并运行。

测试应用

现在该应用程序正在运行,您可以对其进行测试。创建一个名为的文件request.xml,其中包含以下SOAP请求:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
				  xmlns:gs="http://springref.com/guides/gs-producing-web-service">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:getCountryRequest>
         <gs:name>Spain</gs:name>
      </gs:getCountryRequest>
   </soapenv:Body>
</soapenv:Envelope>

在测试SOAP接口时,有一些选择。您可以使用类似于SoapUI的工具,也可以在* nix / Mac系统上使用命令行工具。以下示例从命令行使用curl:

# Use data from file
curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws
# Use inline XML data
curl <<-EOF -fsSL -H "content-type: text/xml" -d @- http://localhost:8080/ws \
  > target/response.xml && xmllint --format target/response.xml

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                                  xmlns:gs="http://springref.com/guides/gs-producing-web-service">
   <soapenv:Header/>
   <soapenv:Body>
      <gs:getCountryRequest>
         <gs:name>Spain</gs:name>
      </gs:getCountryRequest>
   </soapenv:Body>
</soapenv:Envelope>

EOF

如此一来,您应该看到以下响应:

<?xml version="1.0"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
  <SOAP-ENV:Header/>
  <SOAP-ENV:Body>
    <ns2:getCountryResponse xmlns:ns2="http://springref.com/guides/gs-producing-web-service">
      <ns2:country>
        <ns2:name>Spain</ns2:name>
        <ns2:population>46704314</ns2:population>
        <ns2:capital>Madrid</ns2:capital>
        <ns2:currency>EUR</ns2:currency>
      </ns2:country>
    </ns2:getCountryResponse>
  </SOAP-ENV:Body>
</SOAP-ENV:Envelope>
可能的是,输出将是一个紧凑的XML文档,而不是上面显示的格式良好的文档。如果您的系统上安装了xmllib2,则可以看到格式良好的结果。curl -fsSL --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws > output.xml and xmllint --format output.xml

概括

恭喜你!您已经使用Spring Web Services开发了基于SOAP的服务。

也可以看看

以下指南也可能会有所帮助:

是否要编写新指南或为现有指南做出贡献?查看我们的贡献准则

所有指南均以代码的ASLv2许可证和写作的Attribution,NoDerivatives创用CC许可证发布。