如何使用Java上传文档到SharePoint?

17

我正在用Java创建一些大文件(数据库导出),我需要将它们放在我们的SharePoint服务器上。目前,我是用IE来做这件事,但我也想自动化这个步骤。

我搜索了互联网,找到了一些使用SOAP的提示,但我还没有真正看到所有这些的本质。有人能提供给我一些示例代码或指导我需要做什么吗?

请注意:SharePoint服务器要求进行NT域身份验证。我甚至无法使用Firefox登录: (

编辑

  • 如何将IE中可怕的URL转换为WebDAV路径?
  • 是否有一个WebDAV“浏览器”可以在我用代码毁掉生产系统之前使用?我尝试了来自http://www.davexplorer.org/的“DAV Explorer 0.91”,但那里无法连接(可能是因为NT域身份验证)。
6个回答

7
除了Sacha的建议,您还可以使用SharePoint SOAP Web服务。每个SharePoint站点都通过路径http://<Site>/_vti_bin/公开一堆Web服务。
在您的情况下,您可能需要列表Web服务http://<Site>/_vti_bin/Lists.asmx)。您可以从http://<Site>/_vti_bin/Lists.asmx?WSDL获取WSDL。WSS 3.0 SDK有关于如何使用Web服务的详细信息(您可能需要使用UpdateListItemsAddAttachment方法)。
尽管如此,假设您可以解决NTLM问题,Sacha的第一个选项(将文档库映射到驱动器)可能是最简单的方法。
如果您正在使用Windows,则可以简单地导航到文档库的UNC路径。例如,如果浏览器URL为您的文档库:

http://<Site>/Foo/BarDocs/Forms/AllItems.aspx

你可以直接在Windows资源管理器的地址栏中输入相应的UNC路径:\\<站点>\Foo\BarDocs,然后将文件拖放到此位置。如果需要,你可以使用Windows资源管理器或SUBST.EXE命令行实用程序将该位置映射到驱动器字母。

1
UNC不起作用;这个什么时候能用?我在XP上,但是我不知道使用的是哪个版本的SP。 - Aaron Digulla
WSDL下载可以正常工作,但是没有版本信息 :/ - Aaron Digulla
我意识到这已经相当晚了,但是UNC路径对我很有效。我能够使用该路径与Java的IO API一起直接将文档写入Sharepoint。+1 - RustyTheBoyRobot

6

好的...经过几个小时的工作和咬着微软提供的“文档”以及随机分布在网络上的所有提示,我成功地编写了一些示例代码来浏览SharePoint服务器的内容:使用Axis2浏览SharePoint文件夹

下一步:上传一些东西。


3

另一种解决方案是使用HTTP PUT方法直接将文件发送到Sharepoint。

为此,您可以使用Apache HTTP Client

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.2.3</version>
</dependency>

为了允许NTLMv2身份验证,您需要JCIF库。

<dependency>
   <groupId>jcifs</groupId>
   <artifactId>jcifs</artifactId>
   <version>1.3.17</version>
</dependency>

首先,我们需要编写一个包装器,以允许Apache HTTP Client使用JCIF来支持NTLMv2:

public final class JCIFSEngine implements NTLMEngine {

    private static final int TYPE_1_FLAGS =
            NtlmFlags.NTLMSSP_NEGOTIATE_56
            | NtlmFlags.NTLMSSP_NEGOTIATE_128
            | NtlmFlags.NTLMSSP_NEGOTIATE_NTLM2
            | NtlmFlags.NTLMSSP_NEGOTIATE_ALWAYS_SIGN
            | NtlmFlags.NTLMSSP_REQUEST_TARGET;

    @Override
    public String generateType1Msg(final String domain, final String workstation)
            throws NTLMEngineException {
        final Type1Message type1Message = new Type1Message(TYPE_1_FLAGS, domain, workstation);
        return Base64.encode(type1Message.toByteArray());
    }

    @Override
    public String generateType3Msg(final String username, final String password,
            final String domain, final String workstation, final String challenge)
            throws NTLMEngineException {
        Type2Message type2Message;
        try {
            type2Message = new Type2Message(Base64.decode(challenge));
        } catch (final IOException exception) {
            throw new NTLMEngineException("Invalid NTLM type 2 message", exception);
        }
        final int type2Flags = type2Message.getFlags();
        final int type3Flags = type2Flags
                & (0xffffffff ^ (NtlmFlags.NTLMSSP_TARGET_TYPE_DOMAIN | NtlmFlags.NTLMSSP_TARGET_TYPE_SERVER));
        final Type3Message type3Message = new Type3Message(type2Message, password, domain,
                username, workstation, type3Flags);
        return Base64.encode(type3Message.toByteArray());
    }
}

参考资料

执行HTTP PUT请求并进行身份验证的主要代码:

    try {

        HttpParams params = new BasicHttpParams();
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        DefaultHttpClient httpclient = new DefaultHttpClient(params);

        //Register JCIF NTLMv2 to manage ntlm auth.
        httpclient.getAuthSchemes().register("ntlm", new AuthSchemeFactory() {
            @Override
            public AuthScheme newInstance(HttpParams hp) {
                return new NTLMScheme(new JCIFSEngine());
            }
        });

        //Provide login/password
        httpclient.getCredentialsProvider().setCredentials(
                AuthScope.ANY,
                new NTCredentials([LOGIN], [PASSWORD], "", [DOMAIN]));
        //Create HTTP PUT Request       
        HttpPut request = new HttpPut("http://[server]/[site]/[folder]/[fileName]");
        request.setEntity(new FileEntity([File]));            

        return httpclient.execute(request);

    } catch (IOException ex) {
      //...
    }

能否使用HTTP PUT和overwrite=true选项来应用此解决方案? - Daniel Rodríguez

2

我使用这段代码成功地上传和下载文件到SharePoint,使用了集成的Windows身份验证,希望可以帮到你。

public class HttpClient {               
    HttpClient() { }

    public static void download(final String source, final File resultingFile) {
        CloseableHttpClient client = WinHttpClients.createSystem();
        HttpGet httpRequest = new HttpGet(source);

        CloseableHttpResponse httpResponse = null;      
        try {
            httpResponse = client.execute(httpRequest);
            HttpEntity entity = httpResponse.getEntity();

            if(httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
                LOGGER.warn(httpResponse.getStatusLine());
            }else {  
                LOGGER.debug(httpResponse.getStatusLine());
                FileUtils.touch(resultingFile);
                InputStream is = entity.getContent(); 
                File outFile = new File(resultingFile.getAbsolutePath());
                FileOutputStream fos = new FileOutputStream(outFile);

                int inByte;
                while ((inByte = is.read()) != -1) {
                    fos.write(inByte);
                }
                is.close();
                fos.close(); 
                client.close();
            }
        } catch (ClientProtocolException e) {
            LOGGER.warn(e);
        } catch (UnsupportedOperationException e) {
            LOGGER.warn(e);
        } catch (IOException e) {
            LOGGER.warn(e);
        }
    }


    public static void upload(final File source, final String destination) {    
        CloseableHttpClient httpclient = WinHttpClients.createSystem();
        HttpPut httpRequest = new HttpPut(destination);
        httpRequest.setEntity(new FileEntity(new File(source.getPath())));

        CloseableHttpResponse httpResponse = null;
        try {
            httpResponse = httpclient.execute(httpRequest);
            EntityUtils.consume(httpResponse.getEntity());

            if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) {
                LOGGER.debug(httpResponse.getStatusLine());
                LOGGER.info("Upload of " + source.getName() + " via HTTP-Client succeeded.");
            } else if (httpResponse.getStatusLine() != null && httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
                LOGGER.debug(httpResponse.getStatusLine());
            }else {
                LOGGER.warn("Uploading " + source.getName() + " failed.");
                LOGGER.warn(httpResponse.getStatusLine().getStatusCode() + ": " + httpResponse.getStatusLine().getReasonPhrase());
            }
        } catch (IOException e) {
            LOGGER.warn(e);
            LOGGER.warn(e.getMessage());
        }       
        return;
    }
}

