JSP/SERVLET
2020.03.20 / 09:57

JAVA를 이용한 구글 캘린더 API 연동

코로나
추천 수 51

외부에서 제작한 회의실 예약을 관리하는 서비스를 사용중이다.

이 서비스에서 예약한 회의 30분 전에 회의 참가자들에게 알림을 주고 싶다는 요구사항이 생겼다.

외부에서 제작한 서비스이기 때문에 직접 서비스에 기능을 추가할 수 없는 상황이었다.

 

다만 서비스에서 회의실 예약 정보를 저장하고 있는 DB의 테이블과 자료의 형식은 알고있었다.

그래서 해당 테이블을 감시하면서 다가온 회의실 예약에 대해 알림을 제공하는 프로그램을 만들기로 하였다.

 

예약 정보는 DB에서 가져왔지만, 이걸 알림을 주려면 뭘로 해야할지 고민이 되었다.

쉽게는 텔레그램 같은 메신저로 보내도 되고, 사내에서 사용하는 로켓챗을 이용해도 된다.

여러가지를 고민하다가 구글캘린더에 일정으로 등록해주면 이 예약정보를 다양하게 활용이 가능하겠다는 생각을 하게 되었다.

 

구글캘린더에 일정으로 등록을 하게되면..

  • 일정이 등록된 순간 사용자의 구글계정 일정에 등록이 되고 앱에서 등록 알림을 준다.
  • 사용자가 자신의 일정앱에서 일정 시작 몇분전에 알림을 줄지 정할 수 있다(기본값은 30분, 10분)
  • 휴대폰의 일정앱 뿐 아니라 컴퓨터의 브라우저에서도 일정 기능을 키면 확인이 가능하다.

구글캘린더를 도입 하려면 알림을 받을 사람들의 구글계정이 필요하다.

요즘 대부분 구글계정 한개씩 가지고 있기때문에 큰 제약은 아니었다.

이 점만 합의가 된다면 원래 요건을 충족하고 추가로 편의성을 더 보장할 수 있어서 구글캘린더에 회의실 예약 정보를 등록하기로 하였다.

 

구글캘린더 API 와 연동하려면 구글개발자 계정과 API 등록과정이 필요하다.

또한 JAVA에서 OAuth2 인증을 위해 인증정보를 담은 json 파일이 필요하다.

설정과정은 정리가 잘 된 링크를 첨부한다. 아래 링크에서 json 파일을 다운받는 곳 까지 진행하면 된다.

https://kingbbode.tistory.com/8

 

 

개발은 SpringBoot 2, Maven 환경에서 진행하였다.

연동부분에 대한 코드는 딱히 스프링의 라이브러리를 사용하지 않았으니 스프링이 꼭 필요하지는 않다.

 

구글 oauth 인증을 하기 위해서는 아래 라이브러리 디펜던시를 추가 해야한다.

 

<dependency>
   <groupId>com.google.api-client</groupId>
   <artifactId>google-api-client</artifactId>
   <version>1.23.0</version>
</dependency>
<dependency>
   <groupId>com.google.oauth-client</groupId>
   <artifactId>google-oauth-client-jetty</artifactId>
   <version>1.23.0</version>
</dependency>
<dependency>
   <groupId>com.google.apis</groupId>
   <artifactId>google-api-services-calendar</artifactId>
   <version>v3-rev305-1.23.0</version>
</dependency>

 

아래는 구글캘린더 API 를 이용해 일정을 등록하고 삭제하는 내용을 담은 코드이다.

public class GoogleCalendar {



   private static final String APPLICATION_NAME = "Google Calendar API Java Quickstart";

   private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

   private static final String CREDENTIALS_FOLDER = "credentials"; // Directory to store user credentials.

   private static final String CALENDAR_ID = "[캘린더연동아이디]";



   /**

    * Global instance of the scopes required by this quickstart.

    * If modifying these scopes, delete your previously saved credentials/ folder.

    */

   private static final List<String> SCOPES = Collections.singletonList(CalendarScopes.CALENDAR);

   private static final String CLIENT_SECRET_DIR = "/client_secret.json";





