Web-Service-常用監聽器&&註解修改WSDL

WebService監聽工具:

之前我們使用過HttpWatch獲取的HTTP的調用過程,並獲得了HTTP的請求頭及其他請求的詳細信息。

既然WebServie也是通過HTTP進行通信的,能不使用HTTPWatch來獲取它的請求過程呢?


我們的代碼不僅僅是向服務器發送的HTTP協議,更具體的說應該叫SOAP協議,它是WebService進行通信的基
礎。
爲了獲取SOAP數據發送和接收的格式。我們有必要使用一個工具來深入的瞭解WebService.

爲了監控攔截請求頭和響應頭的具體數據,我們使用TCP/IP Monitor來攔截請求和響應的完整過程。

1:簡單的說,SOAP就是在HTTP的基礎上傳輸XML數據,以實現遠程調用。

    因爲HTTPXML格式的數據已經被廣泛的應用。而SOAP又架構在這兩種技術之上,所以WebService爲什麼會流行也就不難理解了。

2:老生常談,無論你的服務端是什麼語言書寫的,只要接收SOAP協議的XML數據,並返回SOAP協議的XML數據,就可以被任何語言調用。

3、以下是通過純ajax向服務器發送XML數據並解析的代碼:

<%@page language="java" import="java.util.*"pageEncoding="UTF-8"%>

<!DOCTYPEHTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

<html>

  <head>

  </head>

  <body>

    <p>通過Ajax向服務器發送XML數據</p>

    <button onclick="test1();">Ajax</button>

  </body>

  <script type="text/javascript">

    varhttp;

    functiontest1(){

    if(window.XMLHttpRequest){

    http =new XMLHttpRequest();

    }else{

    http =new ActiveXObject("Microsoft.XMLHttp");

    }

    varurl= "One";

    http.open("POST",url,true);

    http.setRequestHeader("Content-Type","application/x-www-form-urlencoded");

    http.onreadystatechange=function(){

    if(http.readyState==4){

    if(http.status==200){

    //返回JSON

    varjson= http.responseText;

    varperson= eval("("+json+")");

    alert("人員名單:"+person.name);

    }

    }

    };

    http.send("<?xmlversion='1.0' encoding='utf-8'?>" +

    "<user><name>xx</name><name>張三</name></user>");

    }

  </script>

</html>

---

服務器使用jaxp進行解析

packagecn.itcast;

importjava.io.IOException;

importjava.io.InputStream;

importjava.io.PrintWriter;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importjavax.xml.parsers.DocumentBuilder;

importjavax.xml.parsers.DocumentBuilderFactory;

importorg.w3c.dom.Document;

importorg.w3c.dom.Element;

importorg.w3c.dom.NodeList;

/**

 * 接收XML數據使用jaxp進行解析

 * @author

 */

publicclass One extends HttpServlet{

  public void doGet(HttpServletRequestrequest, HttpServletResponseresponse)

  throws ServletException,IOException{

  doPost(request,response);

  }

  public void doPost(HttpServletRequestrequest, HttpServletResponseresponse)

  throws ServletException,IOException{

  //獲取輸入流,如果在輸出,請在組成String時使用UTF-8

  InputStreamin = request.getInputStream();

  String names = "";

  // 使用JAXP解析

  try {

  DocumentBuilderFactoryfactory = DocumentBuilderFactory

  .newInstance();

  DocumentBuilderbuilder = factory.newDocumentBuilder();

  Document dom= builder.parse(in);

  NodeList nl = dom.getElementsByTagName("name");

  for(inti=0;i<nl.getLength();i++){

  Element el = (Element)nl.item(i);

  String name = el.getTextContent();

  System.err.println(">>:"+name);

  names +=name;

  }

  } catch (Exception e) {

  throw new RuntimeException(e.getMessage(),e);

  }

  response.setContentType("text/xml;charset=UTF-8");

  PrintWriterout = response.getWriter();

  out.print("{\"name\":\""+names+"\"}");

  }

}

