上一篇: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(十七)