WebService 教程(包含項目實踐)

情景引入:

時間:早晨 8 : 00 am

小白:起牀起牀,,,公司又來需求了,你還在睡覺,快點起來~!

我:大驚小怪,又怎麼了呢?小白,別一驚一乍的,打擾我的美夢

小白:公司給了個新需求,你還記得,咱們上次做的那個項目嗎?

我:記得,怎麼了呢?不是都已經上線了嗎?

小白:對呀,但是,與我們合作的那個公司,他們想把我們項目裏面的物流查詢功能,放到他們自己開發的一個系統裏面去,說這樣方便他們自己進行查詢,要不然,老是需要額外登錄我們的系統,挺麻煩的,而還要特別的給他們一個賬號進行管理。所以,他們的需求就是:讓物流查詢的功能提供給他們。 

我:意思是他們想跨平臺用我們的物流功能呢?

小白:是的,,,快,趕緊想想辦法,咱們,總不能又給他們寫一套一樣的代碼嵌入吧,這效率太低了。

我:當然不行了,這樣寫的話,有很多問題的,而且系統與系統進行了多重嵌入會影響整體的執行。

小白:對呀,所以,那咱們怎麼辦呢?

我:容我思考思考,針對這樣的跨平臺問題,其實也挺好解決的,那就是採取WebService的方式,我們將物流查詢作爲一個WebService,這樣只需要他們那邊進行相應的規則處理就好了。

小白:WebService??這是一個什麼東西呢?有這麼神奇,還可以跨平臺的嗎?

我:當然,這在很多地方其實都用到的,比如天氣查詢功能,你覺得每個公司都會去寫一套這樣的代碼嗎?當然不會。

小白:對哦,要不然這多麻煩,你看像微信公衆號裏面的那麼多服務,都是別人寫好的,我們開發都是用一定的規則去解析的。

我:對的,那下面,我來說說,到底什麼是WebService和它的功能。

一:WebService簡介

(1)簡介----百度百科(注意標識的重點)

        Web service是一個平臺獨立的,低耦合的,自包含的、基於可編程的web的應用程序,可使用開放的XML(標準通用標記語言下的一個子集)標準來描述、發佈、發現、協調和配置這些應用程序,用於開發分佈式的互操作的應用程序。 [1] 
       Web Service技術, 能使得運行在不同機器上的不同應用無須藉助附加的、專門的第三方軟件或硬件, 就可相互交換數據或集成。依據Web Service規範實施的應用之間, 無論它們所使用的語言、 平臺或內部協議是什麼, 都可以相互交換數據。Web Service是自描述、 自包含的可用網絡模塊, 可以執行具體的業務功能。Web Service也很容易部署, 因爲它們基於一些常規的產業標準以及已有的一些技術,諸如標準通用標記語言下的子集XML、HTTP。Web Service減少了應用接口的花費。Web Service爲整個企業甚至多個組織之間的業務流程的集成提供了一個通用機制。

(2)WebService三元素

UDDI:UDDI 的目的是爲電子商務建立標準;UDDI是一套基於Web的、分佈式的、爲Web Service提供的、信息註冊中心的實現標準規範,同時也包含一組使企業能將自身提供的Web Service註冊,以使別的企業能夠發現的訪問協議的實現標準。---簡單點說,就是一套規則,方便使用;

WSDL:Web Service描述語言WSDL 就是用機器能閱讀的方式提供的一個正式描述文檔而基於XML(標準通用標記語言下的一個子集)的語言,用於描述Web Service及其函數、參數和返回值。因爲是基於XML的,所以WSDL既是機器可閱讀的,又是人可閱讀的。----簡單點說,就是使用規則,方便人和機器進行閱讀;

SOAP協議:基於Http,基於XML,SOAP即簡單對象訪問協議(Simple Object Access Protocol),它是用於交換XML(標準通用標記語言下的一個子集)編碼信息的輕量級協議。它有三個主要方面:XML-envelope爲描述信息內容和如何處理內容定義了框架,將程序對象編碼成爲XML對象的規則,執行遠程過程調用(RPC)的約定。SOAP可以運行在任何其他傳輸協議上。例如,你可以使用 SMTP,即因特網電子郵件協議來傳遞SOAP消息,這可是很有誘惑力的。在傳輸層之間的頭是不同的,但XML有效負載保持相同。----簡單點說,就是傳輸協議,方便進行傳輸;