   public static Event addEvent(Event event) throws IOException, GeneralSecurityException, GoogleJsonResponseException {

       final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

       Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))

               .setApplicationName(APPLICATION_NAME)

               .build();

       return service.events().insert(CALENDAR_ID, event).execute();

   }



   public static void delEvent(String eventKey) throws IOException, GeneralSecurityException, GoogleJsonResponseException {

       final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

       Calendar service = new Calendar.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT))

               .setApplicationName(APPLICATION_NAME)

               .build();

       service.events().delete(CALENDAR_ID, eventKey).execute();

   }



   /**

    * Creates an authorized Credential object.

    * @param HTTP_TRANSPORT The network HTTP Transport.

    * @return An authorized Credential object.

    * @throws IOException If there is no client_secret.

    */

   private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {

       // Load client secrets.

       InputStream in = GoogleCalendar.class.getResourceAsStream(CLIENT_SECRET_DIR);

       GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));



       // Build flow and trigger user authorization request.

       GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(

               HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)

               .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(CREDENTIALS_FOLDER)))

               .setAccessType("offline")

               .build();

       return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");

   }

}

getCredentials

OAuth 인증을 이용해 구글에서 인증을 가져오는 메소드이다.

앞에서 만든 인증 json을 불러와야 한다. 나의 경우는 resource 폴더에 넣고 불러왔다.

이 인증메소드는 api 요청 때 마다 실행해서 인증정보를 반환한다.

 

addEvent

구글캘린더에 일정을 추가하는 메소드이다.

일정정보를 담기 위해 Event 라는 객체를 사용한다.

Event 객체를 사용하는 방법은 아래에 따로 다루었으니 참고하자.

 

delEvent

구글캘린더에 일정을 삭제하는 메소드이다.

addEvent 했을때 구글에서 응답받은 eventKey 가 필요하다.

 

Event 생성

이벤트 생성은 크게 제목, 시작시간, 종료시간, 참여자 정보가 필요하다. 아래는 일정을 추가하는 메소드이다.

참여자정보(ResourceSubscriber), 일정정보(RecourceInfo), 사원정보(EmpInfo) 는 나의 시스템에서 사용하는 DB에 맞게 직접 만든 객체이다. 참여자정보, 일정정보, 사원정보 부분은 본인의 시스템에 맞게 각자 제작하면 된다.

 

public Event makeEvent(ResourceInfo resourceInfo, List<ResourceSubscriber> subList) throws ParseException, IOException, GeneralSecurityException {

   Event event = new Event()

           .setSummary(resourceInfo.getReqText())

           .setLocation(getMeetingRoom(resourceInfo.getResSeq()).getResName()) //장소이름은 따로 불러오길..

           .setDescription(resourceInfo.getDescText());



   DateTime startDateTime = new DateTime(dateTimeTzFormat.format(dateTimeFormat.parse(resourceInfo.getStartDate())));

   EventDateTime start = new EventDateTime()

           .setDateTime(startDateTime)

           .setTimeZone("Asia/Seoul");

   event.setStart(start);



   DateTime endDateTime = new DateTime(dateTimeTzFormat.format(dateTimeFormat.parse(resourceInfo.getEndDate())));

   EventDateTime end = new EventDateTime()

           .setDateTime(endDateTime)

           .setTimeZone("Asia/Seoul");

   event.setEnd(end);



   EventReminder[] reminderOverrides = new EventReminder[]{

           new EventReminder().setMethod("popup").setMinutes(10),

   };

   Event.Reminders reminders = new Event.Reminders()

           .setUseDefault(false)

           .setOverrides(Arrays.asList(reminderOverrides));

   event.setReminders(reminders);



   List<EventAttendee> attendList = new ArrayList();



   for (ResourceSubscriber subObj : subList) {

       logger.info("SUB ADD OBJ : " + subObj.toString());

       EmpInfo empInfo = getEmpInfo(subObj.getEmpSeq());



       if (empInfo.getOutMail() != null && empInfo.getOutMail().length() > 0 && empInfo.getOutDomain() != null && empInfo.getOutDomain().length() > 0) {

           if (empInfo.getOutDomain().equals("gmail.com")) {

               attendList.add(new EventAttendee().setEmail(empInfo.getOutMail() + "@" + empInfo.getOutDomain()));

           } else {

               //이메일주소가 gmail.com 이 아닌 케이스. 일단은 아무것도 안함.

           }

       } else {

           //메일주소가 없는 케이스.

       }

   }

   event.setAttendees(attendList);

   try {

       event = GoogleCalendar.addEvent(event);

   } catch (Exception ex) {

       logger.info("Calendar Exception in insert");

   }

   logger.info("EVENT : " + event.toPrettyString());



   return event;

}

 

구글 캘린더 API 에는 더 다양한 기능이 있다. 아래 링크에서 참고하자.

https://developers.google.com/calendar/v3/reference/

불러오는 중입니다...