4.2. WebService請求深入分析
1). 分析WebService的WSDL文檔結構
1.1). 實例截圖
<definitions>
<types>
<schema>
<element>
<message>
<portType>
<operation>
<input>
<output>
<binding>
<operation>
<input>
<output>
<service>
<port>
binding屬性
<address>
1.2). 文檔結構
<definitions>
<types>
<schema>
<element>
</types>
<message>
<part>
</message>
<portType>
<operation>
<input>
<output>
</portType>
<binding>
<operation>
<input>
<output>
</binding>
<service>
<port>
<address>
</service>
</definitions>
1.3). 文檔結構圖
1.4). 重要標簽的說明
- types - 數據類型(標簽)定義的容器,里面使用schema
- 定義了一些標簽結構供message引用
- 定義了一些標簽結構供message引用
- message - 通信消息的數據結構的抽象類型化定義。
- 引用types中定義的標簽
- 引用types中定義的標簽
- operation - 對服務中所支持的操作的抽象描述,
- 一個operation描述了一個訪問入口的請求消息與響應消息對。
- 一個operation描述了一個訪問入口的請求消息與響應消息對。
- portType - 對於某個訪問入口點類型所支持的操作的抽象集合,
- 這些操作可以由一個或多個服務訪問點來支持。
- 這些操作可以由一個或多個服務訪問點來支持。
- binding - 特定端口類型的具體協議和數據格式規范的綁定。
- service- 相關服務訪問點的集合
- port - 定義為協議/數據格式綁定與具體Web訪問地址組合的單個服務訪問點。
2). 測試CXF支持的數據類型
- 基本類型
– int,float,boolean等
- 引用類型
– String
– 集合:數組,List, Set, Map
– 自定義類型 Student
Jdk:不支持 map.
3). 一次Web service請求的流程
一次web service請求的本質:
1)客戶端向服務器端發送了一個soap消息(http請求+xml片斷)
2) 服務器端處理完請求后, 向客戶端返回一個soap消息
那么它的流程是怎樣的呢?
4.3. CXF框架的深入使用
1).CXF的攔截器
1.1) 理解
- 為什么設計攔截器?
- 為了在webservice請求過程中,能動態操作請求和響應數據, CXF設計了攔截器.
- 攔截器分類:
- 按所處的位置分:服務器端攔截器,客戶端攔截器
- 按消息的方向分:入攔截器,出攔截器
- 按定義者分:系統攔截器,自定義攔截器
- 攔截器API
Interceptor(攔截器接口)
AbstractPhaseInterceptor(自定義攔截器從此繼承)
LoggingInInterceptor(系統日志入攔截器類)
LoggingOutInterceptor(系統日志出攔截器類)
1.2) 編碼實現攔截器
- 使用日志攔截器,實現日志記錄
– LoggingInInterceptor
– LoggingOutInterceptor
- 使用自定義攔截器,實現用戶名與密碼的檢驗
– 服務器端的in攔截器
– 客戶端的out攔截器

