ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 코프링(코틀린 + 스프링부트) + 구글 스프레드 시트로 슬랙봇 만들기 - ① 슬랙앱 생성 및 사용 설정하기
    KOTLIN 2022. 10. 22. 13:59

     

     

     

    이번에는 코틀린을 공부하면서 코틀린과 함께 스프링부트를 이용한 슬랙봇을 만들어 보았다.

    아이디어는 동기분이 점심봇을 얘기해주셨고,

    이를 이용해서 공부하면 좋을 것 같아 슬랙봇이 메세지 통신을 어떻게하고 보여주는지 간단한 학습용 프로젝트를 진행했다!

     

    참고로 데이터 베이스를 어떻게 할 지 생각해 보았는데,

    예전에 유튜브에서 비슷한 아이디어로 슬랙봇을 만든 동영상이 생각이 났다!

    영상을 보고 구글 스프레드 시트를 데이터베이스로 활용할 수 있다는 것을 알게 되었고,

    리스트를 관리하기에 스프레드시트가 훨씬 편할 것 같아 나도 같은 방식을 적용하되 파이썬이 아닌 코틀린에 적용하도록 하였다!

     

    참고한 영상

    https://www.youtube.com/watch?v=NfJjaGjVceo

     

     

     

     

    먼저 코틀린 + 스프링부트로 프로젝트를 생성한 부분은

    Restaurant 객체 하나로 구성하여 간단하기도 하고,

    기존에 스프링부트 프로젝트를 적용 한 부분이 비슷하여 이 부분은 생략하였다..!

    적용하고 싶은 내용대로 구성하면 될 듯 하다.

    (참고로 프로젝트에 적용한 인수테스트 부분은 나중에 추가로 블로그 글을 작성할 예정이다!)

    기존 프로젝트 + 슬랙 앱 + 구글 스프레드 시트 연동 방법을 위주로 기록하였다.

     

     

     

    슬랙 연동을 위한 dependency 추가하기

    다음의 글을 참고하여 슬랙연동을 위한 dependency를 추가하였다.

    https://medium.com/codex/creating-a-slack-bot-kotlin-and-deploying-it-in-heroku-32f884e39bea

     

    Creating a Slack bot (Kotlin) and deploying it in Heroku

    This is the minimum needed to create and deploy an app that replies to Slack commands.

    medium.com

    https://jsonobject.tistory.com/m/518

     

    Spring Boot, Kotlin, Slack 채널 메시지 전송하기

    개요 Slack은 아주 편리한 엔터프라이즈 협업 도구이다. 애플리케이션에서도 Slack을 이용하면 장애와 같은 중요한 상황에서 적절한 메시지를 특정 채널에 전송할 수 있다. 이번 글에서는 Slack 연

    jsonobject.tistory.com

     

    위의 글을 참고하여 적용한 내 프로젝트의 dependency는 다음과 같다.

    아래의 내용중에서 slack항목을 추가해주면 된다.

    import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
    import org.gradle.api.tasks.testing.logging.TestLogEvent
    import org.gradle.api.tasks.testing.logging.TestExceptionFormat
    
    
    plugins {
    // 스프링 프레임워크 
    	id("org.springframework.boot") version "2.7.4"
    	id("io.spring.dependency-management") version "1.0.14.RELEASE"
    
    // springRestDoc을 위한 플러그인 
    	id("org.asciidoctor.convert") version "1.5.8"
    
    // jpa을 위한 플러그인
    	id("org.jetbrains.kotlin.plugin.noarg") version "1.5.30"
    	kotlin("jvm") version "1.6.21"
    	kotlin("plugin.spring") version "1.6.21"
    	kotlin("plugin.jpa") version "1.4.32"
    
    // slack을 위한 플러그인 
    	kotlin("kapt") version "1.3.61"
    	kotlin("plugin.serialization") version "1.6.20"
    }
    
    group = "slack"
    version = "0.0.1-SNAPSHOT"
    java.sourceCompatibility = JavaVersion.VERSION_11
    
    configurations {
    	compileOnly {
    		extendsFrom(configurations.annotationProcessor.get())
    	}
    }
    
    repositories {
    	mavenCentral()
    }
    
    
    // slack을 위한 추가 항목 
    val snippetsDir by extra { file("build/generated-snippets")}
    sourceSets["main"].withConvention(org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet::class) {
    	kotlin.srcDir("$buildDir/generated/source/kapt/main")
    }
    
    dependencies {
    	implementation("org.springframework.boot:spring-boot-starter-web")
    	implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    	implementation("org.jetbrains.kotlin:kotlin-reflect")
    	implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    
    // 추후에 구글 스프레드 시트 사용을 위한 추가항목 
    	implementation("com.google.api-client:google-api-client:1.30.4")
    	implementation("com.google.apis:google-api-services-sheets:v4-rev581-1.25.0")
    
    // 데이터 베이스 및 jpa 항목 
    	implementation("org.springframework.boot:spring-boot-starter-data-jpa")
    	implementation("org.springframework.boot:spring-boot-starter-jdbc")
    	implementation("mysql:mysql-connector-java")
    	implementation("com.h2database:h2")
    	implementation("com.querydsl:querydsl-jpa:5.0.0")
    
    // slack을 위한 추가 항목 
    	implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2")
    	implementation("com.slack.api:slack-api-client:1.20.2")
    	implementation("com.slack.api:bolt:1.1.+")
    	implementation("com.slack.api:bolt-servlet:1.1.+")
    	implementation("com.slack.api:bolt-jetty:1.1.+")
    	implementation ("com.slack.api:slack-api-client-kotlin-extension:1.10.0")
    	implementation("com.google.code.gson:gson:2.9.1")
    
    // query dsl 및 테스트를 위한  추가 항목 
    	kapt("com.querydsl:querydsl-apt:5.0.0:jpa")
    	kapt("org.springframework.boot:spring-boot-configuration-processor")
    	compileOnly("org.projectlombok:lombok")
    	annotationProcessor("org.projectlombok:lombok")
    	testImplementation("org.springframework.boot:spring-boot-starter-test")
    	testImplementation("org.springframework.restdocs:spring-restdocs-mockmvc")
    	testImplementation("io.mockk:mockk:1.12.0")
    	testImplementation("org.jetbrains.kotlin:kotlin-test-junit5:1.6.20")
    	testImplementation("org.hamcrest:hamcrest:2.2")
    	testImplementation("io.rest-assured:kotlin-extensions:5.0.1")
    	testImplementation("com.squareup.okhttp3:mockwebserver:4.0.0")
    	testImplementation("com.squareup.okhttp3:okhttp:4.0.0")
    	testImplementation("com.github.tomakehurst:wiremock-jre8:2.34.0")
    }
    
    
    // jpa 설정 항목 
    allOpen { // 추가적으로 열어줄 allOpen
    	annotation("javax.persistence.Entity")
    	annotation("javax.persistence.MappedSuperclass")
    	annotation("javax.persistence.Embeddable")
    }
    
    tasks.withType<KotlinCompile> {
    	kotlinOptions {
    		freeCompilerArgs = listOf("-Xjsr305=strict")
    		jvmTarget = "11"
    	}
    }
    
    tasks.withType<Test> {
    	useJUnitPlatform()
    }
    
    tasks.test {
    	outputs.dir(snippetsDir)
    	useJUnitPlatform()
    	testLogging {
    		events(TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED)
    		exceptionFormat = TestExceptionFormat.SHORT
    		showCauses = true
    		showExceptions = true
    		showStackTraces = true
    	}
    }
    
    tasks.asciidoctor {
    	inputs.dir(snippetsDir)
    	dependsOn(tasks.test)
    }

     

     

     

     

     

     

    슬랙앱 생성하기

    이 부분은 다음의 사이트를 참고하여 진행하였다.

    http:// https://zzang9ha.tistory.com/m/400

     

     

     

    우선 슬랙에 워크스페이스가 없다면 먼저 워크스페이스를 만들어주어야 한다.

    이후 슬랙 사이트에 가서 앱을 생성(Create New App)해준다.

    From scratch 선택 후 생성하고자 하는 슬랙봇 이름과 워크스페이스를 선택해준다.

     

     

     

     

     

    토큰 생성하기

    이제 앱을 사용하기 위한 토큰을 생성해준다.

    좌측의 OAuth & Permission을 선택한 후 원하는 Scope를 선택해준다.

    • 간단 설명
      • app_mention_read : @<앱 이름>을 이용해 들어오는 요청을 읽을 수 있음
      • channels:[history:read:write] : 앱이 할당된 채널에 대한 메세지를 읽고 쓸 수 있음
      • commands : /<요청>을 통해 들어오는 메세지를 읽을 수 있음
      • groups:read : 채널을 확인 권한 부여로 private 채널에 슬랙봇 사용시 필요
      • im:[history:read:write] : 슬랙봇과의 DM으로 들어온 요청을 읽고 쓸 수 있음
      • incoming-webhook : 웹훅으로 들어온 요청을 처리할 수 있음
      • users-profile : 사용자의 정보를 확인할 수 있음

     

     

    권한부여를 완료하였다면 install to Workspace를 통해 앱을 만들어준다.

    참고로, 여기서 생성된 토큰은 노출되지 않도록 조심해야한다.

     

     

    게시하고자 하는 채널을 선택 후 허용을 클릭한다.

     

     

     

     

    채널에 앱 등록하기

    다음과 같이 슬랙 워크스페이스의 앱을 게시하고자 하는 채널에 가서 세부정보에 앱을 추가해준다.

    채널 세부 정보 보기 → 통합 → 앱 추가

     

     

     

     

    앱이 등록된 채널 아이디 얻기

    사이트에 들어가서 다음과 같이 앱이 등록된 채널 아이디를 얻는다.

    • 다음와 같이 발급받은 oauth 토큰을 입력하고 생성했던 채널 이름을 확인하여 id를 얻는다.

    나의 경우에는 restaurant_bot_test 이름의 채널에 게시하였다.

     

     

     

     

     

     

    슬랙봇 사용을 위한 설정값 추가하기

    이제 만들어둔 프로젝트에서 슬랙을 사용하기 위해 설정값을 추가해준다.

    secret은 다음과 같이 슬랙 정보에서 확인해준다.

    Basic Information → App Credentials → Signing Secret

     

     

     

    /resources/application.properties 에 다음과 같이 작성해준다.

    내 프로젝트의 데이터는 영상과 같이 구글 스프레드 시트에 담아 영구적으로 저장하도록 만들고, 서버가 실행될 시 스프레드 시트와 동기화 시켜서 데이터를 이용할 것이기 때문에 DB설정을 인메모리 데이터인 h2를 사용하도록 설정하였다.

    // DB 설정 
    spring.datasource.hikari.driver-class-name=org.h2.Driver
    spring.datasource.hikari.jdbc-url=jdbc:h2:mem:testdb;MODE=MySQL
    spring.datasource.hikari.username=sa
    spring.datasource.hikari.password=
    spring.jpa.hibernate.ddl-auth=update
    
    server.servlet.encoding.charset=UTF-8
    server.servlet.encoding.force=true
    
    slack.bot.token=<발급받은 oAuth 토큰>
    slack.monitor.channel.token=<앱이 등록된 채널의 ID>
    slack.signing.secret=<앱의 signing secret>

     

     

     

     

    이제 슬랙을 사용하기 위한 기본적인 설정은 완료가 되었다! ✨

     

     

     

     

     

Designed by Tistory.