(3)WebService與Socket的區別(兩種通信的方式)

(1) Socket是基於TCP/IP的傳輸層協議。 
    Webservice是基於HTTP協議傳輸數據,http是基於tcp的應用層協議。 
    Webservice採用了基於http的soap協議傳輸數據。
(2)Socket接口通過流傳輸,不支持面向對象。 
    Webservice 接口支持面向對象,最終webservice將對象進行序列化後通過流傳輸。 
    Webservice採用soap協議進行通信,不需專門針對數據流的發送和接收進行處理,是一種跨平臺的面向對象遠程調用技術。
(3)Socket適用於高性能大數據的傳輸,傳輸的數據需要手動處理,socket通信的接口協議需要自定義。

二:屬於自己的第一個WebService程序

1)服務端代碼(Java工程項目即可,而不需要是web項目,因爲webservice已經作爲了java SE裏面自帶的內容):

package com.hnu.scw.webservice;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**  
 * <p>Title: MyFirstWebService.java</p>  
 * <p>Description: </p>  
 */
@WebService
public class MyFirstWebService {
	/**
	 * 定義webservice服務器中的方法
	 * @param content
	 * @return
	 */
	public String testWebService(String content){
		System.out.println("我收到了你發的信息:" + content);
		return "服務器:我轉發信息給你";
	}
	
	public static void main(String[] args){
		//定義自己的webservice服務器發佈的地址
		String address = "http://localhost:9090/MyFirstWebService"; //這個9090端口隨便定義,只要不衝突即可
		//通過該方法進行發佈
		Endpoint.publish(address, new MyFirstWebService());
		//打印一句話,表示一下服務器進行了開啓
		System.out.println("my webservcie starting");
	}
}

溫馨提示:1:必須加@WebService註解或者@WebServiceProvider

2:至少有一個方法是public,並且不可以用static 和 final進行修飾;原因很明顯,因爲webservice就是提供給別人各自進行使用的,而不是保持同一個,所以不能是static ,而對於final修飾的話就是不可繼承,這也是沒有意義的。大家可以試試,將方法進行修改,看會不會報錯。

(2)解析WebService服務器的內容

操作:在cmd命令行中執行:wsimport -s . http://localhost:9090/MyFirstWebService

結果:這樣的話,就會在你執行這句話的目錄下面生成對應的服務器的代碼(包括.class文件和.java文件)

(3)客戶端代碼(Java工程項目即可):

步驟:

1:首先是把上面得到的代碼中的.java文件(請注意,.class文件就不需要)拷貝到我們新建的一個客戶端的java項目中

2:編寫我們的測試方法

 

溫馨提示:可以通過瀏覽器輸入:http://localhost:端口號/發佈的服務器名字?wsdl     -----------來查看定義service的wsdl文檔

這時候,我們只需要首先運行服務器端的java項目,然後再運行我們客戶端的@Test方法,這樣就可以得到從服務器中獲取到的消息內容了。

三:與WebService服務器進行交互的方式

(1)普通客戶端調用

這個的話就不多說了,因爲在我們上面的第一個WebService的代碼中,就已經是這樣的一種調用方式。

(2)ajax調用

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
	<script type="text/javascript">
		/*
			思路:
			1.創建一個XMLHTTP對象
			2.打開鏈接open("POST",url)
			3.設置請求頭Content-Type
			4.設置回調函數,處理返回值
			5.從返回的XML中解析我們要的內容
		*/
		
		var xmlHttpReqquest = new ActiveXObject("Microsoft.XMLHTTP");
		//alert(xmlHttpReqquest);
 
		//發送SOAP請求
		function sendMsg(){
			//獲取用戶輸入的內容
			var name = document.getElementById("name").value;
			var url = "http://localhost:9090/MyFirstWebService";
			//下面的這種格式主要是通過Eclipse下載了一個webservice調式工具,這樣就可以看到對應的xml格式內容
			var requestBody = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:q0=\"http://webservice.scw.hnu.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
							+ "<soapenv:Body><q0:testWebService><arg0>"+name+"</arg0></q0:testWebService></soapenv:Body></soapenv:Envelope>";
			xmlHttpReqquest.open("POST", url);
			xmlHttpReqquest.setRequestHeader("Content-Type","text/xml;charset=utf-8");
			xmlHttpReqquest.onreadystatechange = _back;
			xmlHttpReqquest.send(requestBody);
		}
 
		//接收SOAP返回,從返回XML中解析
		function _back(){
			//處理完畢,處理成功
			if(xmlHttpReqquest.readystate==4){		//處理完
				if(xmlHttpReqquest.status==200){	//成功
					var xml = xmlHttpReqquest.responseXML;
					//alert(xml);
 
					//獲取return標籤的第一個
					var ele = xml.getElementsByTagName("return")[0];
					alert(ele.text);
				}else{
					alert(0);
				}
			}
		}
	
	</script>
