본문 바로가기
  • 실행력이 모든걸 결정한다
OpenAPI/OAuth

[OAuth] Google Calendar(4) - 내 서비스에 적용하기

by 김코더 김주역 2021. 8. 4.
반응형

들어가기 앞서...

Google Calendar(1)~(3)에 걸쳐 우리는 성공적으로 access_token을 얻어왔다.

다시 말하지만, access_token은 인증된 사용자를 식별하는 토큰이다.

 

이제 이 access_token을 이용하여 구글 캘린더 정보를 프로젝트의 콘솔상에 출력해볼 것이다.

 

필자는 SpringBoot - Maven 프로젝트를 사용했으며, Google API의 데이터 반환 형식은 기본적으로 JSON이기 때문에 JSON 데이터 파싱을 위한 라이브러리들도 프로젝트 내에 설치했다.

 

설치할 라이브러리들과 JSON 데이터 파싱 방법은 아래 포스팅에서 설명해두었으니 읽고 오는것을 권장한다.

https://kimcoder.tistory.com/333

 

[OpenAPI] 코로나 19 감염 현황(2) - 데이터 파싱

[예제 프로젝트 정보] Editor Program : IntelliJ Language : JAVA 1. 필요 라이브러리 JAVA 라이브러리를 쉽게 찾을 수 있는 사이트로, 필자가 개인적으로 강추한다. https://mvnrepository.com/ 1) 필요 라이브..

kimcoder.tistory.com

 

본 포스팅에서는 JSON 파싱보다는 구글 캘린더에 초점을 맞출 것이다.

 

 

 

1. 프로젝트 구성

 

 

 

2. HomeController 수정

CalendarList를 콘솔에 출력하기 위해 receiveAC 메소드의 내용을 수정했다.

access_token이 포함된 JSON 데이터를 소스 코드로 받아오는 과정은 RestJsonService에서 처리했고,

CalendarList JSON 데이터를 소스 코드로 받아오는 과정은 CalendarListService에서 처리했다.

package com.example.demo.controller;

import com.example.demo.service.CalendarListService;
import com.example.demo.service.RestJsonService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;

import org.json.JSONObject;
import org.json.JSONArray;

@Controller
public class HomeController {

    @GetMapping("/goocal")
    public String goocal(Model model){
        return "goocal";
    }

    @GetMapping("/receiveAC")
    public String receiveAC(@RequestParam("code") String code, Model model){
        RestJsonService restJsonService = new RestJsonService();
        String accessTokenJsonData = restJsonService.getAccessTokenJsonData(code);

        JSONObject accessTokenjsonObject = new JSONObject(accessTokenJsonData);

        String accessToken = accessTokenjsonObject.get("access_token").toString();
        System.out.println(accessToken);

        // Get CalendarList
        CalendarListService calendarListService = new CalendarListService();
        String calendarListJsonData = calendarListService.getCalendarList(accessToken);
        if(calendarListJsonData=="error") return "error";
        else System.out.println("CalendarList Json Data : " + calendarListJsonData);

        JSONObject calendarListJsonObject = new JSONObject(calendarListJsonData);
        JSONArray itemArr = (JSONArray) calendarListJsonObject.get("items");

        //결과 출력
        for(int i=0; i<itemArr.length(); i++){
            JSONObject item = (JSONObject)itemArr.get(i);
            System.out.println("Calender name"+" ("+item.get("id")+") : "+item.get("summary").toString());
        }
        
        return "success";
    }
}

 

 

 

3. RestJsonService

Spring Framework에서 제공하는 RestTemplate을 이용하면 URI 요청에 대한 응답 데이터를 바로 받을 수 있다.

요청 파라미터는 Map에 담아서 RestTemplate의 postForEntity() 메소드의 인자에 넣었다.

package com.example.demo.service;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;


public class RestJsonService {
    private final String CLIENT_ID = "499264841555-1kqekv3g1khc8jn5848cn1i8pcp12t29.apps.googleusercontent.com";
    private final String CLIENT_SECRET= "415QTI...생략";
    private final String REDIRECT_URI= "http://localhost:8080/receiveAC";
    private final String GRANT_TYPE= "authorization_code";
    private final String TOKEN_URL = "https://oauth2.googleapis.com/token";

    public String getAccessTokenJsonData(String code){
        RestTemplate restTemplate = new RestTemplate();

        Map<String, Object> params = new HashMap<>();
        params.put("code", code);
        params.put("client_id", CLIENT_ID);
        params.put("client_secret", CLIENT_SECRET);
        params.put("redirect_uri", REDIRECT_URI);
        params.put("grant_type", GRANT_TYPE);

        ResponseEntity<String> responseEntity =
                restTemplate.postForEntity(TOKEN_URL, params, String.class); // POST 방식으로 전송

        if (responseEntity.getStatusCode() == HttpStatus.OK) {
            return responseEntity.getBody(); // JSON 데이터 반환
        }
        return "error";
    }
}

 

 

 

 

4. CalendarListService

package com.example.demo.service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;

public class CalendarListService {
    private final String HTTP_REQUEST = "https://www.googleapis.com/calendar/v3/users/me/calendarList";

    public String getCalendarList(String accessToken){
        try {
            String jsonData = "";
			
            // URI를 URL객체로 저장
            URL url = new URL(HTTP_REQUEST + "?access_token=" + accessToken);
			
            // 버퍼 데이터(응답 메세지)를 한 줄씩 읽어서 jsonData에 저장
            BufferedReader bf;
            bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
            
            String line;
            while((line = bf.readLine()) != null){
                jsonData+=line;
            }
            
            return jsonData;

        } catch(Exception e) {
            return "error";
        }
    }
}

 

 

 

