본문 바로가기

테크 노트/소소한 개발 팁

java, google sheet api 이용하기

2019/03/12 - [개발이/개발노트] - java spring boot에서 google api 이용하기 (sheet, youtube 등) (2019 ver)

더 최신의 관련 정보를 알고싶으시면 윗 글을 참고해주세요.



1. 프롤로그 

서비스를 운영할때, 운영자(혹은 기획자)들이 쉽게 사용할 수 있도록 운영툴 "잘" 만들어주는것은 매우 귀찮은 일중에 하나이다.

그러나 이를 제대로 만들어 주지 않을 때는 기획자들의 요구에 따른 작업을 서버개발자가 항상 도와줘야 하므로

이는 더 큰 귀찮음을 낳게 된다. 따라서 운영툴.. 귀찮지만 더 안귀찮아 지려면 잘 만들놔야 한다.


우리회사의 기획자들은 엑셀에 능숙하다. 문서를 만들때도 엑셀, 일정을 짤 때도 엑셀, 자료 정리도 엑셀..

내가 운영툴에 부트스트랩으로 아무리 이쁘게 폼을 만들어도 기획자들에겐 사실 생소한 html덩어리들일 뿐이다.

따라서 운영툴에 값을 입력 하는 수단으로 google docs 의 스프레드시트를 연동하면 어떨까 하는 생각이 들었다.




2. 작업 착수 

구선생님께 물어보니 https://developers.google.com/google-apps/spreadsheets/ 이런 사이트를 바로 뱉어주었다.

일단 중간에 나와있는 예제코드를 보았다. (그냥 가장 길어서 왠지 걍 복붙하면 바로 툭 뭔가 뱉어줄것 같아서 긴 코드부터 복붙해봤다.)

대충 보니 예제코드가 많아서 복붙하면 일이 쉽게 끝나겠군.... 이라고 생각하는 찰나,

// TODO: Authorize the service object for  a specific user (see other sections)  라는 글귀가 눈에 들어왔다.

저 사이트엔 실제 문서를 조작하는 api 설명은 있지만, 사용자 인증과정에 대한설명이 없었다. 심지어 주석에 다른 섹션 보라고 무책임하게 써놨다.
(인증 코드가 있긴한데 .NET 코드 예제밖에 없다 -_-)

근데 (검색을 못해서인지, 영어를 못해서인지 모르겠지만) 아무리 찾아봐도 Google api 공식 사이트처럼 생긴 페이지들 안에서 oauth2 인증 코드 예시를 볼 수 없었다.

물론 직접 http request 만들어서 하라는대로 요청만 날려주면 되긴 한다. 그럼 access_token 이 어떻게든 오겠지.. 근데 이 방법이 맘에 들지 않았다.

결국 기나긴 삽질을 거쳐 스택오버플로우 형들의 도움을 받아 해답을 찾았다.





3. 준비 작업 

우선 https://console.developers.google.com 여기에 프로젝트가 생성되어 있다고 가정한다.

"API 및 인증" -> "사용자 인증 정보" 에서 왼편의 "새 클라이언트 ID 만들기"를 클릭한다.

뭐 이런 화면이 나타날텐데, 이때 "서비스 계정" 을 선택하고 "클라이언트 ID 만들기"를 클릭하여 완료한다.



그럼 이렇게 생성된 키를 볼 수 있게 된다. "새 P12키 생성" 을 클릭하여 키 파일을 다운받아 둔다.





4. 코딩! 

일단 코딩에 필요한 디펜던시들을 넣어보자

        <dependency>
            <groupId>com.google.gdata</groupId>
            <artifactId>core</artifactId>
            <version>1.47.1</version>
        </dependency>

        <dependency>
            <groupId>com.google.apis</groupId>
            <artifactId>google-api-services-oauth2</artifactId>
            <version>v1-rev88-1.19.1</version>
        </dependency>

한마디로 얘기하자면 위에꺼는 구글docs 데이터를 조작하기 위해서 쓰고, 아래꺼는 구글api  oauth 인증을 받기위해 쓴다.


import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.gdata.client.spreadsheet.SpreadsheetService;
import com.google.gdata.data.spreadsheet.SpreadsheetEntry;
import com.google.gdata.data.spreadsheet.SpreadsheetFeed;
import com.google.gdata.util.ServiceException;
import sun.rmi.rmic.iiop.ClassPathLoader;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.List;

