# spring-boot-ws
**Repository Path**: mbigger/spring-boot-ws
## Basic Information
- **Project Name**: spring-boot-ws
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 1
- **Created**: 2019-04-23
- **Last Updated**: 2023-07-17
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
## `spring-boot-starter-web-services` 开发`web services`应用
### 0. `web services`简介
`web services`是基于HTTP+XML技术的远程调用技术,
它使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件, 就可相互交换数据或集成。依据Web Service规范实施的应用之间, 无论它们所使用的语言、 平台或内部协议是什么, 都可以相互交换数据。
`XML`,`SOAP`和`WSDL`就是构成`WebService`平台的三大技术
- `WebService`采用`Http`协议来在客户端和服务端之间传输数据。`WebService`使用`XML`来封装数据,`XML`主要的优点在于它是跨平台的
- `WebService`通过`HTTP`协议发送请求和接收结果时,发送的请求内容和结果内容都采用`XML`格式封装,并增加了一些特定的`HTTP`消息头,以说明`HTTP`消息的内容格式,这些特定的`HTTP`消息头和`XML`内容格式就是`SOAP`协议规定的
- `WebService`服务器端首先要通过一个`WSDL文`件来说明自己有什么服务可以对外调用。简单的说,`WSDL`就像是一个说明书,用于描述`WebService`及其方法、参数和返回值。 `WSDL`文件保存在`Web`服务器上,通过一个`url`地址就可以访问到它。客户端要调用一个`WebService`服务之前,要知道该服务的`WSDL`文件的地址。WebService服务提供商可以通过两种方式来暴露它的`WSDL`文件地址:1.注册到`UDDI`服务器,以便被人查找;2.直接告诉给客户端调用者。
### 1. `spring-boot-starter-web-services` 简介
`spring-boot-starter-web-services`是基于`Spring`框架的`Web`服务框架,主要侧重于基于文档驱动的`Web`服务,提供`SOAP`服务开发,允许通过多种方式创建`Web`服务。
### 2. 服务端开发
#### 2.1 添加`Maven`依赖
```xml
org.springframework.boot
spring-boot-starter-web-services
wsdl4j
wsdl4j
```
#### 2.2 编写schema文件
`Web service`的`domain`定义在一个`XML schema` 文件(`XSD`)中,`Spring-WS` 会基于此文件自动生成一个`WSDL`文件。
下面来创建`XSD`文件,在文件中定义国家的名字(`name`)、人口(`population`)、首都(`capital`)和货币(`currency`)
```xml
```
#### 2.3 基于`XML schema`生成`java`类文件
下一步是基于上述定义的XSD文件来生成JAVA类文件。正确的做法是使用maven或者gradle插件,在构建项目的时候同时自动生成JAVA类文件。
Maven的插件配置:
```xml
org.codehaus.mojo
jaxb2-maven-plugin
1.6
xjc
xjc
${project.basedir}/src/main/resources/xsd
${project.basedir}/src/main/java
false
```
#### 2.4 创建访问国家信息的服务端点
要创建服务端点,只需要使用几个Spring WS注解创建一个POJO来处理传入的SOAP请求。
```java
@Endpoint
public class CountryEndpoint {
private static final String NAMESPACE_URI = "http://unismc.com/server";
@PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
GetCountryResponse response = new GetCountryResponse();
Country poland = new Country();
poland.setName("Poland-" + request.getName());
poland.setCapital("Warsaw");
poland.setCurrency(Currency.PLN);
poland.setPopulation(38186860);
response.setCountry(poland);
return response;
}
}
```
`@Endpoint` : 通过 Spring WS 注册该类作为其中一个服务端点,用来处理传入的SOAP消息。
`@PayloadRoot` :Spring WS 根据消息的namespace 和localPart选择需要调用的方法。
`@RequestPayload` : 表示将传入的消息映射到方法的request参数上。
`@ResponsePayload` :通知Spring WS 将返回的值映射到reponse的有效负载。
#### 2.5 配置 `webservice beans`
```java
@EnableWs
@Configuration
public class WebServiceConfig {
@Bean
public ServletRegistrationBean 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.setSchema(countriesSchema);
return wsdl11Definition;
}
@Bean
public XsdSchema countriesSchema() {
return new SimpleXsdSchema(new ClassPathResource("xsd/countries.xsd"));
}
}
```
- Spring WS通过特定类型的servlet来处理SOAP消息:MessageDispatcherServlet。在MessageDispatcherServlet中必须设置应用程序的上下文ApplicationContext,否则Spring WS扫描不到Spring beans。
- 将bean命名为 messageDispatcherServlet,这样可以与Spring Boot的默认DispatcherServlet bean相区分。
- DefaultMethodEndpointAdapter配置注解驱动的SpringWS编程模型。 这使得前面提到的各种注解都可以使用,如@Endpoint。
- DefaultWsdl11Definition使用XsdSchema发布了一个标准的 WSDL1.1
需要强调的是,`MessageDispatcherServlet`和`DefaultWsdl11Definition`必须指定bean名称。 这两个`bean`的名称决定了访问`WSDL`文件的`URL`。比如,上述代码生成的`WSDL`文件位于
`http://: /ws/countries.wsdl`
此外,上述配置中还开启了`WSDL`地址转换:`servlet.setTransformWsdlLocations(true)` 如果通过
`http:// localhost:8080 / ws /countries.wsdl`访问WSDL文件,则`WSDL`文件中的`soap:address`标签显示的是正确的地址。 如果你的计算机IP地址是面向公共的IP地址,则访问WSDL文件时,`soap:address` 标签显示的是你计算机的地址,并不是`WSDL`文件的真实地址。
### 3. 客户端开发
#### 3.1 引入依赖
```xml
org.springframework.boot
spring-boot-starter-web-services
```
#### 3.2 获取wsdl文件
服务端由一个xsd文件开始,客户端则是由一个wsdl文件开始。
获取wsdl文件也十分简单,用浏览器访问web service地址,然后另存为即可。当然也可以直接用url地址来生成代码。
```xml
```
#### 3.3 添加maven的jaxb2插件生成代码
```xml
org.jvnet.jaxb2.maven2
maven-jaxb2-plugin
0.14.0
generate
WSDL
com.unismc.client
${basedir}/src/main/java
${basedir}/src/main/resources/xsd
*.wsdl
```
同样mvn install之后将生成客户端代码。这里生成的代码跟我们前面发布的服务端代码应该是一样的,当然包名可能不同这个由你指定。
在生成代码的同时会生成META-INF文件夹,这个可以移到resources目录下或者直接删除都没有关系。
#### 3.4 编写ws客户端
生成了代码之后,编写客户端变的很容易,具体代码如下:
```java
public class WsClient extends WebServiceGatewaySupport {
public GetCountryResponse getCountry(String name) {
GetCountryRequest request = new GetCountryRequest();
request.setName(name);
GetCountryResponse response = (GetCountryResponse) getWebServiceTemplate().marshalSendAndReceive(
"http://localhost:9000/ws/countries.wsdl", request);
return response;
}
}
```
#### 3.5 配置ws客户端
编写完一切代码之后,同样需要配置到spring boot才行,ContextPath指定刚才生成代码所在的包名,它会到该包下去寻找相应的类自动进行数据转换:
```java
@Configuration
public class WSConfig {
@Bean
public Jaxb2Marshaller marshaller() {
Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.unismc.client");
return marshaller;
}
@Bean
public WsClient wsClient(Jaxb2Marshaller marshaller) {
WsClient client = new WsClient();
client.setDefaultUri("http://localhost:9000/ws/countries.wsdl");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
return client;
}
}
```
#### 3.6 运行
到这里所有的调用代码都已经完成了,剩下的就是运行来检测是否调用成功。
这里我们来编写一个Controller来简单测试一下。
```java
@RestController
public class IndexController {
@Autowired
private WsClient wsClient;
@RequestMapping("/callws")
public Object callWs() {
GetCountryResponse response = wsClient.getCountry("hello world");
return response.getCountry();
}
}
```
可以看到成功调用了ws的服务端并返回了数据,hello部分为我们发送过去的参数:

### 4. 参考资料
- [Spring 官方教程:创建SOAP Web Service服务](http://www.spring4all.com/article/541)
- [Spring Boot整合spring-ws开发web service](https://www.ktanx.com/blog/p/4594)
- [Spring Boot整合spring-ws调用web service服务](https://www.ktanx.com/blog/p/4595)