Interagieren Sie mit Google Sheets über Java

1. Überblick

Google Sheets bietet eine bequeme Möglichkeit zum Speichern und Bearbeiten von Tabellenkalkulationen und zur Zusammenarbeit mit anderen Personen in einem Dokument.

Manchmal kann es nützlich sein, von einer Anwendung aus auf diese Dokumente zuzugreifen, um beispielsweise eine automatisierte Operation auszuführen. Zu diesem Zweck bietet Google die Google Sheets-API an, mit der Entwickler interagieren können.

In diesem Artikel werden wir einen Blick darauf werfen, wie wir eine Verbindung zur API herstellen und Vorgänge in Google Sheets ausführen können.

2. Abhängigkeiten von Maven

Um eine Verbindung zur API herzustellen und Dokumente zu bearbeiten, müssen Sie https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A%22google-api-client%22%20AND%20g hinzufügen % 3A% 22com.google.api-client% 22[Google-API-Client], google-oauth -client-jetty und google-api-services-sheets Abhängigkeiten:

<dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client</artifactId>
    <version>1.23.0</version>
</dependency>
<dependency>
    <groupId>com.google.oauth-client</groupId>
    <artifactId>google-oauth-client-jetty</artifactId>
    <version>1.23.0</version>
</dependency>
<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-sheets</artifactId>
    <version>v4-rev493-1.23.0</version>
</dependency>

3. Genehmigung

  • Die Google Sheets-API erfordert die Autorisierung von OAuth 2.0 ** , bevor wir über eine Anwendung darauf zugreifen können.

Zunächst müssen wir eine Reihe von OAuth-Anmeldeinformationen abrufen und diese dann in unserer Anwendung verwenden, um eine Autorisierungsanfrage zu senden.

3.1. OAuth 2.0-Berechtigungsnachweise abrufen

Um die Anmeldeinformationen zu erhalten, müssen Sie ein Projekt in der Google Developers Console erstellen und anschließend die Google Sheets-API für das Projekt aktivieren. Der erste Schritt im Handbuch Google Quickstart enthält detaillierte Informationen dazu.

Nachdem wir die JSON-Datei mit den Anmeldeinformationen heruntergeladen haben, kopieren wir den Inhalt in eine google-sheet-client-secret.json -Datei im Verzeichnis src/main/resources unserer Anwendung.

Der Inhalt der Datei sollte folgendermaßen aussehen:

