«1. Обзор
Google Sheets предоставляет удобный способ хранения электронных таблиц и управления ими, а также совместной работы над документом с другими пользователями.
Иногда бывает полезно получить доступ к этим документам из приложения, например, для выполнения автоматизированной операции. Для этой цели Google предоставляет API Google Sheets, с которым разработчики могут взаимодействовать.
В этой статье мы рассмотрим, как мы можем подключиться к API и выполнять операции в Google Таблицах.
2. Зависимости Maven
Для подключения к API и управления документами нам нужно добавить зависимости google-api-client, google-oauth-client-jetty и google-api-services-sheets: ~ ~~
<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. Авторизация
API Google Sheets требует авторизации OAuth 2.0, прежде чем мы сможем получить к нему доступ через приложение.
Сначала нам нужно получить набор учетных данных OAuth, а затем использовать их в нашем приложении для отправки запроса на авторизацию.
3.1. Получение учетных данных OAuth 2.0
Чтобы получить учетные данные, нам нужно создать проект в Google Developers Console, а затем включить API Google Таблиц для проекта. Первый шаг в руководстве Google Quickstart содержит подробную информацию о том, как это сделать.
После того, как мы загрузили файл JSON с учетными данными, давайте скопируем содержимое файла google-sheets-client-secret.json в каталог src/main/resources нашего приложения.
Содержимое файла должно быть примерно таким:
{
"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. Получение объекта учетных данных
Успешная авторизация возвращает объект учетных данных, который мы можем использовать для взаимодействия с API Google Таблиц.
Давайте создадим класс GoogleAuthorizeUtil со статическим методом authorize(), который считывает содержимое файла JSON выше и создает объект GoogleClientSecrets.
Затем мы создадим GoogleAuthorizationCodeFlow и отправим запрос на авторизацию. полученные полномочия. Другой вариант — использовать FileDataStoreFactory для хранения учетных данных в файле.
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;
}
}
Полный исходный код класса GoogleAuthorizeUtil см. в проекте GitHub.
4. Создание экземпляра сервиса Sheets
Для взаимодействия с Google Sheets нам понадобится объект Sheets, который является клиентом для чтения и записи через API.
Давайте создадим класс SheetsServiceUtil, который использует указанный выше объект Credential для получения экземпляра Sheets:
Далее мы рассмотрим некоторые из наиболее распространенных операций, которые мы можем выполнять с помощью API.
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();
}
}
5. Запись значений на лист
Взаимодействие с существующей электронной таблицей требует знания идентификатора этой электронной таблицы, который мы можем найти по ее URL-адресу.
Для наших примеров мы будем использовать общедоступную электронную таблицу под названием «Расходы», расположенную по адресу:
https://docs.google.com/spreadsheets/d/1sILuxZUnyl_7-MlNThjt765oWshN3Xs-PPLfqYe4DhI/edit# gid=0
На основе этого URL-адреса мы можем идентифицировать идентификатор этой электронной таблицы как «1sILuxZUnyl_7-MlNThjt765oWshN3Xs-PPLfqYe4DhI».
Кроме того, для чтения и записи значений мы будем использовать коллекции электронных таблиц.
Значения представлены в виде объектов ValueRange, которые представляют собой списки списков объектов Java, соответствующих строкам или столбцам на листе.
Давайте создадим тестовый класс, в котором мы инициализируем наш служебный объект Sheets и константу SPREADSHEET_ID:
Затем мы можем записать значения следующим образом:
public class GoogleSheetsLiveTest {
private static Sheets sheetsService;
private static String SPREADSHEET_ID = // ...
@BeforeClass
public static void setup() throws GeneralSecurityException, IOException {
sheetsService = SheetsServiceUtil.getSheetsService();
}
}
запись в один диапазон запись в несколько диапазонов добавление данных после таблица
-
5.1. Запись в один диапазон
Чтобы записать значения в один диапазон на листе, мы будем использовать метод электронных таблиц().values().update():
Здесь мы сначала создаем объект ValueRange с несколькими строками, содержащими список расходов за два месяца.
@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();
}
Затем мы используем метод update() для создания запроса, который записывает значения в электронную таблицу с заданным идентификатором, начиная с ячейки «A1».
«Чтобы отправить запрос, мы используем метод execute().
Если мы хотим, чтобы наши наборы значений рассматривались как столбцы, а не строки, мы можем использовать метод setMajorDimension(“COLUMNS”).
Опция ввода «RAW» означает, что значения записываются точно так, как они есть, а не вычисляются.
При выполнении этого теста JUnit приложение откроет окно браузера, используя системный браузер по умолчанию, который попросит пользователя войти в систему и дать нашему приложению разрешение на взаимодействие с Google Таблицами от имени пользователя:
Обратите внимание, что это руководство шаг можно пропустить, если у вас есть учетная запись службы OAuth.
Чтобы приложение могло просматривать или редактировать электронную таблицу, необходимо, чтобы у вошедшего в систему пользователя был доступ для просмотра или редактирования. В противном случае запрос приведет к ошибке 403. Электронная таблица, которую мы используем для нашего примера, настроена на общедоступный доступ для редактирования.
Теперь, если мы проверим электронную таблицу, мы увидим, что диапазон «A1: B6» обновлен нашими наборами значений.
Давайте перейдем к записи в несколько разрозненных диапазонов в одном запросе.
5.2. Запись в несколько диапазонов
Если мы хотим обновить несколько диапазонов на листе, мы можем использовать BatchUpdateValuesRequest для повышения производительности:
В этом примере мы сначала создаем список ValueRanges, каждый из которых состоит из из двух ячеек, которые представляют название месяца и общие расходы.
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();
Затем мы создаем BatchUpdateValuesRequest с параметром ввода «USER_ENTERED», а не «RAW», что означает, что значения ячеек будут вычисляться на основе формулы добавления двух других ячеек.
Наконец, мы создаем и отправляем запрос batchUpdate. В результате диапазоны «D1:E1» и «D4:E4» будут обновлены.
5.3. Добавление данных после таблицы
Другой способ записи значений на листе — добавление их в конец таблицы.
Для этого мы можем использовать метод append():
Сначала мы создаем объект ValueRange, содержащий значения ячеек, которые мы хотим добавить.
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");
В нашем случае это содержит ячейку с общими расходами за оба месяца, которые мы находим, складывая значения ячеек «E1» и «E2».
Затем мы создаем запрос, который добавит данные после таблицы, содержащей ячейку «A1».
Параметр INSERT_ROWS означает, что мы хотим, чтобы данные добавлялись в новую строку, а не заменяли какие-либо существующие данные после таблицы. Это означает, что пример запишет диапазон «A7:B7» при первом запуске.
При последующих запусках таблица, начинающаяся с ячейки «A1», теперь будет растягиваться, чтобы включить строку «A7: B7», поэтому новая строка переходит к строке «A8: B8» и т. д. .
Нам также нужно установить для свойства includeValuesInResponse значение true, если мы хотим проверить ответ на запрос. В результате объект ответа будет содержать обновленные данные.
6. Чтение значений с листа
Давайте проверим правильность записи наших значений, прочитав их с листа.
Мы можем сделать это, используя метод spreadsheets().values().get() для чтения одного диапазона или метод batchUpdate() для чтения нескольких диапазонов:
Здесь мы читаем диапазоны «E1» и «E4» и проверка того, что они содержат сумму за каждый месяц, которую мы написали ранее.
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");
7. Создание новых электронных таблиц
Помимо чтения и обновления значений, мы также можем манипулировать листами или целыми электронными таблицами с помощью наборов электронных таблиц() и электронных таблиц().sheets().
Давайте рассмотрим пример создания новой электронной таблицы:
Здесь мы сначала создаем объект электронной таблицы с заголовком «Моя таблица», затем строим и отправляем запрос с помощью функции create() и выполняем () методы.
@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();
}
Новая электронная таблица будет закрыта и размещена на Диске пользователя, вошедшего в систему.
8. Другие операции обновления
Большинство других операций принимают форму объекта Request, который затем добавляется в список и используется для создания запроса BatchUpdateSpreadsheetRequest.
Давайте посмотрим, как мы можем отправить два запроса на изменение заголовка электронной таблицы и копирование-вставку набора ячеек с одного листа на другой:
«
@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();
}
«Здесь мы создаем объект UpdateSpreadSheetPropertiesRequest, который указывает новый заголовок, объект CopyPasteRequest, который содержит источник и место назначения операции, а затем добавляем эти объекты в список запросов.
Затем мы выполняем оба запроса как пакетное обновление.
Многие другие типы запросов доступны для использования аналогичным образом. Например, мы можем создать новый лист в электронной таблице с помощью AddSheetRequest или изменить значения с помощью FindReplaceRequest.
Мы можем выполнять другие операции, такие как изменение границ, добавление фильтров или объединение ячеек. Полный список типов запросов доступен здесь.
9. Заключение
В этой статье мы увидели, как мы можем подключиться к API Google Sheets из приложения Java, и несколько примеров манипулирования документами, хранящимися в Google Sheets.
Полный исходный код примеров можно найти на GitHub.