目次
Java consuming SharePoint REST API
SharePoint2016オンプレ環境のREST APIと連携するJava Clientの実装例を紹介します。
SharePoint RESTサービスの概要
SharePoint 2016ではREST(REpresentational State Transfer)サービスを導入しています。
これにより開発者は、標準のREST Web要求をサポートするテクノロジを使用してSharePointデータとリモートで対話できるようになました。
つまり、クライアントアプリケーションからREST Webテクノロジと標準のOData(Open Data Protocol)構文を使用して、CRUD操作が実行できるようになりました。
SharePoint RESTサービスエンドポイントを決定する
SharePoint リソース用のRESTエンドポイントを作成するには、次の手順に従います。
1. REST サービスの参照から始めます。
http://<app site url>/_api
2. 適切なエントリポイントを指定します。 次にその例を示します。
http://<app site url>/_api/web
3. エントリポイントから、アクセスする特定のリソースに移動します。
これには、クライアントオブジェクトモデルのメソッドに対応するエンドポイントのパラメータの指定が含まれます。
次にその例を示します。
http://<app site url>/_api/web/lists/getbytitle('listname')
client.svcサービスの直接参照の代わりに_apiを使用する
SharePoint REST サービスのアーキテクチャ1)を見ると分かりますが、client.svcがREST サービスへの参照するURIを認識し受け入れます。
たとえば、http://<app site url>/_vti_bin/client.svc/web/lists でアクセスできます。
しかし、これに加え、後に説明するパラメーターが入ってくるとURLが長くなり、URL制限の256文字に引っかかります。
これを回避するために、_apiを使用してclient.svc web サービスを明示的に参照する必要性を取り除きます。
_apiを使用することで、URLを短縮し、残り部分を構築するために使用できる文字数を増やすことができます。
REST エンドポイント URIでパラメータを指定する
SharePointではOData仕様が拡張されており、かっこ()を使用してメソッドのパラメーターとインデックスの値を指定することができます。
複数のパラメーターを指定するには、次のように、名前と値をペアにしたパラメーターを指定し、各パラメーターをコンマで区切ります。
http://<app site url>/_api/web/getAvailableWebTemplates(lcid=1033, includeCrossLanguage=true)
context infoへのHTTP要求例
form digest value2)はcontext情報から取得可能です。
context情報のHTTP要求例を次に示します。
区分 | value |
---|---|
endpoint | http://<api site url>/_api/contextinfo |
HTTP method | POST |
HTTP header | content-type: application/json;odata=verbose |
accept: application/json;odata=verbose |
フォルダー作成のHTTP要求例
e-キャビネットにフォルダーを作成するHTTP要求例を次に示します。
区分 | value |
---|---|
endpoint | http://<api site url>/_api/web/folders/add('/document library relative url/folder name') |
HTTP method | POST |
HTTP header | content-type: application/json;odata=verbose |
accept: application/json;odata=verbose | |
X-RequestDigest: <form digest value> |
ここでdocument library relative url3)は<api site url>のhost対しての相対パスを指定します。
ドキュメント・ライブラリの指定フォルダーへファイル追加のHTTP要求例
あるドキュメント・ライブラリの指定フォルダーにファイルを追加するHTTP要求例を次に示します。
区分 | value |
---|---|
endpoint | http://<api site url>/_api/web/getfolderbyserverrelativeurl('/document library relative url/folder name')/files/add(overwrite=true, url='file name') |
HTTP method | POST |
HTTP header | content-type: multipart/form-data |
accept: application/json;odata=verbose | |
X-RequestDigest: <form digest value> |
REST Clientの実装概要
REST サービスへのHTTP要求/応答を実装するために、Spring-web及びApacheのhttpclientを利用します。
また、ResponseのJSONを解析するために、json-libを利用します。
その他、エンドポイントURLのエスケープにgoogleのguavaライブラリを、ロギングにslf4jを使っています。
必要ライブラリ
以下にREST Client実装で必要なライブラリを示します。
必要ライブラリをbuild-pathに追加してください。
ライブラリ | 説明 |
---|---|
httpclient-4.5.6.jar | Apache httpclient |
httpcore-4.4.10.jar | httpclientの依存ライブラリ |
commons-codec-1.10.jar | httpclientの依存ライブラリ |
logback-classic-1.2.3.jar | loggingライブラリ |
logback-core-1.2.3.jar | logback-classicの依存ライブラリ |
slf4j-api-1.7.25.jar | logback-classicの依存ライブラリ |
spring-core-4.3.18.RELEASE.jar | spring-webの依存ライブラリ |
spring-web-4.3.18.RELEASE.jar | spring-web |
spring-aop-4.3.18.RELEASE.jar | spring-webの依存ライブラリ |
spring-beans-4.3.18.RELEASE.jar | spring-webの依存ライブラリ |
spring-context-4.3.18.RELEASE.jar | spring-webの依存ライブラリ |
spring-expression-4.3.18.RELEASE.jar | spring-contextの依存ライブラリ |
guava-25.1-android.jar | google guava |
json-20210307.jar | JSON解析用ライブラリ |
SharePointService.java code snippet
SharePointServiceコードの一部を示します。
/** * return Form Digest value * @return Form Digest value */ public String getFormDigestValue() { String _output = ""; try { //endpoint String _endpoint = MessageFormat.format("{0}/_api/contextinfo", properties.getProperty("siteUrl")); //request entity RequestEntity<String> _requestEntity = RequestEntity .post(new URI(_endpoint)) .header("content-type", "application/json;odata=verbose") .header("accept", "application/json;odata=verbose") .body(null); RestTemplate _restTemplate = new RestTemplate(); _restTemplate.setRequestFactory(buildHttpComponentsClientHttpRequestFactory(properties.getProperty("username"), properties.getProperty("password"), properties.getProperty("host"), properties.getProperty("domain"))); ResponseEntity<String> _responseEntity = _restTemplate.exchange(_requestEntity, String.class); if (_responseEntity.getStatusCode() != HttpStatus.OK) { throw new RuntimeException("Failed : HTTP error code : " + _responseEntity.getStatusCode()); } logger.debug("response body=" + _responseEntity.getBody()); //parse json _output = RestResponseUtil.parseJsonDigestValue(_responseEntity.getBody()); } catch (Exception e) { logger.debug(e.getMessage(), e); }//try~catch return _output; } /** * Create a folder in the relative document library.<br> * * @param digestValue Form Digest value * @param folderName Folder name * @return relative folder path */ public String createEcabinetFolder(String digestValue, String folderName) { String _output = ""; try { //endpoint String _endpoint = MessageFormat.format("{0}/_api/web/folders/add(''/{1}/{2}'')", properties.getProperty("siteUrl"), properties.getProperty("libraryName"), folderName); //escape url String _requestUrl = UrlEscapers.urlFragmentEscaper().escape(_endpoint); logger.debug("endpoint=" + _requestUrl); //request entity RequestEntity<String> _requestEntity = RequestEntity .post(new URI(_requestUrl)) .header("content-type", "application/json;odata=verbose") .header("accept", "application/json;odata=verbose") .header("X-RequestDigest", digestValue) .body(null); RestTemplate _restTemplate = new RestTemplate(); _restTemplate.setRequestFactory(buildHttpComponentsClientHttpRequestFactory(properties.getProperty("username"), properties.getProperty("password"), properties.getProperty("host"), properties.getProperty("domain"))); ResponseEntity<String> _responseEntity = _restTemplate.exchange(_requestEntity, String.class); if (_responseEntity.getStatusCode() != HttpStatus.OK) { throw new RuntimeException("Failed : HTTP error code : " + _responseEntity.getStatusCode()); } logger.debug("response body=" + _responseEntity.getBody()); //parse json _output = RestResponseUtil.parseJsonServletRelativeUrl(_responseEntity.getBody()); } catch (Exception e) { logger.debug(e.getMessage(), e); }//try~catch return _output; } /** * Add a file to the folder in the relative document library.<br> * * @param digestValue * @param sourceUrl * @param folderName * @return relative file path */ public String addFileToEcabinet(String digestValue, String sourceUrl, String folderName) { String _output = ""; try { File _f = new File(sourceUrl); //endpoint String _endpoint = MessageFormat.format("{0}/_api/web/getfolderbyserverrelativeurl(''/{1}/{2}'')/files/add(overwrite=true, url=''{3}'')", properties.getProperty("siteUrl"), properties.getProperty("libraryName"), folderName, _f.getName()); //escape url String _requestUrl = UrlEscapers.urlFragmentEscaper().escape(_endpoint); logger.debug("endpoint=" + _requestUrl); //request entity RequestEntity<FileSystemResource> _requestEntity = RequestEntity .post(new URI(_requestUrl)) .contentType(MediaType.MULTIPART_FORM_DATA) .header("accept", "application/json;odata=verbose") .header("X-RequestDigest", digestValue) .contentLength(_f.length()) .body(new FileSystemResource(_f)); RestTemplate _restTemplate = new RestTemplate(); _restTemplate.setRequestFactory(buildHttpComponentsClientHttpRequestFactory(properties.getProperty("username"), properties.getProperty("password"), properties.getProperty("host"), properties.getProperty("domain"))); ResponseEntity<String> _responseEntity = _restTemplate.exchange(_requestEntity, String.class); if (_responseEntity.getStatusCode() != HttpStatus.OK) { throw new RuntimeException("Failed : HTTP error code : " + _responseEntity.getStatusCode()); } logger.debug("response body=" + _responseEntity.getBody()); //parse json _output = RestResponseUtil.parseJsonServletRelativeUrl(_responseEntity.getBody()); } catch (Exception e) { logger.debug(e.getMessage(), e); }//try~catch return _output; } /** * build HttpComponentsClientHttpRequestFactory<br> * * @param userName SharePoint userName * @param password SharePoint password * @param host Host * @param domain Domain * @return HttpComponentsClientHttpRequestFactory */ private HttpComponentsClientHttpRequestFactory buildHttpComponentsClientHttpRequestFactory(String userName, String password, String host, String domain) throws Exception { //create connection manager PoolingHttpClientConnectionManager _cm = new PoolingHttpClientConnectionManager(); _cm.setMaxTotal(128); _cm.setDefaultMaxPerRoute(24); //request configuration RequestConfig.Builder _requestBuilder = RequestConfig.custom().setConnectTimeout(5000).setSocketTimeout(10000); //build registry and register authentication to its registry Registry<AuthSchemeProvider> _authSchemeRegistry = RegistryBuilder.<AuthSchemeProvider>create() .register(AuthSchemes.NTLM, new NTLMSchemeFactory()) .register(AuthSchemes.SPNEGO, new SPNegoSchemeFactory()).build(); //create NTCredential CredentialsProvider _credentialProvider = new BasicCredentialsProvider(); _credentialProvider.setCredentials(AuthScope.ANY, new NTCredentials(userName, password, host, domain)); //create HttpClient HttpClientBuilder _builder = HttpClientBuilder.create() .setConnectionManager(_cm) .setDefaultRequestConfig(_requestBuilder.build()) .setDefaultAuthSchemeRegistry(_authSchemeRegistry) .setDefaultCredentialsProvider(_credentialProvider); HttpComponentsClientHttpRequestFactory _factory = new HttpComponentsClientHttpRequestFactory(_builder.build()); return _factory; }
reference
document library relative url = sites/qua-app/Test%20Data
※ ここで、%20は半角スペースを表します。(半角スペースをエスケープした形)
コメント