WinHttpClients:

 <dependency>
     <groupId>org.apache.httpcomponents</groupId>
     <artifactId>httpclient-win</artifactId>
     <version>4.4</version>
 </dependency> 

路径:
org.apache.http.impl.client.WinHttpClients

描述:
默认配置为使用集成Windows身份验证的CloseableHttpClient实例的工厂方法。


这个检查会同时上传文件吗? - CodingOwl
这里使用了非标准类,如 WinHttpClients。请编辑您的答案并提及必要的依赖项。 - Aaron Digulla
1
是的,这会检查文件。 - go4X
1
你的代码最近帮了大忙,无论它是否对原始提问者有所帮助。我已经更新了依赖项,因为你发布的那个不起作用。 - JoshDM
我的工具的最新版本实际上使用了httpclient和httpclient-win v4.5.6。 - go4X

2

我认为我的方法可能会对你有所帮助。

最初,我创建了SharePoint帐户,并按照此链接中的过程进行操作(http://www.ktskumar.com/2017/01/access-sharepoint-online-using-postman/)以获取所需的REST API凭据。一旦我获得了凭据,我所需要的只是以下依赖项和代码:

<dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5</version>
</dependency>

由于我使用了OAUTH2身份验证,获取访问令牌的代码有助于其他CRUD操作。

/* OAuth2 authentication to get access token */
public String getSharePointAccessToken() throws ClientProtocolException, IOException
{
    /* Initializing variables */
    String grant_type = RcConstants.GRANT_TYPE;
    String client_id = RcConstants.CLIENT_ID;
    String client_secret = RcConstants.CLIENT_SECRET;
    String resource = RcConstants.RESOURCE;
    String url = RcConstants.OAUTH_URL + RcConstants.URL_PARAMETER + "/tokens/OAuth/2";

    /*
     * NOTE: RcConstants.OAUTH_URL =
     * https://accounts.accesscontrol.windows.net/ RcConstants.URL_PARAMETER
     * = Bearer Realm from
     * (http://www.ktskumar.com/2017/01/access-sharepoint-online-using-
     * postman/) Figure 6.
     */

    /* Building URL */
    HttpClient client = HttpClientBuilder.create().build();
    HttpPost post = new HttpPost(url);
    post.setHeader("Content-Type", "application/x-www-form-urlencoded");

    /* Adding URL Parameters */
    List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
    urlParameters.add(new BasicNameValuePair("grant_type", grant_type));
    urlParameters.add(new BasicNameValuePair("client_id", client_id));
    urlParameters.add(new BasicNameValuePair("client_secret", client_secret));
    urlParameters.add(new BasicNameValuePair("resource", resource));
    post.setEntity(new UrlEncodedFormEntity(urlParameters));

    /* Executing the post request */
    HttpResponse response = client.execute(post);
    logger.debug("Response Code : " + response.getStatusLine().getStatusCode());

    String json_string = EntityUtils.toString(response.getEntity());
    JSONObject temp1 = new JSONObject(json_string);  
    if (temp1 != null)
    {
        /* Returning access token */
        return temp1.get("access_token").toString();
    }
    return RcConstants.OAUTH_FAIL_MESSAGE;
}

获取访问令牌后,我们可以使用以下方法上传:

public String putRecordInSharePoint(File file) throws ClientProtocolException, IOException
{
    /* Token variable declaration */
    String token = getSharePointAccessToken();
    /* Null or fail check */
    if (!token.equalsIgnoreCase(RcConstants.OAUTH_FAIL_MESSAGE))
    { 
        /* Upload path and file name declaration */
        String Url_parameter = "Add(url='" + file.getName() + "',overwrite=true)";
        String url = RcConstants.UPLOAD_FOLDER_URL + Url_parameter;
        /*
         * NOTE: RcConstants.UPLOAD_FOLDER_URL =
         * https://<your_domain>.sharepoint.com/_api/web/
         * GetFolderByServerRelativeUrl('/Shared%20Documents/<FolderName>')/
         * Files/
         */

        /* Building URL */
        HttpClient client = HttpClientBuilder.create().build();
        HttpPost post = new HttpPost(url);
        post.setHeader("Authorization", "Bearer " + token);
        post.setHeader("accept", "application/json;odata=verbose");
        /* Declaring File Entity */
        post.setEntity(new FileEntity(file));

        /* Executing the post request */
        HttpResponse response = client.execute(post);
        logger.debug("Response Code : " + response.getStatusLine().getStatusCode());

        if (response.getStatusLine().getStatusCode() == HttpStatus.OK.value()|| response.getStatusLine().getStatusCode() == HttpStatus.ACCEPTED.value())
        {
            /* Returning Success Message */
            return RcConstants.UPLOAD_SUCCESS_MESSAGE;
        }
        else
        {
            /* Returning Failure Message */
            return RcConstants.UPLOAD_FAIL_MESSAGE;
        }
    }
    return token;
}

这个检查会同时上传文件吗? - CodingOwl
@MonkeyD.Luffy,在你分享的源代码中,“RcConstants”是什么?我可以理解它是一个Java类,其中包含所有常量。你能否举个例子,告诉我们在这个常量文件中应该保存什么内容?比如“GRANT_TYPE”和“RESOURCE”的值应该是什么? - Anurag_BEHS

2

我可以想到不同的选项:

  • 将文档库映射到文件驱动器并像文件系统中的任何其他文件一样保存文件。
  • 使用HTTP WebDAV协议。

...至于NTLM身份验证部分:

http://www.luigidragone.com/networking/ntlm.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接