[英]JAX-WS and SharePoint usergroup web service
我有一個小應用程序,它查詢我們的SharePoint服務器的Web服務接口,以獲取組的所有用戶的列表。 我可以看到原始HTTP響應將與列出的所有用戶一起返回,但JAX-WS響應對象(在NetBeans 6.9下創建)僅包含空白的Group Name String值。 HTTP響應中沒有所有用戶名的跟蹤。
任何人都知道為什么JAX-WS沒有正確讀取SOAP響應?
WSDL很長,但可以從各個位置廣泛訪問,包括這個站點: http : //www.hezser.de/_vti_bin/UserGroup.asmx?wsdl
這是原始HTTP響應的開始:
---[HTTP response - http://{server}/_vti_bin/usergroup.asmx - 200]---
null: HTTP/1.1 200 OK
Cache-control: private, max-age=0
Content-type: text/xml; charset=utf-8
Content-length: 136738
X-powered-by: ASP.NET
Server: Microsoft-IIS/6.0
Date: Wed, 22 Sep 2010 20:53:12 GMT
X-aspnet-version: 2.0.50727
Set-cookie: WSS_KeepSessionAuthenticated=80; path=/
Microsoftsharepointteamservices: 12.0.0.6303
<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetUserCollectionFromGroupResponse xmlns="http://schemas.microsoft.com/sharepoint/soap/directory/"><GetUserCollectionFromGroupResult><GetUserCollectionFromGroup><Users><User ID="201" Sid="S-1-5-21-1545385408-2720673749-3828181483-1245" ....
在生成存根之前,您需要手動編輯UserGroup.wsdl。 您需要將processContents='skip'
添加到定義響應的<s:any>
標記中。
<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<!-- Added the "processContents" attribute below -->
<s:any processContents='skip' />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
然后,在處理響應時,JAXB將子元素作為DOM元素返回:
UserGroup service = new UserGroup();
UserGroupSoap port = service.getUserGroupSoap();
GetUserCollectionFromGroupResult usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);
List<Object> content = usersCollection.getContent();
org.w3c.dom.Element usersElement = (org.w3c.dom.Element) content.get(0);
為什么會這樣
問題是由多種條件引起的:
<GetUserCollectionFromGroup>
:Web服務返回的響應包含<GetUserCollectionFromGroup>
標記:
<GetUserCollectionFromGroupResult>
<GetUserCollectionFromGroup>
<Users>
<User ID="4" Name="User1_Display_Name" />
<User ID="5" Name="User2_Display_Name" />
</Users>
</GetUserCollectionFromGroup>
</GetUserCollectionFromGroupResult>
B.嵌入在WSDL中的模式將<GetUserCollectionFromGroup>
定義為包含一個子組<groupName>
(這是用於發出請求的元素):
<s:element name="GetUserCollectionFromGroup">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="groupName" type="s:string"/>
</s:sequence>
</s:complexType>
</s:element>
C. JAXB尊重<xs:any>
的processContents
屬性(請參閱<xs:any />的Mapping )。 當processContents='strict'
,JAXB會嘗試根據子元素所屬的命名空間來匹配(和編組)子元素。
D. <GetUserCollectionFromGroupResult>
的WSDL模式定義包括<xs:any>
:
<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<s:any/>
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
E.省略processContents
,默認值為strict
。
因此,當JAX-WS / JAXB處理來自Web服務的結果時,它會嘗試使用模式對<GetUserCollectionFromGroupResult>
的子項進行編組。 子項在響應中顯示為與請求屬於同一名稱空間。 處理<GetUserCollectionFromGroup>
元素時,會將其編組為<GetUserCollectionFromGroup>
元素請求中使用的同一類的實例。 因此,您實際上無法訪問<Users>
元素。
我搜索過高和低,我能找到的唯一解決方案是以太(a)編輯WSDL,如本答案開頭所述,或(b)編輯生成的存根。 不理想,但在這種情況下不可避免。
有關<xs:any>
架構元素(以及processContents
屬性)的更多信息可以在MSDN上找到 。
您的問題有點難以回答,因為我們沒有看到您正在使用的生成的客戶端,也沒有看到調用時的調試/錯誤消息,但我會嘗試。 您的WSDL看起來有效,如果您的JAX-WS工具堆棧能夠創建客戶端(具有適當的Java類)並且能夠正確調用端點,那么您到目前為止表現良好。
查看HTTP響應和您的WSDL,您的SOAP請求是GetUserCollectionFromGroup調用。 看看GetUserCollectionFromGroupResponse的 XML-Schema定義(在WSDL中)我很困惑一件事:
<s:element name="GetUserCollectionFromGroupResponse">
<s:complexType>
<s:sequence>
<s:element minOccurs="0" maxOccurs="1" name="GetUserCollectionFromGroupResult">
<s:complexType mixed="true">
<s:sequence>
<s:any />
</s:sequence>
</s:complexType>
</s:element>
</s:sequence>
</s:complexType>
</s:element>
WSDL基本上說你的調用可以返回任何類型的XML。 你從webservice獲得的是一個XML片段,如:
<users><user ID="201" Sid="" /></users>
當然,這確實符合任何類型的XML的描述,但我認為您生成的客戶端無法理解它。 現在,我沒有使用NetBeans 6.9的jax-ws工具堆的經驗,但是你應該以這樣的方式配置WSDL到客戶端的生成,它將這個'any'轉換為java XML-Element或java XML-節點對象。
生成的此調用代碼是什么樣的? 它真的認為你得到一個String用戶嗎?
謝謝你的回復。 你是對的我應該發布生成的代碼,但調用和響應是如此簡單,我沒有想到它。 簡化了通話
System.setProperty("com.sun.xml.internal.ws.transport.http.client.HttpTransportPipe.dump", "true");
GetUserCollectionFromGroupResult usersCollection = null;
Object o = null;
UserGroup service = new UserGroup();
UserGroupSoap port = service.getUserGroupSoap();
usersCollection = port.getUserCollectionFromGroup(Settings.usersGroup);
返回的usersCollection只包含一個元素,即“groupName”,其值為“null”。
不幸的是,微軟似乎喜歡在幾乎所有的WSDL定義中使用ANY元素。 我有幾個工作,包括身份驗證,Web,列表,版本,但這個不會去。
我認為可以覆蓋默認的接收器代碼,但是今天早些時候我決定編寫自己的簡單SOAP客戶端可能更容易,而不是試圖找出修復JAX-WS接收器。 因此即使它可能不是最正確的方法,它也完成了工作。 這是所有恐怖的代碼。
我是Java的新手,所以對我很輕松;-)
HashMap<String, String> users = null;
String SOAPUrl = Settings.userListWebServiceURL;
String SOAPAction = "http://schemas.microsoft.com/sharepoint/soap/directory/GetUserCollectionFromGroup";
// Create the connection.
URL url = new URL(SOAPUrl);
URLConnection connection = url.openConnection();
HttpURLConnection httpConn = (HttpURLConnection) connection;
StringBuilder sb = new StringBuilder();
sb.append("<?xml version=\"1.0\" ?><S:Envelope xmlns:S=\"http://schemas.xmlsoap.org/soap/envelope/\"><S:Body><GetUserCollectionFromGroup xmlns=\"http://schemas.microsoft.com/sharepoint/soap/directory/\"><groupName>");
sb.append(Settings.usersGroup);
sb.append("</groupName></GetUserCollectionFromGroup></S:Body></S:Envelope>");
byte[] b = sb.toString().getBytes("UTF-8");
// Set the appropriate HTTP parameters.
httpConn.setRequestProperty("Content-Length", String.valueOf( b.length ) );
httpConn.setRequestProperty("Content-Type","text/xml; charset=utf-8");
httpConn.setRequestProperty("SOAPAction",SOAPAction);
httpConn.setRequestMethod( "POST" );
httpConn.setDoOutput(true);
httpConn.setDoInput(true);
// Everything's set up; send the XML that was read in to b.
OutputStream out = httpConn.getOutputStream();
out.write( b );
out.flush();
out.close();
// Setup to receive the result and convert stream to DOM Document
DOMParser parser = new DOMParser();
InputStreamReader in = new InputStreamReader(httpConn.getInputStream());
InputSource source = new InputSource(in);
parser.parse(source);
org.w3c.dom.Document d = parser.getDocument();
in.close();
httpConn.disconnect();
// Read the DOM and contruct a Hashmap with username to e-mail mapping.
NodeList nl = d.getElementsByTagName("User");
users = new HashMap<String, String>();
for (int i = 0; i < nl.getLength(); i++) {
NamedNodeMap attr = nl.item(i).getAttributes();
users.put(attr.getNamedItem("LoginName").getNodeValue(), attr.getNamedItem("Email").getNodeValue());
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.