{
  "installed":
    {
      "client__id":"<your__client__id>",
      "project__id":"decisive-octane-187810",
      "auth__uri":"https://accounts.google.com/o/oauth2/auth",
      "token__uri":"https://accounts.google.com/o/oauth2/token",
      "auth__provider__x509__cert__url":"https://www.googleapis.com/oauth2/v1/certs",
      "client__secret":"<your__client__secret>",
      "redirect__uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]    }
}

3.2. Ein Credential -Objekt erhalten

  • Eine erfolgreiche Autorisierung gibt ein Credential -Objekt zurück, mit dem Sie mit der Google Sheets-API interagieren können. **

Erstellen Sie eine GoogleAuthorizeUtil -Klasse mit einer statischen authorize () -Methode, die den Inhalt der obigen JSON-Datei liest und ein GoogleClientSecrets -Objekt erstellt.

Dann erstellen wir einen GoogleAuthorizationCodeFlow und senden die Autorisierungsanfrage:

public class GoogleAuthorizeUtil {
    public static Credential authorize() throws IOException, GeneralSecurityException {

       //build GoogleClientSecrets from JSON file

        List<String> scopes = Arrays.asList(SheetsScopes.SPREADSHEETS);

       //build Credential object

        return credential;
    }
}

In unserem Beispiel legen wir den Bereich SPREADSHEETS fest, da auf Google Sheets zugegriffen werden soll und ein in-memory DataStoreFactory zum Speichern der empfangenen Anmeldeinformationen verwendet werden soll. Eine andere Option ist die Verwendung einer FileDataStoreFactory zum Speichern der Berechtigungsnachweise in einer Datei.

Den vollständigen Quellcode von GoogleAuthorizeUtil cla____ss finden Sie unter https://github.com/eugenp/tutorials/tree/master/libraries [s GitHub-Projekt

4. Erstellen der Sheets Service-Instanz

Für die Interaktion mit Google Sheets benötigen wir ein Sheets -Objekt, das der Client zum Lesen und Schreiben über die API ist

Lassen Sie uns eine SheetsServiceUtil -Klasse erstellen, die das Objekt Credential oben verwendet, um eine Instanz von __Sheets abzurufen:

public class SheetsServiceUtil {
    private static final String APPLICATION__NAME = "Google Sheets Example";

    public static Sheets getSheetsService() throws IOException, GeneralSecurityException {
        Credential credential = GoogleAuthorizeUtil.authorize();
        return new Sheets.Builder(
          GoogleNetHttpTransport.newTrustedTransport(),
          JacksonFactory.getDefaultInstance(), credential)
          .setApplicationName(APPLICATION__NAME)
          .build();
    }
}

Im Folgenden werden einige der häufigsten Vorgänge beschrieben, die mit der API ausgeführt werden können.

5. Werte auf ein Blatt schreiben

Um mit einer vorhandenen Tabelle zu interagieren, müssen Sie die ID der Tabelle kennen, die wir über ihre URL finden können.

Für unsere Beispiele verwenden wir eine öffentliche Kalkulationstabelle mit dem Namen "Ausgaben".

Basierend auf dieser URL können wir die ID dieser Tabelle als "1sILuxZUnyl__7-MlNThjt765oWshN3Xs-PPLfqYe4DhI" identifizieren.

Zum Lesen und Schreiben von Werten verwenden wir spreadsheets.values Collections. **

Die Werte werden als ValueRange -Objekte dargestellt. Hierbei handelt es sich um Listen von Java- Objects-Listen, die Zeilen oder Spalten in einem Arbeitsblatt entsprechen.

Erstellen wir eine Testklasse, in der wir unser Sheets -Serviceobjekt und eine SPREADSHEET__ID-Konstante initialisieren:

public class GoogleSheetsIntegrationTest {
    private static Sheets sheetsService;
    private static String SPREADSHEET__ID =//...

    @BeforeClass
    public static void setup() throws GeneralSecurityException, IOException {
        sheetsService = SheetsServiceUtil.getSheetsService();
    }
}

Dann können wir Werte schreiben durch:

  • Schreiben in einen einzigen Bereich

  • Schreiben in mehrere Bereiche

  • Anhängen von Daten nach einer Tabelle

5.1. In einen einzelnen Bereich schreiben

Um Werte in einen einzelnen Bereich in einem Arbeitsblatt zu schreiben, verwenden wir die Methode spreadsheets (). Values ​​(). Update () :

@Test
public void whenWriteSheet__thenReadSheetOk() throws IOException {
    ValueRange body = new ValueRange()
      .setValues(Arrays.asList(
        Arrays.asList("Expenses January"),
        Arrays.asList("books", "30"),
        Arrays.asList("pens", "10"),
        Arrays.asList("Expenses February"),
        Arrays.asList("clothes", "20"),
        Arrays.asList("shoes", "5")));
    UpdateValuesResponse result = sheetsService.spreadsheets().values()
      .update(SPREADSHEET__ID, "A1", body)
      .setValueInputOption("RAW")
      .execute();
}

Hier erstellen wir zunächst ein ValueRange -Objekt mit mehreren Zeilen, das eine Aufwandsliste für zwei Monate enthält.

Dann verwenden wir die Methode update () , um eine Anforderung zu erstellen, die die Werte mit der angegebenen ID in die Kalkulationstabelle schreibt, beginnend bei der Zelle "A1".

  • Um die Anfrage zu senden, verwenden wir die Methode execute () . **

Wenn unsere Wertesätze als Spalten anstelle von Zeilen betrachtet werden sollen, können wir die setMajorDimension (“COLUMNS”) - Methode verwenden.

Die Eingabeoption „RAW“ bedeutet, dass die Werte genauso geschrieben werden wie sie sind und nicht berechnet werden.

Bei der Ausführung dieses JUnit-Tests öffnet ** die Anwendung ein Browserfenster mit dem Standardbrowser des Systems, in dem der Benutzer zur Anmeldung aufgefordert wird und unsere Anwendung die Berechtigung erhält, mit Google Sheets im Namen des Benutzers zu interagieren:

Beachten Sie, dass dieser manuelle Schritt umgangen werden kann, wenn Sie über ein https://developers.google.com/identity/protocols/OAuth2ServiceAccount [OAuth-Dienstkonto verfügen.

  • Damit die Anwendung die Tabelle anzeigen oder bearbeiten kann, muss der angemeldete Benutzer über eine Ansicht oder einen Bearbeitungszugriff darauf verfügen. Die Kalkulationstabelle, die wir für unser Beispiel verwenden, ist für den öffentlichen Bearbeitungszugriff festgelegt.

Wenn wir nun die Tabelle überprüfen, wird der Bereich " A1: B6 " mit unseren Wertemengen aktualisiert.

Lassen Sie uns in einer einzigen Anforderung in mehrere unterschiedliche Bereiche schreiben.

5.2. Schreiben in mehrere Bereiche

Wenn Sie mehrere Bereiche auf einem Arbeitsblatt aktualisieren möchten, können Sie BatchUpdateValuesRequest für eine bessere Leistung verwenden:

List<ValueRange> data = new ArrayList<>();
data.add(new ValueRange()
  .setRange("D1")
  .setValues(Arrays.asList(
    Arrays.asList("January Total", "=B2+B3"))));
data.add(new ValueRange()
  .setRange("D4")
  .setValues(Arrays.asList(
    Arrays.asList("February Total", "=B5+B6"))));

BatchUpdateValuesRequest batchBody = new BatchUpdateValuesRequest()
  .setValueInputOption("USER__ENTERED")
  .setData(data);

BatchUpdateValuesResponse batchResult = sheetsService.spreadsheets().values()
  .batchUpdate(SPREADSHEET__ID, batchBody)
  .execute();

In diesem Beispiel erstellen wir zunächst eine Liste von __ValueRanges, die jeweils aus zwei Zellen bestehen, die den Namen des Monats und die Gesamtausgaben darstellen.

Dann erstellen wir ein BatchUpdateValuesRequest mit der Eingabeoption "USER ENTERED", im Gegensatz zu "RAW", __ was bedeutet, dass die Zellenwerte basierend auf der Formel berechnet werden , indem zwei weitere Zellen hinzugefügt werden.

Schließlich erstellen und senden wir die batchUpdate -Anforderung. Daher werden die Bereiche " D1: E1 " und " D4: E4 " aktualisiert.

5.3. Daten nach einer Tabelle anhängen

Eine andere Möglichkeit, Werte in ein Blatt zu schreiben, besteht darin, sie am Ende einer Tabelle anzuhängen.

Dazu können wir die append () -Methode verwenden:

ValueRange appendBody = new ValueRange()
  .setValues(Arrays.asList(
    Arrays.asList("Total", "=E1+E4")));
AppendValuesResponse appendResult = sheetsService.spreadsheets().values()
  .append(SPREADSHEET__ID, "A1", appendBody)
  .setValueInputOption("USER__ENTERED")
  .setInsertDataOption("INSERT__ROWS")
  .setIncludeValuesInResponse(true)
  .execute();

ValueRange total = appendResult.getUpdates().getUpdatedData();
assertThat(total.getValues().get(0).get(1)).isEqualTo("65");

Zuerst erstellen wir das ValueRange -Objekt, das die Zellwerte enthält, die wir hinzufügen möchten.

In unserem Fall enthält diese eine Zelle mit den Gesamtkosten für beide Monate, die wir durch Addition der Zellwerte “E1” und “E2” ermitteln.

Dann erstellen wir eine Anfrage, die die Daten nach der Tabelle mit der Zelle " A1 " anfügt

Die Option INSERT ROWS bedeutet, dass die Daten zu einer neuen Zeile hinzugefügt werden sollen und keine vorhandenen Daten nach der Tabelle ersetzt werden sollen. Das bedeutet, dass das Beispiel beim ersten Durchlauf den Bereich „ A7: B7__“ schreibt.

Bei nachfolgenden Durchläufen wird die Tabelle, die an der Zelle "A1" beginnt, jetzt um die Zeile "A7: B7" erweitert, sodass eine neue Zeile in die Zeile "A8: B8" usw. verschoben wird .

Wir müssen auch die includeValuesInResponse -Eigenschaft auf true setzen, wenn wir die Antwort auf eine Anforderung überprüfen möchten _. _ Das Antwortobjekt enthält daher die aktualisierten Daten.

6. Werte aus einem Blatt lesen

Vergewissern Sie sich, dass unsere Werte richtig geschrieben wurden, indem Sie sie auf dem Blatt lesen.

  • Wir können dies tun, indem Sie die spreadsheets (). Values ​​(). Get () -Methode zum Lesen eines einzelnen Bereichs oder die batchUpdate () -Methode zum Lesen mehrerer Bereiche verwenden: **

List<String> ranges = Arrays.asList("E1","E4");
BatchGetValuesResponse readResult = sheetsService.spreadsheets().values()
  .batchGet(SPREADSHEET__ID)
  .setRanges(ranges)
  .execute();

ValueRange januaryTotal = readResult.getValueRanges().get(0);
assertThat(januaryTotal.getValues().get(0).get(0))
  .isEqualTo("40");

ValueRange febTotal = readResult.getValueRanges().get(1);
assertThat(febTotal.getValues().get(0).get(0))
  .isEqualTo("25");

Hier lesen wir die Bereiche "E1" und "E4" und überprüfen, ob sie die Summe für jeden Monat enthalten, den wir zuvor geschrieben haben.

7. Neue Tabellenkalkulationen erstellen

Neben dem Lesen und Aktualisieren von Werten können Sie auch Tabellen oder ganze Tabellenkalkulationen mithilfe der Sammlungen spreadsheets () und spreadsheets (). Sheets () bearbeiten.

Sehen wir uns ein Beispiel für das Erstellen einer neuen Tabelle an:

@Test
public void test() throws IOException {
    Spreadsheet spreadSheet = new Spreadsheet().setProperties(
      new SpreadsheetProperties().setTitle("My Spreadsheet"));
    Spreadsheet result = sheetsService
      .spreadsheets()
      .create(spreadSheet).execute();

    assertThat(result.getSpreadsheetId()).isNotNull();
}

Hier erstellen wir zuerst ein Spreadsheet -Objekt mit dem Titel „ My Spreadsheet“ , erstellen und senden dann eine Anfrage mit den create () - und execute () -Methoden.

Die neue Tabelle ist privat und wird auf dem angemeldeten Benutzerlaufwerk abgelegt.

8. Andere Aktualisierungsvorgänge

Die meisten anderen Vorgänge haben die Form eines Request -Objekts, das wir dann einer Liste hinzufügen und zum Erstellen eines BatchUpdateSpreadsheetRequest verwenden . **

Mal sehen, wie wir zwei Anfragen senden können, um den Titel einer Kalkulationstabelle zu ändern und einen Satz von Zellen von einem Blatt in ein anderes zu kopieren:

@Test
public void whenUpdateSpreadSheetTitle__thenOk() throws IOException {
    UpdateSpreadsheetPropertiesRequest updateSpreadSheetRequest
      = new UpdateSpreadsheetPropertiesRequest().setFields("** ")
      .setProperties(new SpreadsheetProperties().setTitle("Expenses"));

    CopyPasteRequest copyRequest = new CopyPasteRequest()
      .setSource(new GridRange().setSheetId(0)
        .setStartColumnIndex(0).setEndColumnIndex(2)
        .setStartRowIndex(0).setEndRowIndex(1))
      .setDestination(new GridRange().setSheetId(1)
        .setStartColumnIndex(0).setEndColumnIndex(2)
        .setStartRowIndex(0).setEndRowIndex(1))
      .setPasteType("PASTE__VALUES");

    List<Request> requests = new ArrayList<>();
    requests.add(new Request()
      .setCopyPaste(copyRequest));
    requests.add(new Request()
      .setUpdateSpreadsheetProperties(updateSpreadSheetRequest));

    BatchUpdateSpreadsheetRequest body
      = new BatchUpdateSpreadsheetRequest().setRequests(requests);

    sheetsService.spreadsheets().batchUpdate(SPREADSHEET__ID, body).execute();
}

Hier erstellen wir ein UpdateSpreadSheetPropertiesRequest -Objekt, das den neuen Titel angibt, ein CopyPasteRequest -Objekt, das die Quelle und das Ziel der Operation enthält, und fügen diese Objekte dann zu einer List von Requests

Dann führen wir beide Anforderungen als Stapelaktualisierung aus.

Viele andere Arten von Anforderungen stehen auf ähnliche Weise zur Verfügung.

Beispielsweise können wir ein neues Arbeitsblatt in einer Kalkulationstabelle mit einem AddSheetRequest erstellen oder Werte mit einem __FindReplaceRequest ändern.

Wir können andere Operationen ausführen, z. B. das Ändern von Rändern, das Hinzufügen von Filtern oder das Zusammenführen von Zellen. Die vollständige Liste der Request -Typen ist verfügbar: https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets/request#request [hier

9. Fazit

In diesem Artikel haben wir gesehen, wie wir über eine Java-Anwendung eine Verbindung zur Google Sheets-API herstellen können, und einige Beispiele für die Bearbeitung von in Google Sheets gespeicherten Dokumenten.

Den vollständigen Quellcode der Beispiele finden Sie auf GitHub unter https://github.com/eugenp/tutorials/tree/master/libraries.html .