Interaja com o Planilhas Google a partir de Java
1. Visão geral
O Planilhas Google oferece uma maneira conveniente de armazenar e manipular planilhas e colaborar com outras pessoas em um documento.
Às vezes, pode ser útil acessar esses documentos a partir de um aplicativo, por exemplo, para executar uma operação automatizada. Para esse fim, o Google fornece a API do Planilhas Google com a qual os desenvolvedores podem interagir.
Neste artigo,we’re going to take a look at how we can connect to the API and perform operations on Google Sheets.
2. Dependências do Maven
Para se conectar à API e manipular documentos, precisaremos adicionar as dependênciasgoogle-api-client,google-oauth-client-jettyegoogle-api-services-sheets:
com.google.api-client
google-api-client
1.23.0
com.google.oauth-client
google-oauth-client-jetty
1.23.0
com.google.apis
google-api-services-sheets
v4-rev493-1.23.0
3. Autorização
The Google Sheets API requires OAuth 2.0 authorization antes de podermos acessá-lo por meio de um aplicativo.
Primeiro, precisamos obter um conjunto de credenciais do OAuth e usá-lo em nosso aplicativo para enviar uma solicitação de autorização.
3.1. Obtenção de credenciais OAuth 2.0
Para obter as credenciais, precisaremos criar um projeto emGoogle Developers Console e, em seguida, ativar a API do Planilhas Google para o projeto. A primeira etapa no guiaGoogle Quickstart contém informações detalhadas sobre como fazer isso.
Depois de baixar o arquivo JSON com as informações de credencial, vamos copiar o conteúdo em um arquivogoogle-sheets-client-secret.json no diretóriosrc/main/resources do nosso aplicativo.
O conteúdo do arquivo deve ser semelhante a este:
{
"installed":
{
"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":"",
"redirect_uris":["urn:ietf:wg:oauth:2.0:oob","http://localhost"]
}
}
3.2. Obtendo um objetoCredential
Uma autorização bem-sucedida retorna um objetoCredential que podemos usar para interagir com a API do Planilhas Google.
Vamos criar uma classeGoogleAuthorizeUtil com um métodoauthorize() estático que lê o conteúdo do arquivo JSON acima e constrói um objetoGoogleClientSecrets.
Em seguida, criaremos umGoogleAuthorizationCodeFlowe enviaremos a solicitação de autorização:
public class GoogleAuthorizeUtil {
public static Credential authorize() throws IOException, GeneralSecurityException {
// build GoogleClientSecrets from JSON file
List scopes = Arrays.asList(SheetsScopes.SPREADSHEETS);
// build Credential object
return credential;
}
}
Em nosso exemplo, estamos definindo o escopoSPREADSHEETS, pois queremos acessar o Planilhas Google e usando umDataStoreFactory na memória para armazenar as credenciais recebidas. Outra opção é usarFileDataStoreFactory para armazenar as credenciais em um arquivo.
Para obter o código-fonte completo deGoogleAuthorizeUtil class,, verifiquethe GitHub project.
4. Construindo a instância de serviçoSheets
Para interagir com o Planilhas Google, precisaremos dea Sheets object which is the client for reading and writing through the API.
Vamos criar uma classeSheetsServiceUtil que usa o objetoCredential acima para obter uma instância deSheets:
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();
}
}
A seguir, daremos uma olhada em algumas das operações mais comuns que podemos realizar usando a API.
5. Escrevendo valores em uma folha
Interagir com uma planilha existente requer o conhecimento da id dessa planilha, que podemos encontrar em seu URL.
Para nossos exemplos, usaremos uma planilha pública chamada “Despesas”, localizada em:
Com base neste URL, podemos identificar o id desta planilha como “1sILuxZUnyl_7-MlNThjt765oWshN3Xs-PPLfqYe4DhI”.
Além disso,to read and write values, we’re going to use spreadsheets.values collections.
Os valores são representados como objetosValueRange, que são listas de listas deObjects, Java correspondentes a linhas ou colunas em uma planilha.
Vamos criar uma classe de teste onde inicializamos nosso objeto de serviçoSheets e uma constante 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();
}
}
Então, podemos escrever valores por:
-
escrevendo em um único intervalo
-
gravando em vários intervalos
-
anexando dados após uma tabela
5.1. Gravando em um único intervalo
Para escrever valores em um único intervalo em uma planilha, usaremos o métodospreadsheets().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();
}
Aqui, primeiro estamos criando um objetoValueRange com várias linhas contendo uma lista de despesas para dois meses.
Então, estamos usando o métodoupdate() para construir uma solicitação que grava os valores na planilha com o id fornecido, começando na célula “A1”.
Para enviar a solicitação, estamos usando o métodoexecute().
Se quisermos que nossos conjuntos de valores sejam considerados colunas em vez de linhas, podemos usar o métodosetMajorDimension(“COLUMNS”).
A opção de entrada "RAW" significa que os valores são escritos exatamente como são e não são computados.
Ao executar este teste JUnit,the application will open a browser window using the system’s default browser that asks the user to log in and give our application permission to interact with Google Sheets on the user’s behalf:
Observe que esta etapa manual pode ser ignorada se você tiver umOAuth Service Account.
A requirement for the application to be able to view or edit the spreadsheet is that the signed-in user has a view or edit access to it. Caso contrário, a solicitação resultará em um erro 403. A planilha que usamos para o nosso exemplo está definida como acesso público à edição.
Agora, se verificarmos a planilha, veremos que o intervalo “A1:B6” está atualizado com nossos conjuntos de valores.
Vamos continuar escrevendo para vários intervalos diferentes em uma única solicitação.
5.2. Gravando em vários intervalos
Se quisermos atualizar vários intervalos em uma planilha, podemos usar umBatchUpdateValuesRequest para melhor desempenho:
List 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();
Neste exemplo, estamos primeiro construindo uma lista deValueRanges,, cada uma composta por duas células que representam o nome do mês e as despesas totais.
Então, estamos criando umBatchUpdateValuesRequest comthe input option “USER_ENTERED”, as opposed to “RAW”, meaning the cell values will be computed based on the formula da adição de duas outras células.
Por fim, estamos criando e enviando a solicitaçãobatchUpdate. Como resultado, os intervalos “D1:E1” e “D4:E4” serão atualizados.
5.3. Anexando dados após uma tabela
Outra maneira de escrever valores em uma planilha é anexando-os ao final de uma tabela.
Para isso, podemos usar o métodoappend():
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");
Primeiro, estamos construindo o objetoValueRange contendo os valores da célula que queremos adicionar.
Em nosso caso, contém uma célula com as despesas totais para ambos os meses que encontramos adicionando os valores das células“E1”e“E2”.
Então, estamos criando uma solicitação que acrescentará os dados após a tabela que contém a célula “A1”.
A opçãoINSERT_ROWS significa que queremos que os dados sejam adicionados a uma nova linha e não substituam nenhum dado existente após a tabela. Isso significa que o exemplo gravará o intervalo “A7:B7” em sua primeira execução.
Em execuções subsequentes, a tabela que começa na célula“A1” agora será esticada para incluir a linha“A7:B7”, portanto, uma nova linha vai para a linha“A8:B8” e assim por diante.
Também precisamos definir a propriedadeincludeValuesInResponse como true se quisermos verificar a resposta a uma solicitação.. Como resultado, o objeto de resposta conterá os dados atualizados.
6. Lendo valores de uma folha
Vamos verificar se nossos valores foram escritos corretamente lendo-os da planilha.
Podemos fazer isso usando o métodospreadsheets().values().get() para ler um único intervalo ou o métodobatchUpdate() para ler vários intervalos:
List 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");
Aqui, estamos lendo os intervalos“E1”e“E4” e verificando se eles contêm o total de cada mês que escrevemos antes.
7. Criação de novas planilhas
Além de ler e atualizar valores, também podemos manipular planilhas ou planilhas inteiras usando coleçõesspreadsheets()espreadsheets().sheets().
Vejamos um exemplo de criação de uma nova planilha:
@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();
}
Aqui, primeiro estamos criando um objetoSpreadsheet com o título “MySpreadsheet”, em seguida, criando e enviando uma solicitação usando os métodoscreate()eexecute().
A nova planilha será privada e colocada no Drive do usuário conectado.
8. Outras operações de atualização
A maioria das outras operações tem a forma de um objetoRequest, que adicionamos a uma lista e usamos para construir um objetoBatchUpdateSpreadsheetRequest.
Vamos ver como podemos enviar duas solicitações para alterar o título de uma planilha e copiar e colar um conjunto de células de uma página para outra:
@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 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();
}
Aqui, estamos criando um objetoUpdateSpreadSheetPropertiesRequest que especifica o novo título, um objetoCopyPasteRequest que contém a origem e o destino da operação e, em seguida, adicionando esses objetos a umList deRequests.
Então, estamos executando as duas solicitações como uma atualização em lote.
Muitos outros tipos de solicitações estão disponíveis para uso de maneira semelhante. Por exemplo, podemos criar uma nova folha em uma planilha com umAddSheetRequest ou alterar os valores com umFindReplaceRequest.
Podemos realizar outras operações, como alterar bordas, adicionar filtros ou mesclar células. A lista completa de tipos deRequest está disponívelhere.
9. Conclusão
Neste artigo, vimos como podemos nos conectar à API do Planilhas Google a partir de um aplicativo Java e alguns exemplos de manipulação de documentos armazenados no Planilhas Google.
O código-fonte completo dos exemplos pode ser encontradoover on GitHub.