</head>
<body>
	<input type="text" id="name" name="name" value=""/>
	<input type="button" name="send" value="send" οnclick="sendMsg();"/>
</body>
</html>

(3)URLConnection的調用方式

//創建url地址
URL url = new URL(""http://localhost:9090/MyFirstWebService");
//打開連接
URLConnection conn = url.openConnection();
//轉換成HttpURL
HttpURLConnection httpConn = (HttpURLConnection) conn;
//打開輸入輸出的開關
httpConn.setDoInput(true);
httpConn.setDoOutput(true);
//設置請求方式
httpConn.setRequestMethod("POST");
//設置請求的頭信息
httpConn.setRequestProperty("Content-type", "text/xml;charset=UTF-8");
//拼接請求消息
String data = "<soapenv:Envelope xmlns:soapenv=" +
        "\"http://schemas.xmlsoap.org/soap/envelope/\" " +
        "xmlns:q0=\"http://server.rl.com/\" " +
        "xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " +
        "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">"
        +"<soapenv:Body>"
        +"<q0:testWebService>"
        +"<arg0>my name is scw</arg0> "
      +"</q0:testWebService>"
      +"</soapenv:Body>"
      +"</soapenv:Envelope>";
//獲得輸出流
OutputStream out = httpConn.getOutputStream();
//發送數據
out.write(data.getBytes());
//判斷請求成功
if(httpConn.getResponseCode() == 200){
    //獲得輸入流
    InputStream in = httpConn.getInputStream();
    //使用輸入流的緩衝區
    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
    StringBuffer sb = new StringBuffer();
    String line = null;
    //讀取輸入流
    while((line = reader.readLine()) != null){
        sb.append(line);
    }
    //創建sax的讀取器
    SAXReader saxReader = new SAXReader();
    //創建文檔對象
    Document doc = saxReader.read(new StringReader(sb.toString()));
    //獲得請求響應return元素
    List<Element> eles = doc.selectNodes("//return");
    for(Element ele : eles){
        System.out.println(ele.getText());
    }
}

(4)QName調用------------推薦這種方式

package com.hnu.scw.test;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.namespace.QName;
import javax.xml.ws.Service;
import org.junit.Test;
import com.hnu.scw.webservice.MyFirstWebService;
/**  
 * <p>Title: MyTestQNameWebService.java</p>  
 * <p>Description: 通過QName的一種調用方式</p>  
 
 */
public class MyTestQNameWebService {
	@Test
	public void test() throws MalformedURLException{
		//創建一個連接(地址對應的就是webservice服務器中的地址)
		URL wsdlDocumentLocation = new URL("http://localhost:9090/MyFirstWebService?wsdl");
		//這個參數,主要是根據我們設定的webService的接口來進行的
		QName serviceName = new QName("http://webservice.scw.hnu.com/","MyFirstWebServiceService");
		Service ws = Service.create(wsdlDocumentLocation , serviceName );
		//獲取到調用的對象內容
		MyFirstWebService port = ws.getPort(MyFirstWebService.class);
		//方法的調用
		String result = port.testWebService("my name is scw");
		System.out.println(result);
	}
}

溫馨提示:(1)這個方式大體和我們之間進行的客戶端調用類型,但是注意一點,在我們的客戶端的方式的時候,我們是把所解析得到的.java所有文件都拷貝到客戶端程序,而如果用QName的形式,我們只需要保留我們對應WebService類的接口那個即可。比如,如下:

客戶端的情況:

QName的情況:

(2)當我們只保留上面的java文件的時候,會出現錯誤,只需要根據下面進行修改即可;

(3)QName對象的參數是如何知道的?那麼久看我們保留的那個接口類中;

(4)通過QName的方式可以很明顯的感覺比第一種客戶端要好,因爲,可以對於端口和鏈接都有靈活性,而且拷貝的代碼也相對較少;

四:關於WebService的部分註解

五:初識CXF框架

     官網:http://cxf.apache.org/

    Apache CXF = Celtix + XFire,開始叫 Apache CeltiXfire,後來更名爲 Apache CXF 了,以下簡稱爲 CXF。CXF 繼承了 Celtix 和 XFire 兩大開源項目的精華,提供了對 JAX-WS 全面的支持,並且提供了多種 Binding 、DataBinding、Transport 以及各種 Format 的支持,並且可以根據實際項目的需要,採用代碼優先(Code First)或者 WSDL 優先(WSDL First)來輕鬆地實現 Web Services 的發佈和使用。Apache CXF已經是一個正式的Apache頂級項目。

      Apache CXF 是一個開源的 Services 框架,CXF 幫助您利用 Frontend 編程 API 來構建和開發 Services ,像 JAX-WS 。這些 Services 可以支持多種協議,比如:SOAP、XML/HTTP、RESTful HTTP 或者 CORBA ,並且可以在多種傳輸協議上運行,比如:HTTP、JMS 或者 JBI,CXF 大大簡化了 Services 的創建,同時它繼承了 XFire 傳統,一樣可以天然地和 Spring 進行無縫集成。

六:利用CXF框架來搭建我們的WebService

步驟:

(1)首先去官網下載一個版本http://cxf.apache.org/,現在的話,都是3.2.X版本了,這個根據需要即可;

(2)下載之後,裏面就有一個lib的目錄,就是關於CXF架構的一些依賴包;

可以去官網下載(或者去博文最後的百度雲中下載):http://cxf.apache.org/

(3)創建一個web項目(注意:這時候用了web項目,而之前的開發都是用的Java項目),並且把依賴包都複製到項目中的lib目錄中(就和正常的開發web項目一樣,在拷貝所有的之後,要把裏面的WHICH_JARS這個文件刪除,否則會報錯

服務端代碼:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基於CXF框架的服務端代碼
 * @author Administrator
 *
 */
public class FirstCXFService {
	/**
	 * web服務的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客戶端發送過來信息:" + name);
		return "服務器轉發給你了"+ name;
	}	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//設置訪問地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//設置實現類
		serverFactoryBean.setServiceClass(FirstCXFService.class);
		//啓動服務
		serverFactoryBean.create();
	}
}

溫馨提示:不要運行配置的服務器,而是直接運行main函數即可。。。。。這樣就開啓可服務器

客戶端代碼:(同樣的還是通過cmd中的命令:wsimport -s .  XXXXXXXXXX (SOAP1.1版本)或者wsdl2java –d . XXXXXXXXXX(SOAP1.2版本) 來生成代碼),然後再創建一個工程項目,並把生成的.java文件拷貝進去。


 

 

package com.hnu.scw.test;
import org.junit.Test;
import com.hnu.scw.FirstCXFService;
import com.hnu.scw.FirstCXFServicePortType;
/**
 * 測試CXF框架的客戶端
 * @author Administrator
 *
 */
public class CXFClientTest {
	@Test
	public void printTest(){
		FirstCXFService firstCXFService = new FirstCXFService();
		FirstCXFServicePortType firstCXFServicePort = firstCXFService.getFirstCXFServicePort();
		String result = firstCXFServicePort.printReciveInfo("my name is scw");
		System.out.println(result);
	}
}

七:面向接口的編寫WebService服務

接口:

package com.hnu.scw;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.BindingType;
import javax.xml.ws.soap.SOAPBinding;
@WebService(serviceName="HelloServer")
@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)			
public interface FirstServer {
	@WebMethod(operationName="sayHello")
	@WebResult(name="returnMsg")
	public String printReciveInfo(@WebParam(name="name")String name);
}

服務器端實現類:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基於CXF框架的服務端代碼
 * @author Administrator
 *
 */
public class FirstCXFService implements FirstServer{
	/**
	 * web服務的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客戶端發送過來信息:" + name);
		return "服務器轉發給你了"+ name;
	}
	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//設置訪問地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//設置接口
		serverFactoryBean.setServiceClass(FirstServer.class);
		//設置實現類
		serverFactoryBean.setServiceBean(new FirstCXFService());
		//啓動服務
		serverFactoryBean.create();
	}
}

客戶端類型的方法就不多說了,只是需要重新編譯下載服務端的代碼即可。

八:在WebService服務端添加輸入輸出監控日誌

 方法:其實很簡單,就是添加一些默認的攔截器就可以了

服務端代碼:

package com.hnu.scw;
import org.apache.cxf.frontend.ServerFactoryBean;
/**
 * 基於CXF框架的服務端代碼
 * @author Administrator
 *
 */
public class FirstCXFService {
	/**
	 * web服務的方法
	 * @param name
	 * @return
	 */
	public String printReciveInfo(String name){
		System.out.println("客戶端發送過來信息:" + name);
		return "服務器轉發給你了"+ name;
	}	
	public static void main(String[] args){
		ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
		//設置訪問地址
		serverFactoryBean.setAddress("http://localhost:9090/firstService");
		//設置實現類
		serverFactoryBean.setServiceClass(FirstCXFService.class);
		//攔截器
		serverFactoryBean.getInInterceptors().add(new LoggingInInterceptor());		//攔截請求的鏈接,打印相關信息(誰調用)
		serverFactoryBean.getOutInterceptors().add(new LoggingOutInterceptor());		//攔截響應的鏈接,打印相關信息(返回)
		//啓動服務
		serverFactoryBean.create();
	}
}

九:設置WebService的版本是採取SOAP1.2版本

   在前面有說過,JDK是默認支持SOAP1.1版本的,而現在也有1.2版本,那如何將我們的WebService轉變成1.2版本的呢?其實很簡單,只需要添加一個註解即可:(如果採取的是接口編程,那麼就放在接口名上即可)

@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)

小知識:SOAP1.1和SOAP1.2的區別:

1)命名空間

2)標籤變化

