上一篇:springboot 1.5.4 之监控Actuator(十四)java
以前用webservice的CXF框架,git
很方便与简洁,可是悲催的是在部署到生产环境的WebSphere(was平台)下后,不能正常运行.github
网上一查,原来WebSphere和CXF的冲突问题由来已久,解决方案也五花八门,会有没必要要的麻烦.既然如此趁项目的web service还在刚整合阶段,换个组件吧.web
问了其它项目组同事之前是怎么实现的,说就是由于冲突问题之前都是采用了httpClient之类的组装xml发送原生http请求调用的.redis
处理方式欠妥,做者固然不能接受。既然spring能在WebSphere下正常运行,那么spring的组件可以成功运行的可能性相对较大。spring
研究考虑以后,决定选用spring-ws来实现webservice。事实证实选择是正确的。json
spring-boot相关项目源码,api
码云地址:https://git.oschina.net/wyait/springboot1.5.4.git浏览器
github地址:https://github.com/wyait/spring-boot-1.5.4.gitspringboot
spring-ws的资料相对较少,不像cxf那样一找就是一大堆,不过好在有官方示例和文档。
官方示例中使用了spring boot,这跟我当前的环境不谋而合,不过它示例了多个构建工具和Groovy等,看起来比较复杂难懂一些,这里咱们就以单纯的maven来实现。
新建项目:ws-server(源码地址:
码云地址:https://git.oschina.net/wyait/springboot1.5.4.git
github地址:https://github.com/wyait/spring-boot-1.5.4.git
)
spring boot的工程,除了spring boot外还须要添加spring-ws和wsdl4j的依赖,固然后面生成代码还须要添加maven的jaxb2插件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
spring-ws的发布,都是以一个schema文件(xsd)定义开始的,它描述了webservice 的参数以及返回的数据。
这是官方示例给出的countries.xsd,这里以它为例,更改下命名空间,由于jaxb2插件自动生成代码是以命名空间来肯定包名的。手动生成不影响!
<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"xmlns:tns="http://www.wyait.com/ws"
targetNamespace="http://www.wyait.com/ws"elementFormDefault="qualified">
<xs:elementname="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:elementname="name" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:elementname="getCountryResponse">
<xs:complexType>
<xs:sequence>
<xs:elementname="country" type="tns:country"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexTypename="country">
<xs:sequence>
<xs:elementname="name" type="xs:string"/>
<xs:elementname="population" type="xs:int"/>
<xs:elementname="capital" type="xs:string"/>
<xs:elementname="currency" type="tns:currency"/>
</xs:sequence>
</xs:complexType>
<xs:simpleTypename="currency">
<xs:restrictionbase="xs:string">
<xs:enumerationvalue="GBP"/>
<xs:enumerationvalue="EUR"/>
<xs:enumerationvalue="PLN"/>
</xs:restriction>
</xs:simpleType>
</xs:schema>
pom文件配置jaxb2插件:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/schema</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>
eclipse开发工具:选中countries.xsd文件,右键:
IDEA开发工具:
对coruntries.xsd右键,而后选中web service那一项,generatejava code from xml schema using jaxb
选择要生成代码的包位置!生成代码结果:
咱们就再也不像spring-ws官方那样再建一个Repository了,这里直接返回。须要注意PayloadRoot注解当中的namespace和localPart须要和xsd中对应。
/**
*
* @项目名称:ws-server
* @类名称:CountryEndPoint
* @类描述:编写endpoint
* @建立人:wyait
* @建立时间:2017年7月14日上午11:02:49
* @version:
*/
@Endpoint
public class CountryEndPoint {
privatestatic final String NAMESPACE_URI = "http://www.wyait.com/ws";
@PayloadRoot(namespace= NAMESPACE_URI, localPart = "getCountryRequest")
@ResponsePayload
publicGetCountryResponse getCountry(
@RequestPayloadGetCountryRequest request) {
GetCountryResponseresponse = new GetCountryResponse();
Countrypoland = new Country();
poland.setName("Poland-"+ request.getName());
poland.setCapital("Warsaw");
poland.setCurrency(Currency.PLN);
poland.setPopulation(38186860);
response.setCountry(poland);
returnresponse;
}
}
/**
*
* @项目名称:ws-server
* @类名称:WebServiceConfig
* @类描述:spring boot整合web service
* @建立人:wyait
* @建立时间:2017年7月14日上午11:24:22
* @version:
*/
@EnableWs
@Configuration
public class WebServiceConfigextends WsConfigurerAdapter {
@Bean
publicServletRegistrationBean messageDispatcherServlet(
ApplicationContextapplicationContext) {
MessageDispatcherServletservlet = new MessageDispatcherServlet();
servlet.setApplicationContext(applicationContext);
servlet.setTransformWsdlLocations(true);
returnnew ServletRegistrationBean(servlet, "/ws/*");
}
@Bean(name= "countries")
publicDefaultWsdl11Definition defaultWsdl11Definition(
XsdSchemacountriesSchema) {
DefaultWsdl11Definitionwsdl11Definition = new DefaultWsdl11Definition();
wsdl11Definition.setPortTypeName("CountriesPort");
wsdl11Definition.setSchema(countriesSchema);
returnwsdl11Definition;
}
@Bean
publicXsdSchema countriesSchema() {
returnnew SimpleXsdSchema(
newClassPathResource("schema/countries.xsd"));
}
}
到这里spring-ws的全部配置和工做都已经完成了,上面的DefaultWsdl11Definitionid默认就是发布的ws的访问路径。
启动后访问 http://localhost:8080/ws/countries.wsdl 发现web service已经成功发布了。
这里要注意一下spring-ws发布的webservice是之后缀.wsdl访问的,跟传统的?wsdl不大同样,也看过它的源码,发现是在判断后缀时写死的,因此没办法配置修改了。
还有就是spring-ws实际上把发布wsdl和真正的服务实现Endpoint分开了,若是你的Endpoint不正确,极可能会出现浏览器访问.wsdl地址看起来正常而客户端调用却出现Not Found 404的错误。
前面咱们已经整合spring-ws实现了webservice的服务端:Spring Boot整合spring-ws开发web service客户端
接下来就是实现客户端进行调用了。
新建:ws-client(项目源码:https://git.oschina.net/wyait/springboot1.5.4.git)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-ws</artifactId>
<version>1.4.5.RELEASE</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
</dependency>
服务端由一个xsd文件开始,客户端则是由一个wsdl文件开始。
获取wsdl文件也十分简单,用浏览器访问webservice地址,而后另存为便可。固然也能够直接用url地址来生成代码。
方式一:本地另存:
完整的wsdl文件以下:
<wsdl:definitionsxmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:sch="http://www.wyait.com/ws"xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://www.wyait.com/ws"targetNamespace="http://www.wyait.com/ws">
<wsdl:types>
<xs:schemaxmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"targetNamespace="http://www.wyait.com/ws">
<xs:elementname="getCountryRequest">
<xs:complexType>
<xs:sequence>
<xs:elementname="name" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:elementname="getCountryResponse">
<xs:complexType>
<xs:sequence>
<xs:elementname="country" type="tns:country" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexTypename="country">
<xs:sequence>
<xs:elementname="name" type="xs:string" />
<xs:elementname="population" type="xs:int" />
<xs:elementname="capital" type="xs:string" />
<xs:elementname="currency" type="tns:currency" />
</xs:sequence>
</xs:complexType>
<xs:simpleTypename="currency">
<xs:restrictionbase="xs:string">
<xs:enumerationvalue="GBP" />
<xs:enumerationvalue="EUR" />
<xs:enumerationvalue="PLN" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
</wsdl:types>
<wsdl:messagename="getCountryResponse">
<wsdl:partelement="tns:getCountryResponse" name="getCountryResponse"></wsdl:part>
</wsdl:message>
<wsdl:messagename="getCountryRequest">
<wsdl:partelement="tns:getCountryRequest"name="getCountryRequest"></wsdl:part>
</wsdl:message>
<wsdl:portTypename="CountriesPort">
<wsdl:operationname="getCountry">
<wsdl:inputmessage="tns:getCountryRequest"name="getCountryRequest"></wsdl:input>
<wsdl:outputmessage="tns:getCountryResponse"name="getCountryResponse"></wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:bindingname="CountriesPortSoap11" type="tns:CountriesPort">
<soap:bindingstyle="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operationname="getCountry">
<soap:operationsoapAction="" />
<wsdl:inputname="getCountryRequest">
<soap:bodyuse="literal" />
</wsdl:input>
<wsdl:outputname="getCountryResponse">
<soap:bodyuse="literal" />
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:servicename="CountriesPortService">
<wsdl:portbinding="tns:CountriesPortSoap11"name="CountriesPortSoap11">
<soap:address/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>
方式二:jaxb2插件配置生成wsdl文件
跟服务端根据xsd来生成代码相似,客户端一样能够根据wsdl来生成代码。maven插件依赖:
<plugin>
<groupId>org.jvnet.jaxb2.maven2</groupId>
<artifactId>maven-jaxb2-plugin</artifactId>
<version>0.12.3</version>
<executions>
<execution>
<goals>
<goal>generate</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaLanguage>WSDL</schemaLanguage>
<generatePackage>com.wyait.ws.domain</generatePackage>
<generateDirectory>${basedir}/src/main/java</generateDirectory>
<schemas>
<schema>
<fileset>
<!--Defaults to schemaDirectory. -->
<directory>${basedir}/src/main/resources/schema</directory>
<!--Defaults to schemaIncludes. -->
<includes>
<include>*.wsdl</include>
</includes>
<!--Defaults to schemaIncludes -->
<!--<excludes>-->
<!--<exclude>*.xs</exclude>-->
<!--</excludes>-->
</fileset>
<!--<url>http://localhost:8080/ws/countries.wsdl</url>-->
</schema>
</schemas>
</configuration>
</plugin>
配置完,install将生成客户端代码。这里生成的代码跟咱们前面发布的服务端代码应该是同样的,固然包名可能不一样这个由本身指定。
在生成代码的同时会生成META-INF文件夹,这个能够移到resources目录下或者直接删除都没有关系。生成后的项目结构图:
编写ws 客户端代码:
public class WsClient extendsWebServiceGatewaySupport {
publicGetCountryResponse getCountry(String name) {
GetCountryRequestrequest = new GetCountryRequest();
request.setName(name);
GetCountryResponseresponse = (GetCountryResponse) getWebServiceTemplate()
.marshalSendAndReceive(
"http://http://127.0.0.1:9111/ws/countries.wsdl",
request);
returnresponse;
}
}
编写完一切代码以后,一样须要配置到spring boot才行,ContextPath指定刚才生成代码所在的包名,它会到该包下去寻找相应的类自动进行数据转换:
@Configuration
public class WSConfig {
@Bean
publicJaxb2Marshaller marshaller() {
Jaxb2Marshallermarshaller = new Jaxb2Marshaller();
marshaller.setContextPath("com.wyait.ws.domain");
returnmarshaller;
}
@Bean
publicWsClient wsClient(Jaxb2Marshaller marshaller) {
WsClientclient = new WsClient();
client.setDefaultUri("http://127.0.0.1:9111/ws/countries.wsdl");
client.setMarshaller(marshaller);
client.setUnmarshaller(marshaller);
returnclient;
}
}
使用了RestController,直接将调用ws返回的数据用json格式输出到页面。
@RestController
public class IndexController {
@Autowired
private WsClient wsClient;
@RequestMapping("callws")
public Object callWs() {
GetCountryResponse response =wsClient.getCountry("hello");
return response.getCountry();
}
}
端口改成:9112 避免和服务端端口9111冲突
启动,访问:http://127.0.0.1:9112/callws
回顾1.6章节末尾:
“还有就是spring-ws实际上把发布wsdl和真正的服务实现Endpoint分开了,若是你的Endpoint不正确,极可能会出现浏览器访问.wsdl地址看起来正常而客户端调用却出现Not Found 404的错误。”
排查ws服务端endpoint代码,没问题。是包命名的时候,单词写错了:
将wyati改为:wyait。启动,访问:http://127.0.0.1:9112/callws
ws-server /ws-client项目源码:
码云地址:https://git.oschina.net/wyait/springboot1.5.4.git
github地址:https://github.com/wyait/spring-boot-1.5.4.git
spring boot系列文章:
spring boot 1.5.4 集成devTools(五)
spring boot 1.5.4 集成JdbcTemplate(六)
spring boot 1.5.4 集成spring-Data-JPA(七)
spring boot 1.5.4 定时任务和异步调用(十)
spring boot 1.5.4 整合log4j2(十一)
spring boot 1.5.4 整合 mybatis(十二)
spring boot 1.5.4 整合 druid(十三)
spring boot 1.5.4 之监控Actuator(十四)
spring boot 1.5.4 整合webService(十五)
spring boot 1.5.4 整合redis、拦截器、过滤器、监听器、静态资源配置(十六)
spring boot 1.5.4 整合rabbitMQ(十七)