-----以下通過jQuery+Dom4j實現發XML數據--------

   <scripttype="text/javascript"src="js/jquery-1.6.2.js"></script>

    <scripttype="text/javascript">

    $(function(){

    $("#jq").click(function(){

    varxml = "<?xml version='1.0' encoding='UTF-8'?>" +

    "<user><name>王健A</name><name>張三</name></user>";

    alert(xml);

    $.ajax({

    url:'Two',

    type:'post',

    dataType:'json',//設置返回的數據類型

    data:xml,//直接發xml數據

    contentType:'application/x-www-form-urlencoded',

    success:function(data){

    alert("返回的信息是:"+data.name);

    },

    complete:function(http,textStatus){

    alert("over..."+textStatus);

    }

    });

    });

    });

    </script>

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

packagecn.itcast;

importjava.io.IOException;

importjava.io.InputStream;

importjava.io.PrintWriter;

importjava.util.Iterator;

importjavax.servlet.ServletException;

importjavax.servlet.http.HttpServlet;

importjavax.servlet.http.HttpServletRequest;

importjavax.servlet.http.HttpServletResponse;

importorg.dom4j.Document;

importorg.dom4j.Element;

importorg.dom4j.io.SAXReader;

/**

 * JQuery+Dom4j

 * @author xx

 */

publicclass Two extends HttpServlet{

  public void doPost(HttpServletRequestrequest, HttpServletResponseresponse)

  throws ServletException,IOException{

  String result = "";

  //中文newString(b,0,len,"UTF-8")

  InputStreamin = request.getInputStream();

  //以下用dom4j解析

  SAXReadersax = new SAXReader();

  try {

  Document dom= sax.read(in);

  Element root = dom.getRootElement();

  Iterator<Element> it = root.elementIterator();

  while(it.hasNext()){

  String nm = it.next().getStringValue();

  System.err.println(nm);

  result+=nm;

  }

  } catch (Exception e) {

  throw new RuntimeException(e.getMessage(),e);

  }

  response.setContentType("text/html;charset=UTF-8");

  PrintWriterout = response.getWriter();

  //返回json數據

  out.print("{\"name\":\""+result+"\"}");

  }

}

WS Explorer工具的使用:- web服務瀏覽器









1、將wsdl文件,保存成本地一樣可以通過此工具訪問遠程服務。爲file:///D:/abc.xml







MyEclipse中調用WebService可以快速驗證你的服務器端程序,從而省去了自己書寫客戶端。

1:這是發出的消息格式:

<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:q0="http://itcast.com/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

-<soapenv:Body>

-<q0:sayHi>

 <arg0>zhangsan同學</arg0>

 </q0:sayHi>

 </soapenv:Body>

 </soapenv:Envelope>

2:以下是接收到的XML格式

<S:Envelopexmlns:S="http://schemas.xmlsoap.org/soap/envelope/">

-<S:Body>

-<ns2:sayHiResponse xmlns:ns2="http://itcast.com/">

 <return>你好:zhangsan同學,當前時間是:2011-05-07 10:15:20</return>

 </ns2:sayHiResponse>

 </S:Body>

 </S:Envelope>

3:上面的12就是SOAPSimpleObject Access Protocol)簡單對像訪問協議的格式。



1:我們已經說過了,WebService是通過向服務器發出XML格式的數據實現遠程調用,然後服務器也返回XML數據給客戶端,那麼這個XML是什麼格式的呢?

下面我將使用MyEclipse中的WebServiceExplorer工具向我們的WebService發起請求,並查看它的XML數據格式。

2:通過HttpWatchprofession Edition只可以看到獲取wsdl文檔的具體信息。

     且必須安裝HttpWatchprofession Edition版本的纔可以,如果是Basic版本的,將不會看到Stream(數據流)信息。

         