溫馨提示:在開發中如果使用SOAP1.2實現WebService,在生成本地調用代碼時,應該使用CXF提供wsdl2java命令。如果使用SOAP1.1實現WebService,在生成本地調用代碼時,應該使用jdk提供wsimport命令。在實際項目中目前儘量使用SOAP1.1版本;

十:CXF和Spring框架的整合(重點知識)

步驟:

(1)導包:將下載下來的CXF中的lib目錄中jar導入到web項目中的WEB-INF目錄下的lib中(同樣,還是需要將其中的WHICH_JARS這個文件刪除,否則會報錯),不需要額外導入Spring的包,因爲在CXF的lib中已經包含有Spring的jar包,這個自己可以進行查看;

(2)創建WebService的類;

比如:

package com.hnu.scw.webservice;
import javax.jws.WebService;
/**
 * 創建一個webservice服務類
 * @author scw
 *
 */
@WebService
public class MyWebService {
	/**
	 * 創建WebService的調用方法
	 * @param content
	 * @return
	 */
	public String hiMyService(String content){
		System.out.println("客戶端發送過來了:" + content);
		return "服務器返回:"+ content ;
	}
}

(3)在WEB-INF目錄下面創建一個cxf-servlet.xml-------------------這個就是對於webservice的管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns:jaxws="http://cxf.apache.org/jaxws" 
		xsi:schemaLocation=" http://www.springframework.org/schema/beans 
							http://www.springframework.org/schema/beans/spring-beans.xsd 
							http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
    
    <!-- 加載提供的服務 -->
    <jaxws:endpoint id="helloService" address="/mywebservice" implementor="com.hnu.scw.webservice.MyWebService"></jaxws:endpoint>
