Backend/개발

[Spring Boot] spread sheet 연동하기

지수쓰 2021. 7. 21. 01:32
반응형

TIL 29일차

TODO

구글 스프레드시트 파일 java api 찾아서 값 읽어오는거 구현하기

필요 배경

마요 대회때마다 구글 스프레드시트에 정리하시는데 구글에 들어가서 보는것 보다 홈페이지에서 확인하면 좋을 것 같다.

팀명, 팀코드, 팀원

대회 일정대회 결과

순위 등등
다 연동되게 하는것이 목표 ..!

저번에 하려는데 뭔가 자꾸 실패했음 ㅠ

일단 스프링말고라도 java api 찾아서 스프레드 시트 연동하기를 해봐야겠다.

 

  1. GCP api 라이브러리 google sheet api 활성화, drive api 활성화
  2. 사용자 인증 정보 - oauth2 클라이언트 id - 웹 클라이언
  3. 리다이렉션 주소는 /Callback
  4. 생성된 json파일 다운로드
  5. pom.xml에 디펜던시 추가 - 링크 참고
  6. 서비스 계정 생성 - sheet에 계정 권한 추가

 

@Value annotation

resoucre 폴더 하위에 application.property 또는 application.yml파일에 적은 property값을 불러온다.

# application.yml
  api:
    google:
      appName: mayo-sheet
  • import org.springframework.beans.factory.annotation.Value;
  • @Value("${api.google.appName}")

스프링 컨테이너 내부에서 빈을 등록할때 @Value()안에 맞는 값을 application.yml에서 찾아 넣어주기 때문에, bean으로 등록되지 않은 클래스에서 호출하면 null값이 들어올 수 있다.

@Value("${api.google.appName}")
private String appName;

@Test
public void sheet_테스트() {

assertThat(appName).isEqualTo("mayo-sheet");
}

간단하게 String appName=""으로 하드코딩 하지 않은 이유는 나중에 spreadsheet 이름이나 설정값이 달라질 때 yml파일만 바꿔주기 위함이고, 또한 public으로 올리면 안되는 정보가 있다면 비공개 yml파일에 값을 저장해 불러오면 보호되기 때문이다. 그리고 static 변수에는 value 값이 injection되지 않는다.
정 static으로 하고싶다면 클래스를 @Component로 bean으로 만든 후 setter를 이용해 주입하면 된다고 한다. - 블로그 내용 참고

여러 블로그 보면서 해도 이해가 잘 안돼서 그냥 공식 문서로 봤다.

 

Java Quickstart Sheets API

https://developers.google.com/sheets/api/quickstart/java

getcredential test

@Test
public void token_받아오기() throws IOException {
    File initialFile = new File("src/main/resources/" + CREDENTIALS_FILE_PATH);
    InputStream in = new FileInputStream(initialFile);

    if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
    }
    GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

    // Build flow and trigger user authorization request.
    GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
          new NetHttpTransport(), JSON_FACTORY, clientSecrets, SCOPES)
          .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
          .setAccessType("offline")
          .build();
    LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8080).build();
    Credential credential = new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");

    System.out.println(credential);
}

token이 받아와 만들어지는지 보기 위해 테스트코드로 먼저 돌려봤다. 맨 처음 코드를 실행하니 google login redirect url이 나왔다

그리고나서는 credential이 저장되어있어서 더이상 인증을 하지 않았다.
이 credential을 그대로 서버에 저장해도 되는건지, 매번 맨 처음에는 인증받는 화면을 보여줘야 사용할 수 있는건지 잘 모르겠다.

private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
private static final String TOKENS_DIRECTORY_PATH = "tokens";
private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS_READONLY);
  1. jacksonfactory
    JacksonFactory는 json 라이브러리를 구현하는 클래스다. getDefaultInstance는 글로벌 스레드 동기화가 된 인스턴스를 반환해준다
    [출처] Google Calendar API 1. 캘린더 정보 가져오기|작성자 혜영
  2. token
    /tokens 폴더에 StoredCredential파일이 생성됐다.

getCredential함수로 만들고 credential파일 경로가 잘못되거나 값이 잘못되었을 경우 에러가 나는지 확인해보았다.

json파일경로 잘못되었을 경우

@Test
public void getCredentialFile_error(){

    // given
    // 임의로 path 변경함
    CREDENTIALS_FILE_PATH +="aa";

    // when
    FileNotFoundException e = Assertions.assertThrows(FileNotFoundException.class,()->{
        new Sheets.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))
            .setApplicationName(appName)
            .build();
    });
    // then
    assertThat(e.getMessage()).contains("No such file or directory");

}

address in use

BindException이 생기는데 이유랑 해결방법을 잘 못찾겠다.

GCP default 뭐 어쩌고도 인텔리제이 팝업메세지로 뜨던데..
더찾아봐야겠다 2탄에 계쏙

마크다운 코드 하이라이트 적용해야겠다

출처
- @Value https://sas-study.tistory.com/273
- https://www.baeldung.com/convert-file-to-input-stream
- Value와 Static https://thingsthis.tistory.com/326
- Calendar정보 가져오기 jacksonfactory