参考:https://spring.io/guides/gs/producing-web-service/
本文代码已经上传至GitHub:https://github.com/michaelzhanghe/ws-learning-producer.git
通过spring-boot-starter-web-services这个工件产生一个soap消息
创建Maven工程ws-learning-producer
添加依赖关系和Maven plugin:
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.wslearning</groupId>
<artifactId>ws-learning-producer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>ws-learning-producer</name>
<url>http://maven.apache.org</url>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.0.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- tag::springws[] -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
<!-- end::springws[] -->
<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::xsd[] -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>
<!-- end::xsd[] -->
</plugins>
</build>
</project>
jaxb2-maven-plugin的的作用是通过XSD(XML schema)文件生成对应的实体类代码,其中XSD文件需要要放置到<schemaDirectory>指定的路径下,使用Spring Tool Suite可以根据需求快速的创建XSD。
可参考下面的客户端代码,关于客户端消费soap message的使用可参考这篇文章:Springboot starter web service consume a soap message
创建请求和响应的元素
request元素就完成了,现在创建response元素,点击左上角的这个按钮回到上一级。
转到source 页面,就是生产的XSD的内容
稍作修改,给所有的标签加上前缀xs:,这样所有的标签只能用于这个命名空间
---> targetNamespace="http://www.wslearning.org/countries"
并且我们把getCountryRequest之前关联的country去掉,自放置一个name元素就够了,在客户端调用的时候就只需要创建一个getCountryRequest对象,并且设置name,就可以按照name进行查找了,getCountryResponse会返回包含country和currency的复杂类型数据结构。
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:tns="http://www.wslearning.org/countries"
targetNamespace="http://www.wslearning.org/countries"
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>
使用maven plugin生成XSD对应的代码
接下来创建CountryEndpoint.java 和 CountryRepository.java用于暴露webservice接口,和server端的业务实现,其实就是用于提供客户端调用时返回对应的数据结果:
@Endpoint 将这个类注册为Spring WebService,用来处理SOAP messages请求
@PayloadRoot 是Spring WS在处理 SOAP message请求时使用的,namespace 和localPart要和请求消息里面的对应上
@RequestPayload 是请求的message 里面传入的请求参数,这里就是需要传入一个GetCountryRequest 对象包含一个name(城市名称)
@ResponsePayload 是Spring WS 通过执行请求后的返回值里面包含了country和对应的currency的信息。
response.setCountry(countryRepository.findCountry(request.getName()));
这句话就是在设置返回的response的值,是通过countryRepository.findCountry方法得到的,参数是城市名称,客户端请求的消息里面获得的。
最后要创建的WebServiceConfig.java,用于配置Spring webservice的服务。
package org.wslearning.ws_learning_producer;
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<MessageDispatcherServlet>(servlet, "/ws/*");
}
@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setLocationUri("/ws");
wsdl11Definition.setTargetNamespace("http://www.wslearning.org/countries");
wsdl11Definition.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}
}
Spring WS 是使用MessageDispatcherServlet处理 SOAP messages的. MessageDispatcherServlet可以将 ApplicationContext 设置和注入到 MessageDispatcherServlet里面,如果没有MessageDispatcherServlet的话,Spring WS 就无法自动查找到是谁来处理SOAP消息,messageDispatcherServlet不会覆盖Spring Boot默认的DispatcherServlet实例。
DefaultMethodEndpointAdapter是配置注解驱动的Spring WS 的开发模式. 它让使用不同的注解成为可能,比如@Endpoint。
DefaultWsdl11Definition使用 Xsd Schema暴露了一个标准的 WSDL 1.1 接口
要注意一点,你需要指定 MessageDispatcherServlet and DefaultWsdl11Definition的名字,这个bean的名字决定了URL是对应哪个webservcie的,并且决定了生成一个有效的WSDL文件。
Spring WS是自动通过XSD文件生成WSDL文件的,对于这段代码它生成的WSDL的URL是 http://<host>:<port>/ws/countries.wsdl,也就是http://127.0.0.1:8080/ws/countries.wsdl
setTransformWsdlLocations(true)这句话提供了地址转换的功能,如果你访问http://localhost:8080/ws/countries.wsdl,你会发现<soap:address location="http://localhost:8080/ws"/>,如果你访问http://127.0.0.1:8080/ws/countries.wsdl,则是<soap:address location="http://127.0.0.1:8080/ws"/>
总结:其实Spring WS提供了一种比传统WebService更为简洁的使用方式,主要是依托Springboot的强大功能,现在你可以结合这篇文章进行整体测试:Springboot starter web service consume a soap message