</beans>

(4)修改web.xml文件內容,將WebService的cxf-servlet.xml進行管理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxf</display-name> 
    <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 這裏配置只針對/cxf/的這樣鏈接進行管理,因爲如果也配置成/*這樣的話,也是可以,這只是更加便於管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>
</web-app>

(5)啓動tomcat項目,測試CXF的配置是否成功

(6)配置Spring的配置文件中的beans.xml,專門進行bean的內容的管理(在項目的src下即可,這和Spring開發沒什麼不同)

主要是爲了將WebService的類放入到Spring中進行管理

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
			http://www.springframework.org/schema/mvc 
			http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd 
			http://www.springframework.org/schema/context 
			http://www.springframework.org/schema/context/spring-context-3.0.xsd 
			http://www.springframework.org/schema/aop 
			http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
			http://www.springframework.org/schema/tx 
			http://www.springframework.org/schema/tx/spring-tx-3.0.xsd ">
	<bean id="myWebService" class="com.hnu.scw.webservice.MyWebService"></bean>	 <!--這就是我的webservice類的路徑-->	
</beans>			

(7)修改之前的cxf-servlet.xml中的內容

原因:因爲現在我們的bean放入到了Spring中進行管理,所以,我們直接引用Spring中的bean即可

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns:jaxws="http://cxf.apache.org/jaxws" 
		xsi:schemaLocation=" http://www.springframework.org/schema/beans 
							http://www.springframework.org/schema/beans/spring-beans.xsd 
							http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
    
    <!-- 加載提供的服務 ,注意看此時的implementor標籤的寫法,#表示的是引用Spring中的bean內容-->
    <jaxws:endpoint id="helloService" address="/mywebservice" implementor="#myWebService"></jaxws:endpoint>
</beans>

(8)修改web.xml內容,將Spring放入到容器進行管理

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee           http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
    <display-name>cxf</display-name>
    
    <!-- 配置spring框架 beans.xml -->
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>classpath:beans.xml</param-value>
    </context-param>
    <listener>
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 這裏配置只針對/cxf/的這樣鏈接進行管理,因爲如果也配置成/*這樣的話,也是可以,這只是更加便於管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>
</web-app>

(9)啓動tomcat,進行測試是否整合成功

總結:通過上面的步驟,我們的整合已經成功了,但是大家可能發現有很多地方不是很好,比如我們的cxf-servlet.xml是放在WEB-INF目錄下,那麼我們應該也像配置Spring的配置文件一樣,放在src下這樣的話將會更加好,所以,我們進行下面的修改

 (10)修改cxf-servlet.xml的加載路徑----------這樣我們就可以把這個xml放到src目錄下了

 <!-- 配置cxf框架 cxf-servlet.xml -->
    <servlet>
    	<servlet-name>cxf</servlet-name>
    	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
    	<!-- 配置cxf-servlet.xml的尋找的位置 -->
    	<init-param>
    		<param-name>config-location</param-name>
    		<param-value>classpath:cxf-servlet.xml</param-value>
    	</init-param>
    </servlet>
    <servlet-mapping>
    	<servlet-name>cxf</servlet-name>
    	<!-- 這裏配置只針對/cxf/的這樣鏈接進行管理,因爲如果也配置成/*這樣的話,也是可以,這只是更加便於管理而已 -->
    	<url-pattern>/cxf/*</url-pattern>
    </servlet-mapping>

--------------------------------------------------------------------------------------------

項目整體結構如下:

------------------------------------------------------------------------------------------------

十一:項目實踐

前提內容:這是一個比較經典的物流供應項目,網上可以找到源碼的。只不過,既然我們學得是WebService,那麼肯定就要進行相應的改造的,所以,針對裏面的一個物流查詢模塊,來設計成爲一個能夠讓其他系統都能調用的功能(這樣,情景引入的問題是不是就解決了)。

描述:針對項目中的,物流查詢模塊改造成一個WebService服務,方便其他的模塊或者系統進行相應的使用,實現一種跨平臺的功能。

步驟:

環境:eclipse + maven + mysql (其他的編輯器什麼的都行,這個完全根據自身習慣即可,沒有要求)

(1)導入項目內容--------這個不多說,就是導入maven項目,然後把相應的數據庫內容在本地生成即可(都在我的百度雲裏面了)

(2)查看原始內容(重點關注我標識的部分,也就是我們要進行改造的類)

 

我們就改造下面這個方法:這個方法的功能就是,通過物流的ID,來查詢到它的物流信息

提示:大家稍微看一下這個類,基本瞭解是幹嘛的就可以了哈~~

改造其類爲WebService類步驟(重點來了):

(1)將需要修改爲WebService的類,添加註解 @WebService進行標識

(2)添加操作對應的DAO類的額外bean依賴

        //給WebService使用
	@WebMethod(exclude=true)
	public void setExportDao(ExportDao exportDao) {
		this.exportDao = exportDao;
	}

分析:

1:添加@WebMethod(exclude=true)的作用:防止給調用者看到這個方法,因爲這個方法只是給spring來進行注入bean依賴的;

2:大家可能注意到一個問題了,在spring開發中,

我們一般是這樣。

但是,千萬注意一下,這個也是要的,而爲什麼又多了一個set注入,是因爲,這是專門用戶webservice注入的,所以,一定要區分開原因,所以這兩者都是需要存在的。也就是下面的這樣的代碼:

//給spring service使用dao
	@Resource
	ExportDao exportDao;
	
	//給WebService使用
	@WebMethod(exclude=true)
	public void setExportDao(ExportDao exportDao) {
		this.exportDao = exportDao;
	}

(3)將其他不進行提供webservice調用的方法進行註解屏蔽,而只保留webservice能夠調用的方法。如下所示:

@WebMethod(exclude=true)
	public List<Export> find(Map paraMap) {
		return exportDao.find(paraMap);
	}
 
	//WebService調用
	public Export get(String id) {
		return exportDao.get(id);
	}

(4)添加cxf-servlet.xml文件

目錄:

cxf-servlet.xml添加的內容如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
		xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
		xmlns:jaxws="http://cxf.apache.org/jaxws" 
		xsi:schemaLocation=" http://www.springframework.org/schema/beans 
					http://www.springframework.org/schema/beans/spring-beans.xsd 
					http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
					
    <import resource="classpath:META-INF/cxf/cxf.xml"/>
    <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
   
	<!-- 發佈WebService 參數:訪問地址address,實現類 implementor -->
	<bean id="exportService" class="cn.itcast.jk.service.impl.ExportServiceImpl">
		<property name="exportDao" ref="exportDaoImpl"/>
	</bean>
	
	<jaxws:endpoint address="/ExportServiceImpl" implementor="#exportService"/>
</beans>

分析:現在再回頭看一下第(2)步中,額外添加的set注入,是不是就明白原因了呢?這上面的知識都是我上面講過的,所以,不懂的就回頭再去看看吧。

(5)修改web.xml,添加對cxf-servlet.xml的加載

<!-- 3.webService CXF -->
  <servlet>
  	<servlet-name>cxf</servlet-name>
  	<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  	<init-param>
  		<param-name>config-location</param-name>
  		<param-value>classpath:cxf-servlet.xml</param-value>
  	</init-param>
  </servlet>
  
  <servlet-mapping>
  	<servlet-name>cxf</servlet-name>
  	<url-pattern>/cxf/*</url-pattern>
  </servlet-mapping>

(6)在pom.xml中添加對CXF框架的依賴

<!-- 整合CXF WebService框架 -->
		<dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-frontend-jaxws</artifactId>
            <version>3.0.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.cxf</groupId>
            <artifactId>cxf-rt-transports-http</artifactId>
            <version>3.0.2</version>
        </dependency>

分析:通過上面的步驟,基本上就改造完成了,那麼下面就來進行實際的使用:(這裏通過ajax的形式來進行,也是我們開發中用的相對較多的方式)

(7)ajax來調用webservice類的形式

具體的內容:大家就看代碼中:src\main\webapp\WEB-INF\pages\cargo\export目錄下的ajaxExport.jsp頁面內容吧

(8)進行測試。(當然,這個最好是在整合完成CXF和Spring,即改造完webservice類的時候就測試一下比較好)

針對這個項目的話,我把最初的項目源碼和改造後的代碼以及數據庫內容,兩個版本的都放入了百度雲,而且把該博文中相關的代碼都放入了這裏面,供大家進行下載。

鏈接:https://pan.baidu.com/s/1_exUqQeg3h2OwGFhDa2dmg          密碼:60fq

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章