# 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部分为我们发送过去的参数: ![结果](/images/result.png) ### 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)