如何成功 运行 "Java Quickstart" 示例 Google 驱动器 API?

How to successfully run "Java Quickstart" sample for Google Drive API?

我按照 Google 的 Java Quickstart 指南尝试开发 Google 驱动器文件的搜索功能。在我执行 gradle -q rungradle run 命令后,它打开一个网页并显示 "Error: redirect_uri_mismatch" 消息。

错误信息:

代码如下:

package main.java;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
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;
import com.google.api.services.drive.model.FileList;

public class Quickstart {
    /** Application name. */
    private static final String APPLICATION_NAME = "Drive API Java Quickstart";

    /** Directory to store user credentials for this application. */
    private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),
            ".credentials/drive-java-quickstart");

    /** Global instance of the {@link FileDataStoreFactory}. */
    private static FileDataStoreFactory DATA_STORE_FACTORY;

    /** Global instance of the JSON factory. */
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    /** Global instance of the HTTP transport. */
    private static HttpTransport HTTP_TRANSPORT;

    /**
     * Global instance of the scopes required by this quickstart.
     *
     * If modifying these scopes, delete your previously saved credentials at
     * ~/.credentials/drive-java-quickstart
     */
    private static final List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY);

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

    /**
     * Creates an authorized Credential object.
     * 
     * @return an authorized Credential object.
     * @throws IOException
     */
    public static Credential authorize() throws IOException {
        // Load client secrets.
        InputStream in = Quickstart.class.getResourceAsStream("/client_secret.json");
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        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");
        System.out.println("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
        return credential;
    }

    /**
     * Build and return an authorized Drive client service.
     * 
     * @return an authorized Drive client service
     * @throws IOException
     */
    public static Drive getDriveService() throws IOException {
        Credential credential = authorize();
        return new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential).setApplicationName(APPLICATION_NAME).build();
    }

    public static void main(String[] args) throws IOException {
        // Build a new authorized API client service.
        Drive service = getDriveService();

        // Print the names and IDs for up to 10 files.
        FileList result = service.files().list().setPageSize(10).setFields("nextPageToken, files(id, name)").execute();
        List<File> files = result.getFiles();
        if (files == null || files.size() == 0) {
            System.out.println("No files found.");
        } else {
            System.out.println("Files:");
            for (File file : files) {
                System.out.printf("%s (%s)\n", file.getName(), file.getId());
            }
        }
    }
}

开发环境:

build.gradle 文件:

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

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

repositories {
    mavenCentral()
}

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

我的 Google 开发者控制台:

我应该怎么做才能成功 运行 gradle -q rungradle run 命令? 如何正确配置"Redirect_URI"?

基于此 thread, if you are using the Gradle Wrapper(Android Studio 中的推荐选项),您可以通过 运行 gradlew compileDebug --stacktrace 从命令行在您的根文件夹中启用堆栈跟踪项目(gradlew 文件所在的位置)。如果您不使用 gradle 包装器,则使用 gradle compileDebug --stacktrace 代替(大概)。有了这个,你就可以知道错误的根源了。

You don't really need to run with --stacktrace though, running gradlew compileDebug by itself, from the command line, should tell you where the error is.

您也可以 try cleaning your project 通过转到以下菜单项:Project > Clean... 如果这不起作用,请尝试从构建路径中删除 jars 然后重新添加它们。

补充:

如何正确配置“Redirect_URI”?

您可以检查这个 SO 线程:How to set redirect_uri in google developer console?

The redirect URI is an object only used by web applications that are doing oAuth2 authentication; so, when you create a new client ID, choose "web application" as the ID type and there will be a text area where you enter all of the allowed redirect URIs (these web pages will be coded by you, and will need to perform the function of doing the oauth2 ticket verification).

If your app is not a web application, you choose "installed application" as the type and you'll get a key that can be used in an Android/iOS/desktop app. However, this key will NOT be useable, at all, in a web application.

If your web application doesn't need to write any data or upload any files, you can create a public API key that you just include as a parameter with your requests.

Service accounts (which you're showing in the image above) are not compatible with the YouTube API.