繁体   English   中英

JAX-WS和SharePoint用户组Web服务

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM