인생 디벨로퍼

[Google API] 구글 캘린더 일정 List 불러오기 본문

JAVA Spring

[Google API] 구글 캘린더 일정 List 불러오기

뫄뫙뫄 2024. 11. 1. 11:42
728x90
반응형

참고

https://developers.google.com/calendar/api/quickstart/java?hl=ko

 

자바 빠른 시작  |  Google Calendar  |  Google for Developers

이 페이지는 Cloud Translation API를 통해 번역되었습니다. 의견 보내기 자바 빠른 시작 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 빠른 시작에서는 Google Work

developers.google.com


1. 기본 세팅

client_secret 어쩌구 .json 파일을 src/main/resources/ 에 저장 

=>파일명  credentials.json 변경

 

그래들 추가

dependencies {
	implementation 'com.google.api-client:google-api-client:2.0.0'
	implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1'
	implementation 'com.google.apis:google-api-services-calendar:v3-rev20220715-2.0.0'
}

사이트 플로우 설명 잠깐!

로그인 할때 구글 인증 받기 -> 메인페이지 로드될때 캘린더 list 불러오기 

해당 사이트는 유저 권한에 따라 이동 페이지가 다르게 나눠뒀기 때문에
메인 페이지 접근이 가능한 유저만 구글 인증 로직을 타게 했다

해당 로직을 실행 하면
oAuth 인증 -> 인증 콜백 -> 액세스 토큰 받아옴 -> 캘린더 credential 생성 -> 생성된 credential 세션에 넣기


코드

@Slf4j
@Controller
public class GoogleCalendar {

    // 배포서버(HTTPS) 운영서버(HTTP) 구별해서 리다이렉트 URI 분기
    private static final String LOCAL_REDIRECT_URI = "http://localhost:8080/Callback";
    private static final String PRODUCTION_REDIRECT_URI = "사이트 콜백 주소";

    private static final String APPLICATION_NAME = "앱이름";
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    //토큰을 저장할 디렉토리.
    private static final String TOKENS_DIRECTORY_PATH = "tokens";

    // 읽기 전용 범위 설정 (사용할 기능 범위에 따라 바꿔줘야함!)
    private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR_READONLY);
    private static final String CREDENTIALS_FILE_PATH = "/credentials.json";

    // GoogleNetHttpTransport.newTrustedTransport(): SSL 인증서를 검증하여 Google API 서버와 안전한 연결을 확립
    private static final NetHttpTransport HTTP_TRANSPORT;

    static {
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //OAuth 2.0 인증 과정을 관리하는 객체
    private static final GoogleAuthorizationCodeFlow flow;

    static {
        try {
            flow = new GoogleAuthorizationCodeFlow.Builder(
                    HTTP_TRANSPORT, JSON_FACTORY, getClientSecrets(), SCOPES)
                    .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                    .setAccessType("offline")
                    .build();

        } catch (Exception e) {
            throw new RuntimeException("Failed to initialize GoogleAuthorizationCodeFlow", e);
        }
    }

    // src/main/resources/credentials.json 의 정보를 들고와 시크릿 키 찾아냄
    private static GoogleClientSecrets getClientSecrets() throws IOException {
        InputStream in = GoogleCalendar.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (in == null) {
            throw new FileNotFoundException("Resource not found: " + CREDENTIALS_FILE_PATH);
        }
        return GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
    }

    // 구글 oauth 인증 과정 관리 -> 로그인 페이지로 리다이렉트
    public static void authorize(HttpServletResponse response, HttpServletRequest request) throws IOException {

        // request.getScheme() 로 http 와 https 구분
        String redirectUri = request.getScheme().equals("https") ? PRODUCTION_REDIRECT_URI : LOCAL_REDIRECT_URI;

        String authorizationUrl = flow.newAuthorizationUrl().setRedirectUri(redirectUri).build();

        // 사용자를 Google 로그인 페이지로 리디렉션
        response.sendRedirect(authorizationUrl);
    }

    // Google에서 인증이 완료되면 사용자를 리디렉션하는 URL
    @GetMapping("/Callback")
    public void oauth2Callback(@RequestParam("code") String authorizationCode, HttpServletResponse response, HttpServletRequest request) {
        try {
            log.info("구글 인증 성공!" + authorizationCode);

            TokenResponse tokenResponse = newTokenRequest(authorizationCode, request);

            // 해당 서비스의 모든 요청에 대해 필요한 인증 정보를 자동으로 처리
            Credential credential = flow.createAndStoreCredential(tokenResponse, "user");
            // 생성된 크레덴셜을 세션에 담아 사용
            request.getSession().setAttribute("credential", credential);

            response.sendRedirect("/main");
        } catch (Exception e) {
            log.info("구글 인증 실패");
            e.printStackTrace();
        }
    }

    // Google의 토큰 서버에 인증 코드를 제출하여 액세스 토큰을 얻음 -> api 사용 인증
    private TokenResponse newTokenRequest(String authorizationCode, HttpServletRequest request) throws Exception {

        String redirectUri = request.getScheme().equals("https") ? PRODUCTION_REDIRECT_URI : LOCAL_REDIRECT_URI;
        return flow.newTokenRequest(authorizationCode)
                .setRedirectUri(redirectUri)
                .execute();
    }

    // 일정 리스트 불러오기
    public static List<Event> getCalendarList(Credential credential, DateTime startDate, DateTime endDate) throws Exception {
        // 새로 인증된 API 클라이언트 서비스를 빌드.
        Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();

        String pageToken = null;
        List<Event> items = null;
        do {
            Events events = service.events().list("가져올 캘린더 이름").setPageToken(pageToken)
                    .setTimeMin(startDate)
                    .setTimeMax(endDate)
                    .execute();
            items = events.getItems();
            pageToken = events.getNextPageToken();
        } while (pageToken != null);
        return items;
    }
}

자세하게 주석 달아둠.
마지막 getCalendarList() 를 호출해서 캘린더 일정을 불러올수 있다

로컬 개발도 계속 진행해야되고, 배포서버 운영도 해야했기 때문에 

request.getScheme()

코드로 http https 구분해서 리다이렉트 uri 을 일치 시켜줬다.


문서에 있는 빠르게 시작하기 따라하면 너무 쉬워서 금방 할줄 알았는데,
은근히 로직이 어렵다. 자바 실력 부족이다.

728x90
반응형