cxf 入門
? 一言以蔽之:WebService是一種跨編程語言和跨操作系統平臺的遠程調用技術。常用的webservice框架 : cfx、jwx、XFire與Axis2,jwx也就是jax-ws,是java6提供的對webservice的一種實現。cxf框架則簡化了服務發布過程。Axis與XFire已隨著技術不斷的更替慢慢落幕,而目前也只有axis2和cxf官方有更新,Axis與XFire都已不再更新。
? XML+XSD
, SOAP
和 WSDL
就是構成WebService平臺的三大技術。
1 XML+XSD
? XML 封裝數據 , 解決數據表示問題 , 因為與平臺和廠商無關 , 保證了通用性 ; XSD 解決數據類型問題 , 定義了 webService 所使用的數據的類型 , 保證了不同系統下數據通用的問題
2 SOAP
? soap協議 . WebService 是通過 http 協議發送請求和接收數據結果 , http 消息內容都有特定的消息頭和消息內容 . 而 SOAP 協議限定了這些消息頭和內容的格式. 簡單理解就是 , SOAP 約束了 WebService 的請求信息和響應信息應該長什麽樣 .
3 WSDL
? WSDL(Web Services Description Language) 服務描述語言 , WebService 作為一個服務 , 必須告訴調用者服務地址在哪?提供什麽服務?調用服務需要傳什麽參數?等 這些信息 , 就是通過 WSDL文件來描述的 .
? WSDL文件保存在Web服務器上,通過一個url地址就可以訪問到它。客戶端要調用一個WebService服務之前,要知道該服務的WSDL文件的地址。WebService服務提供商可以通過兩種方式來暴露它的WSDL文件地址:1.註冊到UDDI服務器,以便被人查找;2.直接告訴給客戶端調用者。
4 UDDI
? UDDI (Universal Description, Discovery, and Integration) 是一個主要針對Web服務供應商和使用者的新項目。在用戶能夠調用Web服務之前,必須確定這個服務內包含哪些商務方法,找到被調用的接口定義,還要在服務端來編制軟件,UDDI是一種根據描述文檔來引導系統查找相應服務的機制。UDDI利用SOAP消息機制(標準的XML/HTTP)來發布,編輯,瀏覽以及查找註冊信息。它采用XML格式來封裝各種不同類型的數據,並且發送到註冊中心或者由註冊中心來返回需要的數據。
2 WebService服務工作流程
? 註冊到 UUID服務器的 webservice
-
服務提供者實現服務 , 並在服務註冊中心(UDDI)進行註冊
-
服務請求者向服務註冊中心請求特定服務(其實就是請求對應的 wsdl 文件)
-
服務註冊中心找到對應的服務後 , 將該服務的描述(wsdl)文件返回為請求者
-
請求者根據返回的 wsdl 文件 , 生成相應的 soap消息 , 發送給服務提供者
-
服務提供者根據 soap消息執行對應的服務 , 並將結果返回給請求者
3 使用 cxf 搭建一個 webService
? CXF : Apache CXF 的前身叫 Apache CeltiXfire,現在已經正式更名為 Apache CXF 了,簡稱為 CXF。CXF 繼承了 Celtix 和 XFire 兩大開源項目的精華。
? 搭建 webService的步驟大致如下:
-
創建一個接口聲明提供的服務方法
-
實現接口
-
搭建web服務器,並註冊 CXFServlet , 用於對外提供服務
-
註冊服務
-
啟動web服務器
1 maven 坐標
<!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-frontend-jaxws -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.cxf/cxf-rt-transports-http -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.0.1</version>
</dependency>
?
<!-- 服務以 war 包形式發布,並且和 spring 整合所以依賴了 springmvc-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.10.RELEASE</version>
</dependency>
2 配置web.xml
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
?
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml</param-value>
</context-param>
?
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<!--cxf 服務的入口-->
<servlet>
<servlet-name>cxf</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>cxf</servlet-name>
<url-pattern>/webservice/*</url-pattern>
</servlet-mapping>
</web-app>
3 創建服務接口和實現類
? HelloWorld.java
package com.fmi110.cxf.service;
import javax.jws.WebParam;
import javax.jws.WebService;
/**
* 一定要添加 @WebService 註解 !!!
*/
public interface HelloWorld {
String sayHi(
?
}
ps:
@WebService
註解一定要有!!!否則報錯
@WebParam(name="msg")
不是必須的 , 加了以後生成的wsdl文件中對參數 msg 的描述會用"msg" 表示 , 否則使用 "arg0" 表述
? HelloWorldImpl.java
package com.fmi110.cxf.service.impl;
import com.fmi110.cxf.service.HelloWorld;
?
public class HelloWorldImpl implements HelloWorld{
public String sayHi(String msg) {
System.out.println("sayHi() 被調用...");
return "sayHi : "+msg;
}
}
4 spring配置文件 applicationContext.xml
? 因為在web.xml 中已經通過 <param-value>classpath*:applicationContext.xml</param-value>
指定配置文件位置 , 所以文件放在 src/main/resource
目錄下(maven工程 , 非maven工程放在 src 目錄下即可)
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
?
?
<!--開啟註解掃描聲明-->
<context:component-scan base-package="com.fmi110"/>
?
<!--聲明服務方式1-->
<bean id="hello" class="com.fmi110.cxf.service.impl.HelloWorldImpl"/>
<jaxws:server address="/helloworld">
<jaxws:serviceBean>
<ref bean="hello"/>
</jaxws:serviceBean>
</jaxws:server>
?
<!--聲明服務方式2-->
<!--
<jaxws:endpoint id="helloWorld" implementor="com.fmi110.cxf.service.impl.HelloWorldImpl" address="/helloworld"/>
-->
?
</beans>
? 如上提供了兩種註冊服務的方式 , <jaxws:server/>
和 <jaxws:endpoint/>
實現效果是等價的 , <jaxws:server/>
來源於 JAXWS 的API , 而 <jaxws:endpoint/>
來自 Xfire 的API , 選用哪個都可以...
? 這裏需要註意的是 <jaxws:server address="/helloworld">
中的 address 屬性指定了服務的訪問地址時 /helloworld , 則在瀏覽器中輸入的地址應該是 ${request.ContextPath}/helloworld
? jaxws 標簽的詳細配置請參考 : jax-ws-configuration
5 啟動服務並訪問
? 配置好後,啟動tomcat並部署應用 , 此時在瀏覽器輸入地址 : http://localhost:8080/cxf/webservice/helloworld?wsdl
可看到如下內容 :
? 這就說明我們的服務註冊成功了...
4 創建一個客戶端
? webService 是用來實現遠程調用的 , 所以這裏我們重新建一個java工程 , 遠程調用服務
1 使用 wsimport 命令生成接口文件
? 在一個空文件夾下 , 打開cmd 窗口 , 輸入如下命令 :
wsimport -s . http://localhost:8080/cxf/webservice/helloworld?wsdl
此時會生成一堆文件 , 這裏我們只需要生成的 HelloWorld.java 這個接口文件就可以了 , 文件內容如下 :
package com.fmi110.cxf.service;
?
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.ws.RequestWrapper;
import javax.xml.ws.ResponseWrapper;
?
(name = "HelloWorld", targetNamespace = "http://service.cxf.fmi110.com/")
// 這個類文件用不到,刪掉了,所以這裏也註釋掉
// ObjectFactory.class
})
public interface HelloWorld {
?
public String sayHi(
String msg);
?
}
註意 :
接口上的註解
@XmlSeeAlso
可以刪除,不影響接口上的註解
@WebService
, name 屬性可以隨便寫不影響 , targetNamespace 屬性不能修改 , 否則服務找不到,程序報錯
2 新建一個 java 工程作為客戶端
? 這裏還是使用maven工具來構建工程,需要導入的依賴跟搭建服務端的一致,這裏不在寫了 , 項目結構如下圖 :
? 這裏接口文件 HelloWorld.java 放在了 com.fmi110.cxf.service
包下 , 只是為了與服務端接口的定義保持一致 , 事實上放在哪個包下都可以 , 因為 cxf 生成代理類對象時 是通過接口文件裏的內容描述(class字節碼) 生成 , 所在包不影響.
3 註冊客戶端
? 在spring配置文件 client-beans.xml 裏註冊客戶端
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://cxf.apache.org/jaxws
http://cxf.apache.org/schemas/jaxws.xsd">
?
?
<!--聲明客戶端-->
<jaxws:client id="client" serviceClass="com.fmi110.cxf.service.HelloWorld"
address="http://localhost:8080/cxf/webservice/helloworld"/>
</beans>
serviceClass 的值是項目中 HelloWorld 類的全限定名
address 地址必須寫正確 , 否則調用不了服務 , 該地址時服務端暴露的服務的地址
4 編寫測試代碼
import com.fmi110.cxf.service.HelloWorld;
import org.springframework.context.support.ClassPathXmlApplicationContext;
?
/**
* Created by huangyunning on 2017/12/20.
*/
public class HelloClient {
?
public static void main(String args[]) throws Exception {
?
ApplicationContext context = new ClassPathXmlApplicationContext("client-beans.xml");
?
HelloWorld client = (HelloWorld)context.getBean("client");
?
String response = client.sayHi("Joe");
System.out.println("Response: " + response);
?
System.exit(0);
}
}
5 cxf 支持的參數
? cxf 定義的接口方法參數和返回值類型可以是基本數據類型 , java 對象 或這 List 集合 , 如果要使用 Map 集合或者 接口 , 則需要註冊XmlAdapter 進行轉換
cxf 入門