webservice呼叫和釋出
原文地址 :https://blog.csdn.net/xnf1991/article/details/52262135
1. 認識webservice
WebService定義: 顧名思義就是基於Web的服務。它使用Web(HTTP)方式,接收和響應外部系統的某種請求。從而實現遠端呼叫。
Webservice理解:我們可以呼叫網際網路上查詢天氣資訊Web服務,然後將它嵌入到我們的程式(C/S或B/S程式)當中來,當用戶從我們的網點看到天氣資訊時,他會認為我們為他提供了很多的資訊服務,但其實我們什麼也沒有做,只是簡單了呼叫了一下伺服器上的一段程式碼而已。WebSerice可以將你的服務(一段程式碼)釋出到網際網路上讓別人去呼叫,也可以呼叫別人機器上釋出的WebService,就像使用自己的程式碼一樣.。
2. Webservice呼叫
2.1webservice幾個名詞
名詞1:XML. Extensible Markup Language -擴充套件性標記語言
XML,用於傳輸格式化的資料,是Web服務的基礎。
namespace-名稱空間。
xmlns=“http://itcast.cn”使用預設名稱空間。
xmlns:itcast=“http://itcast.cn”使用指定名稱的名稱空間。
名詞2:WSDL – WebService Description Language – Web服務描述語言。
通過XML形式說明服務在什麼地方-地址。
通過XML形式說明服務提供什麼樣的方法 – 如何呼叫。
名詞3:SOAP-Simple Object Access Protocol(簡單物件訪問協議)
SOAP作為一個基於XML語言的協議用於有網上傳輸資料。
SOAP= 在HTTP的基礎上+XML資料。
SOAP是基於HTTP的。
SOAP的組成如下:
Envelope– 必須的部分。以XML的根元素出現。
Headers– 可選的。
Body– 必須的。在body部分,包含要執行的伺服器的方法。和傳送到伺服器的資料。
名詞4:UDDI (Universal Description, Discovery, and Integration) 是一個主要針對Web服務供應商和使用者的新專案。
在使用者能夠呼叫Web服務之前,必須確定這個服務內包含哪些商務方法,找到被呼叫的介面定義,還要在服務端來編制軟體,UDDI是一種根據描述文件來引導系統查詢相應服務的機制。
UDDI利用SOAP訊息機制(標準的XML/HTTP)來發布,編輯,瀏覽以及查詢註冊資訊。
它採用XML格式來封裝各種不同型別的資料,並且傳送到註冊中心或者由註冊中心來返回需要的資料。
2.2 webservice服務網址
Webservice服務網站:http://www.webxml.com.cn
2.3 WSDL解析
Wsdl文件從下往上讀
Types - 資料型別定義的容器,它使用某種型別系統(一般地使用XML Schema中的型別系統)。(入參和出參的資料型別)
Message - 通訊訊息的資料結構的抽象型別化定義。使用Types所定義的型別來定義整個訊息的資料結構(入參和出參)。
Operation - 對服務中所支援的操作的抽象描述,一般單個Operation描述了一個訪問入口的請求/響應訊息對(方法)。
PortType- 對於某個訪問入口點型別所支援的操作的抽象集合,這些操作可以由一個或多個服務訪問點來支援(服務類)。
Binding- 特定服務訪問點與具體服務類的繫結(不看內容,看關係)。
Port- 定義為webservice單個服務訪問點。
Service-相關服務訪問點的集合。
2.4生成客戶端程式碼方式呼叫webservice
1. wsimport是jdk自帶的,可以根據wsdl文件生成客戶端呼叫程式碼的工具.當然,無論伺服器端的WebService是用什麼語言寫的,都將在客戶端生成Java程式碼,伺服器端用什麼寫的並不重要。
3. wsimport.exe位於JAVA_HOME\bin目錄下.
常用引數為:-d<目錄> - 將生成.class檔案。預設引數。
• -s<目錄> -將生成.java檔案和class檔案。
• -p<生成的新包名> -將生成的類,放於指定的包下。
• (wsdlurl) - http://server:port/service?wsdl,必須的引數。
示例:
C:/> wsimport –s . http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?wsdl
4.注意:-s不能分開,-s後面有個小點,用於指定原始碼生成的目錄。點即當前目錄。
如果使用了-s引數則會在目錄下生成兩份程式碼,一份為.class程式碼。一份為.java程式碼。
.class程式碼,可以經過打包以後使用。.java程式碼可以直接Copy到我們的專案中執行。
呼叫webservice步驟
1) 開啟WSDL文件
2) 從下往上讀WSDL文件,先找到Services(服務訪問點集合),根據Services裡面binding屬性找到binding元素,再根據binding元素的type屬性找到繫結的portType(服務類)
3) 根據WSDL的地址生成客戶端程式碼wsimport -s . -p com.rl.trans d:/wsCode/EnglishChinese.wsdl
4) 把客戶端程式碼拷貝到專案中
5) 建立服務訪問點集合物件
6) 根據服務訪問點獲得服務類
7) 呼叫服務類的方法
3. jdk釋出webservice服務
注意:用Jdk1.6.0_21以後的版本釋出一個WebService服務.
說明: 在JDK1.6中JAX-WS規範定義瞭如何釋出一個webService服務。
JAX-WS是指Java Api for XML –WebService.
與Web服務相關的類,都位於javax.xml.ws.*包中。
主要類有:
a) @WebService - 它是一個註解,用在類上指定將此類釋出成一個webservice服務,如下所示:
@WebService
public class HelloServer {
/**
* 1.需要方法許可權是public
* 2.不能是final型別
* 3.方法不能是靜態的
* 4.服務類至少有一個方法
* @paramname
*@return
*/
@WebMethod(exclude=false)
public String sayHello(String name){
return name + " hello!";
}
@WebMethod(exclude=false)
public String sayBye(String name){
return name + " bye!";
}
}
b) Endpoint – 此類為端點服務類,它的方法publish用於將一個已經添加了@WebService註解物件繫結到一個地址的埠上。Endpoint是jdk提供的一個專門用於釋出服務的類,它的publish方法接收兩個引數,一個是服務的地址,二是提供服務的類。它位於javax.xml.ws.*包中。
static Endpoint.publish(String address,Object implementor) 在給定地址處針對指定的實現者物件建立併發布端點。
public static void main(String[] args) {
//jdk釋出webservice服務,第一個引數服務地址,第二個引數具體服務類
Endpoint.publish("http://127.0.0.1:8080/hello",new HelloServer());
}
stop方法用於停止服務。
其他注意事項:
1) 給類新增上@WebService註解後,類中所有的非靜態方法都將會對外公佈。不支援靜態方法,final方法。
2) 如果希望某個方法(非static,非final)不對外公開,可以在方法上新增@WebMethod(exclude=true),阻止對外公開。
3) 如果一個類上,被添加了@WebService註解,則必須此類至少有一個可以公開的方法,否則將會啟動失敗。
4) 服務類中不能沒有方法
5) @WebMethod(exclude=true)遮蔽方法
4.其他呼叫webservice的方式
4.1使用ajax+xml呼叫
var xhr;
function invoke(){
if(window.ActiveXObject){
xhr = new ActiveXObject("Microsoft.XMLHTTP");
}else{
xhr = new XMLHttpRequest();
}
//指定請求地址
var url ="http://127.0.0.1:7777/hello?wsdl";
//定義請求型別和地址和非同步
xhr.open("POST", url,true);
//設定Content-Type
xhr.setRequestHeader("Content-Type","text/xml;charset=UTF-8");
//指定回撥方法
xhr.onreadystatechange = back;
var textVal =document.getElementById("mytext").value;
//組裝訊息體的資料
var data = '<soapenv:Envelopexmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"xmlns:q0="http://server.hm.com/"xmlns:xsd="http://www.w3.org/2001/XMLSchema"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">'
+'<soapenv:Body>'
+'<q0:sayHello>'
+'<arg0>'+textVal+'</arg0>'
+'</q0:sayHello>'
+'</soapenv:Body>'
+'</soapenv:Envelope>';
xhr.send(data);
}
function back(){
if(xhr.readyState == 4){
if(xhr.status == 200){
var doc =xhr.responseXML;
alert(doc);
alert(xhr.responseText);
var tag =doc.getElementsByTagName("return")[0];
alert(tag)
}
}
}
4.2通過HttpURLConnection呼叫
//建立url地址
URL url = new URL("http://127.0.0.1:8080/hello?wsdl");
//開啟連線
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:Envelopexmlns: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:sayHello>"
+"<arg0>renliang</arg0>"
+"</q0:sayHello>"
+"</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());
}
5.複雜訊息請求
對於ajax和HttpURLConnection呼叫webservice有一個缺點是都需要自己來組裝訊息體,這對於複雜的web請求就比較麻煩,所以一般都會用生成客戶端程式碼的方式來呼叫webservice,下面是的例子是通過新增person這個實體物件來發送請求。
建立一個實體person:
public class Person {
private int id;
private Stringname;
private int age;
private Stringaddress;
get和set方法…
}
服務端程式碼:
@WebService
public class PersonServer {
List<Person> pList = new ArrayList<Person>();
/**
* 新增人
* @param person
*/
public void addPerson(Person person){
pList.add(person);
}
/**
* 獲得所有的人
* @return
*/
public List<Person> getPersonAll(){
return pList;
}
public static void main(String[] args) {
Endpoint.publish("http://127.0.0.1:6060/person",new PersonServer());
}
在F:/wsCode/生成客戶端程式碼:
wsimport–s . –p com.rl.person http://127.0.0.1:6060/person?wsdl
客戶端呼叫web服務:
public class TestPersonClient {
public static void main(String[] args) {
//建立服務訪問點集合
PersonServerService pss = new PersonServerService();
//根據服務訪問點獲得繫結的類
PersonServer server = pss.getPersonServerPort();
//呼叫具體業務邏輯
Person person = new Person();
person.setId(1);
person.setName("zhaoliu");
person.setAge(20);
person.setAddress("xiangyashan");
Person person1 = new Person();
person1.setId(2);
person1.setName("tianqi");
person1.setAge(25);
person1.setAddress("gaolaozhang");
//呼叫新增人的webservice服務方法
server.addPerson(person);
server.addPerson(person1);
//呼叫查詢所有人的webservice服務方法
List<Person> pList = server.getPersonAll();
for(Person p : pList){
System.out.println("id: "+p.getId()+" name:"+p.getName()+" age:"+p.getAge() + " address:"+p.getAddress());
}
}
6.wsdl文件元素名稱修改
自動生成的文件的名字有時不規範,可以手動進行修改。
@WebService(
portName="myHelloService",修改埠名字
serviceName="HelloServices",修改服務訪問點集合名字
name="HelloService",修改服務類的名字
targetNamespace="hello.test.com"修改名稱空間名字
)
@WebMethod(exclude=false)
public @WebResult(name="byeResult") String sayBye(@WebParam(name="personName ") String name){
return name +" bye!";
}
@WebResult(name="byeResult")修改返回值的元素的父標籤名字
@WebParam(name="personName")修改傳入引數的元素的父標籤名字