【Java】Google Drive APIでGoogle Driveに接続する方法

Agenda
更新日時

article_91_eye_catch

 

最近Google Drive APIを利用する機会があり、API利用までの手順がやや面倒でしたので、備忘録を兼ねてご紹介したいと思います。

プログラムのサンプルはJavaですが、基本はGoogleから提供されているサンプルがベースになります。

API利用までの事前準備は他の言語においても共通になりますので、他の言語を利用の方はGoogleで公開されているサンプルソースをもとにプログラム部分だけ差し替えて読んで頂ければ幸いです。

 


JavaでGoogle Driveへ接続するための事前準備


まずはGoogle Console画面でOAuth認証とGoogle Drive APIの利用登録が必要になります。

【Google Console】

https://console.developers.google.com/

Google APIs

 

「プロジェクトを作成」リンクからプロジェクトを作成します。

Google APIs New Project

 

プロジェクトを作成した後は、「認証情報を作成」からOAuthクライアントIDの作成を行います。

Google APIs Auth Top

 

OAuthクライアントIDを作成する前に同意画面の作成を行います。

Google APIs OAuth Client ID

 

同意画面の設定画面はGSuiteユーザの場合は内部を選択可能ですが、一般的なユーザの場合は外部のみ選択可能です。

OAuth Confirm View

 

同意画面の設定を行います。ひとまずアプリケーション名の設定のみ行います。

OAuth Config

 

同意画面の設定後は先ほどの「認証情報を作成」からOAuthアカウントの作成を行います。アプリケーションの種類は「その他」を選択します。

OAuth Client ID Create

 

OAuthクライアントを作成すると認証情報の一覧に作成したクライアントIDが表示されます。

Created OAuth Client ID

 

作成したクライアントIDをクリックすると詳細画面が表示されるので、詳細画面からJSONファイル(credentials.json)をダウンロードします。

OAuth Detail View

 

これでOAuth認証を利用する準備はできました。

続いて、Google Drive APIの利用を有効にします。「ライブラリ」からAPIライブラリ画面を開きます。

API Library Top

 

Google Drive APIを選択して有効にします。

Google Drive API

以上でJavaからAPIを利用するための準備ができました。

 


JavaでGoogle Driveへ接続する


Google Driveへ接続するにはGoogleから提供されているAPIクライアントを利用します。

サンプルは以下Webページで公開されています。

https://developers.google.com/drive/api/v3/quickstart/java

 

開発用ツールとしてeclipseなどをインストールし、Googleのサンプルと同じくGradleプロジェクトとして作成します。

build.gradleファイルは以下のように設定します。

apply plugin: 'java'
apply plugin: 'application'

mainClassName = 'Quickstart'
sourceCompatibility = 1.8
targetCompatibility = 1.8
version = '1.0'

repositories {
    mavenCentral()
}

dependencies {
    compile 'com.google.api-client:google-api-client:1.23.0'
    compile 'com.google.oauth-client:google-oauth-client-jetty:1.23.0'
    compile 'com.google.apis:google-api-services-drive:v3-rev110-1.23.0'
}

APIクライアントのバージョンは1.23.0を利用します。

最新版を利用した場合、Driveへ接続する際にエラーとなって接続できませんでした。日々バージョンも上がっておりますので、もしかしたら解消している可能性もありますが、1.23.0は問題なく接続できることを確認済みのため、ひとまずご紹介するバージョンでは1.23.0でご紹介します。

先ほど事前準備でダウンロードしたcredentials.jsonをGradleプロジェクトのsrc/main/resourcesの直下に配置します。

以下、Googleのサンプルを参考にGoogle Drive上にfilesフォルダを作成し、ユーザのホームディレクトリに予め用意したtest.pdfファイルをアップロードし、アップロードしたtest.pdfファイルをダウンロードするサンプルになります。

 

package Quickstart;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.FileContent;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;


public class Quickstart {