5. CalendarList 출력

access_token과 CalendarList가 원하는대로 잘 출력되었다.

캘린더의 상세 정보를 확인하기 위해서는 캘린더의 ID가 필요하다.

그래서 필자는 캘린더별 ID를 알기 위해 괄호 안에 ID를 출력시킨 것이다.

 

이제 캘린더 ID를 이용해서 상세 정보까지 출력해볼 것이다.

 

 

 

6. Events : list 문서 확인

Events : list 문서에서는 특정 캘린더의 일정 리스트들을 조회할 수 있는 방법을 안내한다.

필수 파라미터는 calendarId이며, calendarList에서 조회한 캘린더의 ID를 사용하면 된다고 명시되어있다.

그리고 유저의 기본 캘린더를 조회할 때는 calendarId 대신 "primary"를 써도 된다고 명시되어있다.(jooyeok42@naver.com, primary 둘다 사용 가능)

 

참고로 위 이미지에는 나와있지 않지만, access_token은 항상 요청 파라미터로 추가해줘야 한다.

 

 

 

7. HomeController 내용 추가

캘린더의 EventList JSON 데이터를 소스 코드로 받아오는 과정은 EventListService에서 처리했다.

package com.example.demo.controller;

import com.example.demo.service.CalendarListService;
import com.example.demo.service.EventListService;
import com.example.demo.service.RestJsonService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.json.JSONObject;

@Controller
public class HomeController {
    private final String ENCODED_HOLIDAY_CALENDAR_ID = "ko.south_korea%23holiday%40group.v.calendar.google.com";
    private final String ENCODED_BIRTHDAY_CALENDAR_ID = "addressbook%23contacts%40group.v.calendar.google.com";

    @GetMapping("/goocal")
    public String goocal(Model model){
        return "goocal";
    }

    @GetMapping("/receiveAC")
    public String receiveAC(@RequestParam("code") String code, Model model){
        RestJsonService restJsonService = new RestJsonService();
        String accessTokenJsonData = restJsonService.getAccessTokenJsonData(code);

        JSONObject accessTokenjsonObject = new JSONObject(accessTokenJsonData);

        String accessToken = accessTokenjsonObject.get("access_token").toString();
        System.out.println(accessToken);

        // Get CalendarList
        CalendarListService calendarListService = new CalendarListService();
        String calendarListJsonData = calendarListService.getCalendarList(accessToken);
        if(calendarListJsonData=="error") return "error";
        else System.out.println("CalendarList Json Data : " + calendarListJsonData);
        

        // Get EventList
        // Get Primary Calendar
        EventListService eventListService = new EventListService();
        String userJsonData = eventListService.getMyCalendar(accessToken, "primary");
        if(userJsonData=="error") return "error";
        else System.out.println("User Json Data : " + userJsonData);

        // Get Holiday Calendar
        String holidayJsonData = eventListService.getMyCalendar(accessToken, ENCODED_HOLIDAY_CALENDAR_ID);
        if(holidayJsonData=="error") return "error";
        else System.out.println("Holiday Json Data : " + holidayJsonData);

        // Get birthday Calendar
        String birthdayJsonData = eventListService.getMyCalendar(accessToken, ENCODED_BIRTHDAY_CALENDAR_ID);
        if(calendarListJsonData=="error") return "error";
        else System.out.println("Birthday Json Data : " + birthdayJsonData);

        return "success";
    }
}

 

 

 

8. EventListService

getMyCalendar() 메소드는 accessToken과 encodedCalendarId를 파라미터로 받는다.

package com.example.demo.service;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;


public class EventListService {
    private final String HTTP_REQUEST_PRE = "https://www.googleapis.com/calendar/v3/calendars/";
    private final String HTTP_REQUEST_POST = "/events";

    public String getMyCalendar(String accessToken, String encodedCalendarId){
        try {
            String jsonData = "";

            URL url = new URL(HTTP_REQUEST_PRE + encodedCalendarId + HTTP_REQUEST_POST +
                    "?access_token=" + accessToken
            );

            BufferedReader bf;
            bf = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));
            String line;
            while((line = bf.readLine()) != null){
                jsonData+=line;
            }

            return jsonData;

        } catch(Exception e) {
            return "error";
        }
    }
}

 

※ encode된 Calendar ID를 받는 이유

'#' 문자가 포함되어 있으면 URI 구조에 문제가 생겨서 요청 파라미터를 인식하지 못한다.

 

 

 

9. 실행 결과

CalendarList, EventList(User, Holiday, Birthday)에 대한 JSON 데이터를 모두 성공적으로 가져왔다.

 

JSON 데이터는 모두 한 줄로 출력되었지만, POSTMAN을 이용하면 JSON 데이터를 구조적으로 확인할 수 있다.

https://kimcoder.tistory.com/334?category=961979 

 

[OpenAPI] Postman 소개

https://www.postman.com/ 웹 개발을 할 때나 RESTAPI를 사용할 때 큰 도움이 되는 Postman을 소개한다. Postman은 개발한 API를 테스트하고, 테스트 결과를 공유하여 API 개발의 생산성을 높여주는 플랫폼이다..

kimcoder.tistory.com

 

이제는 여러분의 몫이다.

JSON 데이터에서 여러분이 원하는 데이터들의 구조적인 위치를 파악하고, 이에 알맞게 파싱해서 여러분이 원하는 방식으로 처리하면 된다.

 

반응형

댓글