1 服務端: 2 public class CheckUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> { 3 4 public CheckUserInterceptor() { 5 super(Phase.PRE_PROTOCOL); 6 } 7 8 @Override 9 public void handleMessage(SoapMessage msg) throws Fault { 10 Header header = msg.getHeader(new QName("thecheck")); 11 if(header != null){ 12 Element chenkEle = (Element) header.getObject(); 13 String username = chenkEle.getElementsByTagName("username").item(0).getTextContent(); 14 String password = chenkEle.getElementsByTagName("password").item(0).getTextContent(); 15 16 if("ymmm".equals(username) && "123456".equals(password)){ 17 System.out.println("Client de "+username+" 通過了 服務器的檢查"); 18 return; 19 } 20 } 21 System.out.println("client 沒有通過攔截器檢查"); 22 23 throw new Fault(new RuntimeException("請輸入正確的用戶名和密碼!!!")); 24 25 } 26 27 } 28 29 30 客戶端: 31 public class AddUserInterceptor extends AbstractPhaseInterceptor<SoapMessage> { 32 private String username; 33 private String password; 34 35 public AddUserInterceptor(String username , String password) { 36 super(Phase.PRE_PROTOCOL); 37 this.username = username; 38 this.password = password; 39 } 40 /* 41 <Envelope> 42 <head> 43 <chenkEle> 44 <name>xfzhang</name> 45 <password>123456</password> 46 </chenkEle> 47 <chenkEle2> 48 <name>xfzhang</name> 49 <password>123456</password> 50 </chenkEle2> 51 <head> 52 <Body> 53 <sayHello> 54 <arg0>BOB</arg0> 55 <sayHello> 56 </Body> 57 </Envelope> 58 */ 59 60 @Override 61 public void handleMessage(SoapMessage msg) throws Fault { 62 List<Header> list = msg.getHeaders(); 63 64 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 65 Document document; 66 try { 67 document = factory.newDocumentBuilder().newDocument(); 68 69 Element chenkEle = document.createElement("thecheck"); 70 71 Element usernameEle = document.createElement("username"); 72 usernameEle.setTextContent(username); 73 chenkEle.appendChild(usernameEle); 74 75 Element passwordEle = document.createElement("password"); 76 passwordEle.setTextContent(password); 77 chenkEle.appendChild(passwordEle); 78 79 list.add(new Header(new QName("thecheck"), chenkEle)); 80 } catch (ParserConfigurationException e) { 81 // TODO Auto-generated catch block 82 e.printStackTrace(); 83 } 84 } 85 }

1 public class TestService2 { 2 3 public static void main(String[] args) { 4 String address = "http://192.168.1.102:8787/webService_02_sayService/hellows"; 5 Endpoint publish = Endpoint.publish(address, new HelloWsImpl()); 6 EndpointImpl endImpl = (EndpointImpl) publish; 7 8 //添加日志入攔截器攔截器 9 List<Interceptor<? extends Message>> inList = endImpl.getInInterceptors(); 10 inList.add(new LoggingInInterceptor()); 11 inList.add(new CheckUserInterceptor()); 12 13 //添加日志出攔截器 14 List<Interceptor<? extends Message>> outIplm = endImpl.getOutInterceptors(); 15 outIplm.add(new LoggingOutInterceptor()); 16 17 18 System.out.println("發布 webService_01_cxf_sayService 成功"); 19 } 20 }

1 public class Test2 { 2 3 public static void main(String[] args) { 4 HelloWsImplService factory = new HelloWsImplService(); 5 HelloWs helloWs = factory.getHelloWsImplPort(); 6 7 Client client = ClientProxy.getClient(helloWs); 8 9 List<Interceptor<? extends Message>> outList = client.getOutInterceptors(); 10 outList.add(new AddUserInterceptor("ymmm", "123456")); 11 12 String string = helloWs.sayHello("cxf-client3 yyy"); 13 System.out.println(string); 14 } 15 }
2). 用CXF編寫基於spring的web service
2.1). 編碼實現
- Server端
– 創建spring的配置文件beans.xml,在其中配置SEI

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:jaxws="http://cxf.apache.org/jaxws" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> 8 <!-- 如果是低版本,還要引入更多文件 --> 9 <import resource="classpath:META-INF/cxf/cxf.xml" /> 10 <!-- 配置終端 --> 11 <jaxws:endpoint 12 id="orderWS" 13 implementor="com.ittest.servcie_02_cxf_.ws.OrderWsImpl" 14 address="/orderws" > 15 <!-- 配置攔截器 --> 16 <jaxws:inInterceptors> 17 <bean class="com.ittest.ws.interceptor.CheckUserInterceptor"></bean> 18 </jaxws:inInterceptors> 19 20 </jaxws:endpoint> 21 </beans>
– 在web.xml中,配置上CXF的一些核心組件

1 <context-param> 2 <param-name>contextConfigLocation</param-name> 3 <param-value>classpath:applicationContext.xml</param-value> 4 </context-param> 5 6 <listener> 7 <listener-class> 8 org.springframework.web.context.ContextLoaderListener 9 </listener-class> 10 </listener> 11 12 <servlet> 13 <servlet-name>CXFServlet</servlet-name> 14 <servlet-class> 15 org.apache.cxf.transport.servlet.CXFServlet 16 </servlet-class> 17 <load-on-startup>1</load-on-startup> 18 </servlet> 19 20 <servlet-mapping> 21 <servlet-name>CXFServlet</servlet-name> 22 <url-pattern>/*</url-pattern> 23 </servlet-mapping>
注意:各種cxf版本在配置xml的時候有區別( 在Cxf的高版本中要引入的其它文件較少 ).
- Client端
– 生成客戶端代碼
– 創建客戶端的spring配置文件beans-client.xml,並配置

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xmlns:jaxws="http://cxf.apache.org/jaxws" 5 xsi:schemaLocation="http://www.springframework.org/schema/beans 6 http://www.springframework.org/schema/beans/spring-beans.xsd 7 http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> 8 9 10 <jaxws:client id="orderClient" serviceClass="com.ittest.servcie_02_cxf_.ws.OrderWs" 11 address="http://localhost:8080/webService_02_cxf_sayService_spring/orderws" > 12 13 <!-- 添加攔截器 --> 14 <jaxws:outInterceptors> 15 <bean class="org.apache.cxf.interceptor.LoggingOutInterceptor"/> 16 <bean class="com.ittest.ws.client.intercepter.AddUserInterceptor"> 17 <constructor-arg name="username" value="ymmm"/> 18 <constructor-arg name="password" value="123456"/> 19 </bean> 20 </jaxws:outInterceptors> 21 22 </jaxws:client> 23 24 </beans>
– 編寫測試類請求web service

1 public class Test1 { 2 3 4 public static void main(String[] args) { 5 String path = "classpath:applicationContext.xml"; 6 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(path); 7 8 OrderWs orderWs = (OrderWs) applicationContext.getBean("orderClient"); 9 Order order = orderWs.getOrder(3); 10 System.out.println(order); 11 } 12 }
2.2). 添加自定義攔截器
- Server端
– 在beans.xml中,在endpoint中配置上入攔截器 (同上)
- Client端
– 通過Client對象設置出攔截器 (同上)
4.4. 其它調用WebService的方式
1). Ajax調用webService
跨域請求問題:
1. 什么是跨域請求? (jquery還要求都是 localhost)
1. sina.com--=->baidu.com/xxx.jsp
2. localhost----à192.168.42.165
2. 解決ajax跨域請求webservice的問題?
在客戶端應用中使用java編碼去請求webservice, 在頁面中去請求自己的后台
2). Jquery調用WebService
3). HttpURLConnection調用WebService
以上三個的代碼(一起):

1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 4 <html> 5 <head> 6 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 7 <title>Insert title here</title> 8 <script type="text/javascript" src="jquery-1.8.3.js" ></script> 9 <script type="text/javascript"> 10 11 $(document).ready(function(){ 12 13 $("#btn2").click(function(){ 14 var name = document.getElementById("name").value; 15 $.post( 16 "HttpURLConnectionServlet", 17 "name="+name, 18 function(msg){ 19 var $Result = $(msg); 20 var value = $Result.find("return").text(); 21 alert(value); 22 }, 23 "xml" 24 ); 25 }); 26 27 $("#btn1").click(function(){ 28 29 var name = document.getElementById("name").value; 30 var date = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Header><thecheck><username>ymmm</username><password>123456</password></thecheck></soap:Header><soap:Body><ns2:getOrder xmlns:ns2="http://ws.servcie_02_cxf_.ittest.com/"><arg0>3</arg0></ns2:getOrder></soap:Body></soap:Envelope>'; 31 alert(name+" "+date); 32 $.ajax({ 33 type : "POST", 34 url : "http://localhost:8080/webService_02_cxf_sayService_spring/orderws", 35 data : date, 36 success : function(msg){ 37 alert("------"); 38 var $Result = $(msg); 39 var value = $Result.find("return").text(); 40 alert(value); 41 }, 42 error : function(msg) { 43 //alert("-----"+msg); 44 }, 45 dataType : "xml" 46 }); 47 }); 48 }); 49 50 51 function reqWebService() { 52 53 var name = document.getElementById("name").value; 54 var date = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns2:sayHello xmlns:ns2="http://service.ws.ittest.com/"><arg0>' 55 + name + '</arg0></ns2:sayHello></soap:Body></soap:Envelope>'; 56 57 var xmlhttp = getRequest(); 58 alert("---"); 59 xmlhttp.onreadystatechange = function() { 60 if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 61 alert("前"); 62 var result = xmlhttp.responseXML; 63 alert("后"); 64 var returnEle = result.getElementsByTagName("return")[0]; 65 var vale = returnEle.firstChild.data; 66 alert(vale); 67 68 } 69 }; 70 71 xmlhttp.open("POST", 72 "http://192.168.1.102:8787/webService_02_sayService/hellows"); 73 74 xmlhttp.setRequestHeader("Content-type", 75 "application/x-www-form-urlencoded"); 76 77 xmlhttp.send(date); 78 79 } 80 81 function getRequest() { 82 var xmlhttp = null; 83 if (window.XMLHttpRequest) {// code for IE7+, Firefox, Chrome, Opera, Safari 84 xmlhttp = new XMLHttpRequest(); 85 } else {// code for IE6, IE5 86 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 87 } 88 return xmlhttp; 89 } 90 </script> 91 92 93 </head> 94 <body> 95 用戶名: 96 <input type="text" id="name" name="username" /> 97 <br /> 98 <div> 99 <button onclick="reqWebService()">使用Ajax連接 webservice</button></div> 100 <button id="btn1">使用JQuery鏈接webService</button> 101 <button id="btn2">使用Connection鏈接webService</button> 102 103 </body> 104 </html>

1 package com.ittest.servcie_02_cxf_.web; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 import java.io.OutputStream; 6 import java.net.HttpURLConnection; 7 import java.net.URL; 8 import java.net.URLConnection; 9 10 import javax.servlet.ServletException; 11 import javax.servlet.ServletOutputStream; 12 import javax.servlet.annotation.WebServlet; 13 import javax.servlet.http.HttpServlet; 14 import javax.servlet.http.HttpServletRequest; 15 import javax.servlet.http.HttpServletResponse; 16 17 import org.apache.jasper.tagplugins.jstl.core.Url; 18 19 import com.sun.jndi.toolkit.url.Uri; 20 21 /** 22 * Servlet implementation class HttpURLConnectionServlet 23 */ 24 @WebServlet("/HttpURLConnectionServlet") 25 public class HttpURLConnectionServlet extends HttpServlet { 26 private static final long serialVersionUID = 1L; 27 28 /** 29 * 跨域請求webService 30 */ 31 protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { 32 String name = request.getParameter("name"); 33 34 String path = "http://192.168.1.102:8787/webService_02_sayService/hellows"; 35 String data = "<soap:Envelope xmlns:soap='http://schemas.xmlsoap.org/soap/envelope/'><soap:Body><ns2:sayHello xmlns:ns2='http://service.ws.ittest.com/'><arg0>" 36 + name + "</arg0></ns2:sayHello></soap:Body></soap:Envelope>"; 37 38 URL url = new URL(path); 39 HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 40 connection.setRequestMethod("POST"); 41 connection.setDoOutput(true); 42 connection.setDoInput(true); 43 connection.setRequestProperty("Content-Type", "text/xml;charset=utf-8"); 44 45 OutputStream os = connection.getOutputStream(); 46 os.write(data.getBytes("utf-8")); 47 os.flush(); 48 49 int code = connection.getResponseCode(); 50 if(code==200){ 51 InputStream is = connection.getInputStream(); 52 53 response.setContentType("text/xml;charset=utf-8"); 54 ServletOutputStream outputStream = response.getOutputStream(); 55 56 int len=0; 57 byte[] buff = new byte[1024]; 58 59 while((len = is.read(buff))>0){ 60 outputStream.write(buff,0,len); 61 } 62 63 outputStream.flush(); 64 outputStream.close(); 65 } 66 } 67 }
4.5. 通過注解修改wsdl文檔
1). JDK中的相關注解
1.1). @WebService
l 作用在具體類上。而不是接口。 l 一個類只有添加了此注解才可以通過Endpoint發布為一個web服務。 l 一個添加了此注解的類,必須要至少包含一個實例方法。靜態方法和final方法不能被發布為服務方法。 l WebService注解包含以下參數:
|
1.2). @WebMethod
l 此注解用在方法上,用於修改對外暴露的方法。
|
1.3). @WebResult
用於定制返回值到WSDL的映射
|
1.4). @WebParam
用於定義WSDL中的參數映射
|
1.5). @XmlElement
用於定義實體類的屬性到WSDL中的映射(get/set方法上)
|
2). 說明
即使是沒有修改源代碼,只修改了注解,客戶端的代碼也必須要重新生成, 否則調用將會失敗。 |