    private static final String APPLICATION_NAME = "Drive API Java Sample";
    private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"), ".credentials/drive-java-quickstart");
    private static FileDataStoreFactory DATA_STORE_FACTORY;
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static HttpTransport HTTP_TRANSPORT;
    private static final List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE);

    static {
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(1);
        }
    }

    public static Credential authorize() throws IOException {
        InputStream is = Quickstart.class.getResourceAsStream("/credentials.json");
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(is));

        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(DATA_STORE_FACTORY)
                .setAccessType("offline")
                .build();
        Credential credential = new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

        return credential;
    }

    public static Drive connectDrive() throws IOException {
        Credential credential = authorize();
        return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

    public static String createFolder(Drive service, String folderName) throws IOException {
        File fileMetadata = new File();
        fileMetadata.setName(folderName);
        fileMetadata.setMimeType("application/vnd.google-apps.folder");

        File file = service.files().create(fileMetadata)
                .setFields("id, name, webContentLink, webViewLink")
                .execute();

        return file.getId();
    }

    public static Map<String,String> upload(Drive service, String folderId, String filePath, String fileName, String mimeType) {
        Map<String,String> ret = null;

        try {
            File fileMetadata = new File();
            fileMetadata.setName(fileName);
            if (Objects.nonNull(folderId)) {
                fileMetadata.setParents(Collections.singletonList(folderId));
            }

            java.io.File localFilePath = new java.io.File(filePath);
            FileContent mediaContent = new FileContent(mimeType, localFilePath);

            File file = service.files().create(fileMetadata, mediaContent)
                    .setFields("id, name, webContentLink, webViewLink")
                    .execute();

            ret = new HashMap<String,String>();
            ret.put("id",file.getId());
            ret.put("name",file.getName());
            ret.put("webContentLink",file.getWebContentLink());
            ret.put("webViewLink",file.getWebViewLink());

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }

        return ret;
    }

    public static void download(Drive service, String fileId, String folderPath, String fileName) {
        java.io.File localFolderPath = new java.io.File(folderPath);
        if (!localFolderPath.exists()) {
            localFolderPath.mkdirs();
        }
        String filePath = "";
        if (Objects.equals(folderPath.substring(folderPath.length()-1),"/")) {
            filePath = folderPath + fileName;
        } else {
            filePath = folderPath + "/" + fileName;
        }
        java.io.File localFilePath = new java.io.File(filePath);
        try(OutputStream os = new FileOutputStream(localFilePath)) {

            service.files().get(fileId).executeMediaAndDownloadTo(os);
            os.flush();

        } catch (IOException e) {
            System.out.println(e.getMessage());
        }
    }

    public static void main(String[] args) throws IOException {
        Drive service = connectDrive();
        // create folder
        String folderId = createFolder(service, "files");
        // upload file
        Map<String, String> map = upload(service, folderId, System.getProperty("user.home") + "/test.pdf", "test_googledrive.pdf", "application/pdf");
        // download file
        download(service, map.get("id"), System.getProperty("user.home") + "/", "test_download.pdf");
    }

}

上記プログラムをGUI環境で実行します。eclipseで実行する場合は以下のようにプロジェクトを右クリックしてRun AsメニューからJava Applicationで実行することができます。(選択肢が表示されますので、Quickstartを選択します。)

java run

 

実行するとブラウザが起動して、ログイン画面が表示されます。

Google Login

 

権限付与の確認画面が表示されますので、権限付与を許可します。

Authority Dialog

 

選択内容の確認画面が表示されますので、許可ボタンをクリックします。

Access Confirm

 

ログイン後、StoredCredentialファイルがホームディレクトリの.credentials/drive-java-quickstartの直下に生成されます。

StoredCredential

 

次回以降のアクセスはcredentials.jsonファイルとStoredCredentialファイルがあれば認証可能になり、ブラウザが起動したり、ログインを求められることは無くなります。

ただし、権限変更を行う場合や認証情報(クライアントシークレット)を変更する場合は再度credentials.jsonファイルの取得とStoredCredentialファイルを取得する必要があります。