3、使用MyEclipseTCP/IPMonitor這個工具來查看具體的請求過程。

    TCP/IPMonitor不僅可以看到SOAP數據,還可以獲取HTTP請求和接收的頭信息。

    3.1、此工具位於:window>showview>other>MyEclipseCommon(常用工具)>TCP/IPMonitor

    3.2、此工具,相當於一個代理商,啓動後它將監聽本地的某個端口,然後再將請求轉發給指定的目標IP和端口。

          獲取到數據後,再將數據原封不動的返回給客戶。在客戶看來,永遠首先訪問的都應該是這個代理,否則

          我們將看不到數據傳輸的過程。

   3.3、配置選項:

           在打開的TCP/IPMonitor界面上:viewMenu(右上方向下的小箭頭)>Properties>Add(右側添加)

           設置成以下屬性:

           步1

    localmonitoring port(監聽本地的端口號)9876,隨意設置一個4位的端口號,一會將通過http://127.0.0.1:9876的形式訪問

           hostname(要監聽的服務器,如www.baidu.com):127.0.0.1因爲本機發布了一個WebService所以監聽本機IP.也可以是任意的主機。

           Port(要監聽的目標服務器的端口)6666  - 因爲我們發佈的WebServicehttp://127.0.0.1:6666/helloworld所以,6666是需要監聽的端口號。

           Type(監聽的類型)

  --TCP/IP :將使用原始地址繼續訪問下一個請求,如用戶輸入:http://127.0.0.1:9876/helloworld?wsdl此時將返回wsdl服務訪問地址同前。


        -- HTTP :將使用目標地址繼續訪問下一個請求。如用戶輸入: http://127.0.0.1:9876/helloworld?wsdl在請求方法時將使用http://127.0.0.1:6666/helloworld來訪問sayHi方法。此

種方式將不再會被代理。因爲已經不是正在監聽的端口號了。

          在監聽類型處,我們選擇TCP/IP

             建議同學們,將兩種方式都設置一下,然後通過在地址欄輸入:http://127.0.0.1:9876/helloworld?wsdl,在返回的wsdl文件中

             查看:<soap:addresslocation=http:……”/>處地址的變化情況。

         timeout:設置訪問不成功的連接時間,保持爲0,即不設置。


             在設置好後,點
OK按扭,然後再點右方的Start按扭,監聽便已經啓動。

         步2

          在MyEclipseWebService上配置WSDLURL爲:http://127.0.0.1:9876/helloworld?wsdl,注意使用的是MyEclipseTCP/IP Monitor的端口。而不是直接去訪問我們發佈的

http://127.0.0.1:6666/helloworld?wsdl

         

  在WebServiceExplorer上請求sayHi方法,傳遞參數,並查看http頭信息和發送及返回的xml信息。


         無論是MyEclipseWebServiceExplorer,Httpwatch,還是TCP/IPMonitor都是一些輔助工具。雖然對編寫代碼沒有什麼用處,但對我如何監控問題,發現問題的能力有所幫助。

更能從工具的使用中,發現代碼的問題進行調整或改進。











看董wsdl文件,能幫助我們順利弄清如何調用一個WebService,以及它有哪些類的哪些方法可以調用。


1SOAPBinding(style=Style.DOCUMENTStype.RPC)指定了消息的格式,即相互交流以語言。此值默認爲DOCUMENT。並在wsdl

件的soap:binding.type上出現。請大家注意觀察。


(目前我的使用的WebService規範是基於jax-ws的,而rpc是基於jax-rpc的,已經過時。)


以下是wsdl文檔的部分代碼:


<soap:bindingtransport="http://schemas.xmlsoap.org/soap/http"style="document"/>


Style指定了消息格式


Transport的最後部分指定了使用什麼樣的協議。此處定義爲http協議。


所以,binding部分,定義瞭如何調用,使用什麼樣的協議和消息格式,有什麼樣的方法可以調用。


portType又指定了一個可以調用的Java類,

請看本目錄下的wsdl文件的圖示說明!03_WSDL文件分析.bmp

--types定義了命名空間的信息,其中namespace是倒置的包名。


                                             schemaLocationxsd地址信息,可以拷貝此地址,並查看xsd的定義

開始的二行註釋是Jax-ws的版本,及是由哪個jdk生成的。






1、上面所有的內容,都是由系統發佈時自動生成的,那麼如何纔可以修改這個文檔呢?



修改wsdl文件的內容:


WSDL文件的內容,一般由服務默認生成,但爲了更好的向開發人員提供使用說明書,一般應做一些簡單的修改。至少不應該暴露我們的包結構。而targetNamespace默認情

況下爲倒置的包名,這已經暴露了我們的包結構。

通過在類文件上添加以下註解,可以修改wsdl生成的各元素,而不是直接去修改wsdl文件直接去修改wsdl文件是無

效的

WebService的註解包括:

@WebService-定義服務  --類上

@WebMethod-定義方法  - 方法

@WebResult-定義返回值 – 返回值

@WebParam-定義參數 – 參數 

1、另有:SOAPBinding-指定WebServiceSOAP協議的影射關係?


使用不同版本的Jdk對發佈ws的影響.


1.5不支持.

1.6.0_20前版本必須使用完整註解.

1.6.0_21以後可以只使用@WebService對類進行註解.

2、關於namespace約定名的說明,@WebService(targetNameSpace=..)

targetNamespace

定義導出的服務接口的名域(namespace),默認是倒置的服務接口Java包名。如demo.cxf.UserService的名域將會是http://cxf.demo/




1:WebService的註解都位於javax.jws包下。
     主要包含以下幾個註解(直接查看JDK文檔,關於它裏面的配置屬性也直接看JDK6的文檔。)
	我們只討論以下加個註解:
	WebMethod 	WebParam 	WebResult 	WebService

2:以下是加了註解的示例:
package com.itcast;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.jws.WebParam.Mode;
import javax.xml.ws.Endpoint;
/**
 * 一個加了很多註解的代碼
 */
@WebService(name="myName",//對應portType name="myName"
portName="myPort",  //對應服務中的port name="myPort"
serviceName="myService",//對應service name="myService"
targetNamespace="http://leaf.com/mynamespace")//可以隨意書寫類似於java中的package
public class HelloWorld{
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
@WebMethod(action="myAction",//定義一個soapAction="myAction"用於找到這個方法以執行
   operationName="myOperationName")//定義可以調用的方法,會生成相應類的具體方法,operation name=".."
public @WebResult(name="mySayHelloResult")String//定義返回值的名稱
sayHello(){
return "HelloWorld";
}
@WebMethod(action="mySayHiAction",operationName="mySayHiOperationName")
public @WebResult(name="mySayHiResult")String sayHi(@WebParam(name="myParaName",
//將參數放到頭信息中,用於保護參數,默認在body中
                                                      header=true,
  mode=Mode.IN)
String name){
String str = "你好:"+name+",當前時間是:"+sdf.format(new Date());
return str;
}

public static void main(String[] args) {
Endpoint.publish("http://127.0.0.1:6666/helloworld",new HelloWorld());
}
}


3:將上面的程序對外發布以後,我們通過MyEclipse的WebService Explorer來訪問
你會發現和以前不一樣的提示信息,但其實,仍然還是調用的那同一個方法。

4:請同學們在去觀察SOAP請求和返回文檔的修改。在MyEclipse WebService Explorer的返回信息窗口中點Soure即可以看到。觀察變化加以分析。

5:再次使用wsimport –s . http://127.0.0.1:6666/helloworld?wsdl生成java代碼然後調用,看看還是哪些類名嗎?
以下是調用代碼(可以用面目全非來形容,但完成的還是同樣的工作。)
package com.leaf.mynamespace;
public class Main {
public static void main(String[] args) {
//通過分析wsdl可知從myService中調用getMyPort返回myName
MyName myName = new MyService().getMyPort();
//通過myName的mySayHiOperationName來調用sayHi方法
String str = myName.mySayHiOperationName("王健");
System.err.println(str);
}
}












package cn.leaf.two;
import java.util.Date;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebResult;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;
/**
 * 發佈第一個web服務
 */
@WebService
(serviceName="WjService"//修改Service的名稱,即:new WjService();
 ,name="One"//定義Port名稱,即端口-new WjService().getOnePort();返回接口即One
 ,targetNamespace="http://wj.cn"//定義命名空間,默認爲倒置的包名
 ,portName="one"//定義獲取的方法,此值可以覆蓋name的定義,即port name="getOne"
)
public class OneService{
	@WebMethod(operationName="sayHello"//修改方法名
		      )
	public
	   @WebResult(name="ReturnMsg")
		String sayHi(
				@WebParam(name="yourName")
				String name){
		return name+",你好,現在時間是:"+new Date();
	}
	public static void main(String[] args) throws Exception {
		//發佈服務
		Endpoint ed= Endpoint.publish("http://127.0.0.1:9999/one",
					new OneService());
		System.err.println("服務發佈成功");
	}
}






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