不考慮第三方框架,如果只使用JDK提供的API,那么可以使用三種方式調用WebService服務;另外還可以使用Ajax調用WebService服務。
預備工作:開啟WebService服務,使用jdk命令wsimport生成調用源代碼
package com.kdyzm.ws; import javax.jws.WebService; import javax.xml.ws.Endpoint; @WebService public class MyWsServer { public String calculate(int input){ System.out.println("接收到請求數據:"+input); return input*input+""; } public static void main(String[] args) { Endpoint.publish("http://localhost:9090/ws", new MyWsServer()); System.out.println("server ready ......"); } }
生成源代碼命令:
wsimport -s . http://localhost:9090/ws?wsdl
可能出現的問題參考:http://blog.sina.com.cn/s/blog_924d6a570102w21v.html
因為出現了上述問題,所以本次測試環境使用jdk 1.7。
方法一:使用最簡單、效率最高的方法調用WebService服務
將生成的java文件包括文件夾直接導入項目,並使用其提供的API。
1 package com.kdyzm.call.method; 2 3 import com.kdyzm.ws.MyWsServer; 4 import com.kdyzm.ws.MyWsServerService; 5 6 /** 7 * 第一種方式就是使用wsimport命令獲取所有的需要調用的代碼,並直接使用這些代碼完成任務 8 * @author kdyzm 9 * 10 */ 11 public class Method1 { 12 public static void main(String[] args) { 13 MyWsServerService myWsServerService=new MyWsServerService(); 14 MyWsServer myWsServer=myWsServerService.getMyWsServerPort(); 15 String result=myWsServer.calculate(2); 16 System.out.println(result); 17 } 18 }
客戶端控制台打印結果:4
服務端控制台打印結果:
這種方式是使用最多的方式,也是最不容易出錯、效率最高的方式,推薦使用這種方式。
方法二:使用URLConnection調用WebService服務
URLConnection是JDK最底層的類,所有的網絡服務底層都要使用到該類,現在嘗試直接使用該類操作調用WebService服務的過程,但是首先需要獲取SOAL格式的請求體,可以使用之前介紹的Web Service Explorer瀏覽器捕獲請求體,並將該請求體進行處理轉換成字符串的格式(對"進行轉義\")。
使用這種方法不依賴於任何服務端提供的類和接口,只需要知道SOAP請求體的內容即可。
SOAL請求體:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:q0="http://ws.kdyzm.com/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <q0:calculate> <arg0>2</arg0> </q0:calculate> </soapenv:Body> </soapenv:Envelope>
轉換成String字符串:
1 String requestMessage = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " 2 + "xmlns:q0=\"http://ws.kdyzm.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 3 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<soapenv:Body>" + " <q0:calculate>" 4 + " <arg0>2</arg0>" + " </q0:calculate>" + "</soapenv:Body>" + "</soapenv:Envelope>";
測試代碼:
1 package com.kdyzm.call.method; 2 3 import java.io.BufferedReader; 4 import java.io.InputStream; 5 import java.io.InputStreamReader; 6 import java.io.OutputStream; 7 import java.io.PrintWriter; 8 import java.net.HttpURLConnection; 9 import java.net.URL; 10 11 /** 12 * 第二種方式是使用UrlConnecction調用WebService服務。 13 */ 14 public class Method2 { 15 public static void main(String[] args) throws Exception { 16 // 服務的地址 17 URL url = new URL("http://localhost:9090/ws"); 18 19 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 20 connection.setDoInput(true); 21 connection.setDoOutput(true); 22 23 connection.setRequestMethod("POST"); 24 connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8"); 25 OutputStream os = connection.getOutputStream(); 26 PrintWriter pw = new PrintWriter(os, true); 27 String requestMessage = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " 28 + "xmlns:q0=\"http://ws.kdyzm.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 29 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" + "<soapenv:Body>" + " <q0:calculate>" 30 + " <arg0>2</arg0>" + " </q0:calculate>" + "</soapenv:Body>" + "</soapenv:Envelope>"; 31 // 發起請求 32 pw.println(requestMessage); 33 34 InputStream is = connection.getInputStream(); 35 BufferedReader br = new BufferedReader(new InputStreamReader(is)); 36 String temp = null; 37 38 System.out.println("響應結果是:"); 39 while ((temp = br.readLine()) != null) { 40 System.out.println(temp); 41 } 42 pw.close(); 43 os.close(); 44 br.close(); 45 is.close(); 46 } 47 }
結果和方法一種的結果相同。
方法三:使用JDK提供的WebService相關API實現對WebService的服務調用
使用這種方法只需要一個接口:MyWsServer就可以了,該接口也是通過wsimport命令獲取的,它和服務端對應的服務類同名。
1 package com.kdyzm.call.method; 2 3 import java.net.URL; 4 5 import javax.xml.namespace.QName; 6 import javax.xml.ws.Service; 7 8 import com.kdyzm.ws.MyWsServer; 9 10 /** 11 * 第三種方式:通過客戶端編程實現Serice的遠程調用 12 * 使用這種方式只需要知道一個MyWsServer接口就可以了。 13 * @author kdyzm 14 * 15 */ 16 public class Method3 { 17 public static void main(String[] args) throws Exception { 18 URL url = new URL("http://localhost:9090/ws?wsdl"); 19 Service service=Service.create(url, new QName("http://ws.kdyzm.com/", "MyWsServerService")); 20 MyWsServer myWsServer=service.getPort(new QName("http://ws.kdyzm.com/", "MyWsServerPort"),MyWsServer.class); 21 String result=myWsServer.calculate(2); 22 System.out.println(result); 23 } 24 }
服務端和客戶端的控制台打印結果同上。
方法四:使用Ajax調用WebService服務
這里使用原生的js來操作該過程:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Insert title here</title> 6 <script type="text/javascript"> 7 function ajaxFunction() { 8 var xmlHttp; 9 try { 10 // Firefox, Opera 8.0+, Safari 11 xmlHttp = new XMLHttpRequest(); 12 } catch (e) { 13 // Internet Explorer 14 try { 15 xmlHttp = new ActiveXObject("Msxml2.XMLHTTP"); 16 } catch (e) { 17 18 try { 19 xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); 20 } catch (e) { 21 alert("您的瀏覽器不支持AJAX!"); 22 } 23 } 24 } 25 return xmlHttp; 26 } 27 </script> 28 </head> 29 <body> 30 <div id="content"></div> 31 <!-- 第四種方式:使用ajax的方式請求調用WebService服務 --> 32 <script type="text/javascript"> 33 var xmlHttp = ajaxFunction(); 34 var wsUrl = "http://localhost:9090/ws"; 35 var requestMessage = "<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" " 36 + "xmlns:q0=\"http://ws.kdyzm.com/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" " 37 + "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">" 38 + "<soapenv:Body>" 39 + " <q0:calculate>" 40 + " <arg0>2</arg0>" 41 + " </q0:calculate>" 42 + "</soapenv:Body>" 43 + "</soapenv:Envelope>"; 44 xmlHttp.open("POST", wsUrl, true); 45 xmlHttp.setRequestHeader("Content-Type", "text/xml;charset=utf-8"); 46 xmlHttp.onreadystatechange = _callback; 47 xmlHttp.send(requestMessage); 48 function _callback() { 49 if (xmlHttp.readyState == 4) { 50 if (xmlHttp.status == 200) { 51 var retXml = xmlHttp.responseXML; 52 var result = retXml.getElementsByTagName("return")[0]; 53 document.getElementById("content").innerHTML = result.firstChild.nodeValue;; 54 } 55 } 56 } 57 </script> 58 </body> 59 </html>
注意,result對象是[Object Element]類型的,需要調用.firstChild.nodeValue方法獲取文本值。
使用這種方式只適合在IE瀏覽器中使用,使用谷歌瀏覽器或者火狐瀏覽器都失敗了,出現的異常情況: xmlHttp.open("POST", wsUrl, true);這句代碼設置了請求方式是POST,但是實際上沒管用,請求方式變成了OPTION,statckOverFlow上有人解釋先使用OPTION的請求方式測試和服務器的連通性,然后才使用POST方式發送請求數據,所以服務器才會報出:
不管說法是否正確,該問題在這里暫時沒法解決,先存檔;在IE中運行正常:
服務器控制台打印結果同上。
注解
WebService的注解包括:@WebService,@WebMethod,@WebResult,@WebParam,具體使用方法見下圖
還有一個最重要的注解,使用該注解能夠將服務發布為符合SOAP1.2規范的WebService服務:
@BindingType(value=SOAPBinding.SOAP12HTTP_BINDING)
客戶端使用SOAP1.1可以正常調用服務端1.2的服務,但是反之則不行,所以最好將發布的服務都做成SOAP1.2的。