そのため、Google Drive APIを利用したシステムを作成する場合は、StoredCredentialファイル取得用に上記のようなサンプルプログラムを別プロジェクトのアプリケーションで用意しておくと良いと思います。

なお、StoredCredentialファイルを取得後は任意のディレクトリに配置して読み込むことが可能です。

サンプルプログラムのDATA_STORE_DIRにStoredCredentialファイルを配置したディレクトリへのパスを記述することで動作します。

Google Drive APIを利用したシステムを作成するには、サンプルプログラムのようなGoogle Driveへ接続するサービスを用意して、credentials.jsonをsrc/main/resourcesの直下に配置し、StoredCredentialファイルを特権ユーザのみアクセスできる任意のディレクトリに配置して利用します。

 


まとめ


JavaでGoogle Drive APIを利用するためには以下の手順が必要です。

(1) Google Console画面でプロジェクトを作成する。

(2) OAuth認証の同意画面を設定する。

(3) OAuth認証クライアントを作成する。

(4) OAuth認証クライアントからクライアントシークレット情報が記述されたJSONファイルをダウンロードする。

(5) Google APIライブラリからGoogle Drive APIの利用を有効にする。

(6) Googleが提供するサンプルソースをもとに初回認証を行い、トークンID、リフレシュトークンIDなどが記述されたStoredCredentialファイルを取得する。

以上です。

カテゴリ

コメント

コメント頂きありがとうございます。

Google Drive APIのアップロードファイルに付与できる属性をざっと確認いたしましたが、保存期間を設定できる項目は見当たりませんでした。

公式リファレンスは以下リンクから参照可能です。

https://developers.google.com/drive/api/v3/reference/files

しかしながら、Google Drive にアップロードしたファイルにはそれぞれ固有のIDが付与されておりますので、ローカルのシステム上でアップロードしたファイルをデータベース上で管理することで保存期間を管理することができると思います。

個々のファイルの保存期間を定期的にチェックするバッチ処理を作成し、保存期間を超えたものがあればGoogle Drive APIの削除リクエストを使ってファイルを削除する方法です。

結論から申し上げますと、読取専用にすることは可能です。

Permissionという属性を持たせることができるのですが、ユーザーすべて、あるいは特定ユーザーのみに作成者権限、編集者権限、読者権限といった形で付与ファイルの扱いを制限することが可能です。

 

詳細項目は公式リファレンスのPermissionを参照してください。

https://developers.google.com/drive/api/v3/reference/permissions

 

例えば、当該記事のサンプルにあわせて接続済みのDriveオブジェクトを引数にすると以下のようなサンプルになります。

Permissionに設定する属性を引数に渡せばもっと汎用的にPermissionの設定が可能になるかと思います。

 

public static void setPermissionsToFile(Drive service, String fileId) {
    try {
        JsonBatchCallback<Permission> callback = new JsonBatchCallback<Permission>() {
            @Override
            public void onFailure(GoogleJsonError e,
                HttpHeaders responseHeaders) throws IOException {
                    System.out.println(e.getMessage());
            }

            @Override
            public void onSuccess(Permission permission,
                HttpHeaders responseHeaders) throws IOException {
                    // Slf4jなどでログ出力
                    // log.info("Permission ID: {}", permission.getId());
            }
        };
        // すべてのユーザを読み取り専用にするサンプル
        // type : user, group, domain, anyone
        // role : owner=作者, writer=編集者, commenter=コメント付与可, reader=閲覧者
        BatchRequest batch = service.batch();
        Permission userPermission = new Permission()
            .setType("anyone")
            .setRole("reader")
            .setAllowFileDiscovery(false);
        service.permissions().create(fileId, userPermission)
            .setFields("id")
            .queue(batch, callback);
        batch.execute();
    } catch (IOException e) {
        System.out.println(e.getMessage());
    }
}

 

コメントを追加

CAPTCHA
画像CAPTCHA
画像内に表示されている文字列を入力してください。
This question is for testing whether or not you are a human visitor and to prevent automated spam submissions.