public class OAuth2Sample {
    public static void main(String[] args) throws GeneralSecurityException, IOException, ServiceException {
        ClassLoader classloader = Thread.currentThread().getContextClassLoader();
        URL url = classloader.getResource("다운받은_키_파일.p12");
        final File file = new File(url.getFile());

        HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
        JsonFactory JSON_FACTORY = new JacksonFactory();

        Credential credential = new GoogleCredential.Builder().setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId("서비스계정생성 후에 발급된 이메일 주소") // 서비스 계정 생성 당시의 정보
                .setTokenServerEncodedUrl("https://accounts.google.com/o/oauth2/token")
                .setServiceAccountScopes(Arrays.asList("https://www.googleapis.com/auth/drive", "https://spreadsheets.google.com/feeds", "https://docs.google.com/feeds"))
                .setServiceAccountPrivateKeyFromP12File(file).build();

        // 버전이 v1부터 v3까지 있었는데 사실 그 차이에대해선 아직 알아보지못했다
        SpreadsheetService service = new SpreadsheetService("MySpreadsheetIntegration-v1");
        service.setOAuth2Credentials(credential); // 이거 하려고 위에 저렇게 코딩 한거다. 이게 인증의 핵심
        SpreadsheetFeed feed = service.getFeed(new URL("https://spreadsheets.google.com/feeds/spreadsheets/private/full"), SpreadsheetFeed.class);

        List<SpreadsheetEntry> spreadsheets = feed.getEntries();
        for (SpreadsheetEntry s : spreadsheets) {
            System.out.println(s.getTitle().getPlainText());
        }
    }
}

 

코드는 이게 끝이다. 데이터를 읽거나 쓰거나 하는 api 는 앞서 말했듯이

 https://developers.google.com/google-apps/spreadsheets/ 여기에 충분히 설명되어있으므로 생략.


무튼 이 예시는 접근가능한 스프레드시트의 타이틀을 모두 출력해주는 아주 간단한 예시이다.

컨텐츠 예시보다도 저 인증부분을 어떻게 해야 할지 몰라서 힘들었다. 사실 진짜 별거 아닌데 저게 어디 설명되어있는지 조차 모르겠어서 찾느라 힘들었다.

결론적으로, SpreadsheetService 의 setOAuth2Credentials(credential); 이놈만 잘 세팅하면 된다.

주의할 점은 Credential의 setServiceAccountId(); 이 메소드인데, 위에 서비스 계정 후 발급받은 "이메일 주소"를 입력해야 한다. ("클라이언트 ID"가 아니다)

그 외의 프로퍼티들은 저대로 해주면 문제 없을것 같다. scope라던가 기타 다른 사항들이 궁금하면 구선생님께 물어보면 금방 대답해줄것이다.


setServiceAccountPrivateKeyFromP12File(); 이 메소드를 이용해 다운로드받은 키 파일을 넣어주면 된다. 

나같은경우 spring 프레임워크의 resource 디렉토리에 키파일을 넣었는데

그러다보니 클래스패스에서 파일을 가져와서 로딩시키는 두줄짜리 작업을 하게 되었다. 

이것도 진짜 아무것도 아닌일인데 싱글턴으로 사용하기 위한 static 클래스에선 파일 로딩이 자꾸 안되는 일이 발생했다. 이거 찾는데도 시간을 뺏겼다.


SpreadsheetService service =  new SpreadsheetService("MySpreadsheetIntegration-v1");
service.setUserCredentials("구글계정아이디", "패스워드");

사실 oauth2 인증 안받고 하는 가장 쉬운 방법은 위와같은 방법이다. 걍 자기 아이디, 비번을 직접 코드에 때려박으면 된다.

그러나 내 아이디와 비번을 적고 전사 github에  푸시하는 짓은 안해야 할것 같아서..




5. 끝. 

api다루는거보다 인증하는게 더 힘들었다.. 아니 사실 코드 자체가 어렵진 않은데 저렇게 해야된다는 사실을 알게되기 까지가 어려웠다.

그리고 사담이지만.. 난 코드 예시를 볼때 import 가 생략된 코드를 보면 대체 뭘 import하라는지 모르겠는게 많아서 화가났었다.

그래서 뭘  import 해야할지 모두 기록해둘 생각이다..