สร้าง LINE Bot ด้วย Spring Boot [Step-by-Step]
หลังจากที่เราสร้าง LINE Bot ง่ายๆ กันไปแล้ว เราได้สร้าง LINE developer accout, สร้าง Channel & Provider และใช้โค้ดที่มีอยู่ใน LINE SDK ใน GitHub มาสร้างเป็น Bot ด้วยการ deploy โค้ดที่มีอยู่ไปใน Heroku โดยที่เราไม่ได้สนใจเลยว่าโค้ดมันทำงานอย่างไร คราวนี้ผมจะมาสร้าง LINE Bot ด้วย Spring Boot ที่ละขั้นตอน เพื่อให้เราเข้าใจและนำไปต่อยอดได้ในอนาคต
สร้าง Project กันเลย
ในที่นี้จะใช้ IntelliJ IDEA + Maven ในการสร้าง project เราก็กดที่ “Create New Project” เลย เลือก project แบบ Maven แล้วกด Next ใส่ GroupId, ArtifactId และ Version ดังนี้ (ตัวอย่างน่ะ)
GroupId: com.iphayao
ArtifectId: line-bot-spring-boot
Version: 1.0-SNAPSHOT
ถัดไปก็ตรวจสอบรายละเอียดของ project ซึ่งก็จะเอาข้อมูลมาจากหน้าก่อนหน้านี้คือ ArtitactId มาเป็นชื่อของ project แต่จะเอา “-” ออกไป ดังนั้นถ้าเราต้องการให้มีอยู่ก็จะต้องใส่เข้าไปใหม่ แบบนี้ สุดท้ายก็กด Finish อันเป็นสิ้นสุดการสร้าง project (ถ้ามีหน้าต่าง popup มาเตื่อนว่า directory ไม่มีก็ให้ยอมรับด้วยการกด OK)
ใส่ Dependency ให้กับ Project
หลังจากสร้าง project แล้วจะได้ project ว่างๆ โดยไม่มีอะไรเลยนอกจากข้อมูลของ project ดังนั้งเราจะต้องมาใส่ dependency ให้กับ project ด้วยการแก้ไข pom.xml ซึ่งเป็นไฟล์กำหนดข้อมูลของ project รวมทั้ง dependency ด้วย
เราจะสร้าง LINE Bot ดังนั้นเราจะใส่ line-bot-spring-boot เป็น dependency ซึ่งก็นเป็นการ import LINE SDK dependency มาใน pom.xml
สร้าง Spring Boot App + echo (LINE Bot)
เมื่อเราใส่ dependency เรียบร้อยแล้วก็มาสร้างไฟล์ java ที่จะเป็น entry point ของ application ของเรา ดังนี้
src/main/java/com/iphayao/linebot/Application.java
@SpringBootApplication
กำหนดให้คลาส Application เป็น Spring Boot Application และมี main() เป็น entry point
@EventMapping
กำหนดให้ method handleTextMessage
map กับ MessageEvent
ชนิด TextMessageContent
และ return ข้อความของ event ออกไป เป็น echo bot ง่ายๆ
สร้าง application.yml
เพื่อกำหนด Configuration ของ application ของเรา ซึ่งถ้าไม่กำหนดจะรันไม่ได้เพราะ ตัว line-bot-spring-boot
library ต้องการ channel-token
และ channel-secret
ดังนี้ โดยที่ยังไม่ต้องใส่ข้อมูลจริงๆ เนื่องจากเราจะกำหนดค่าใน environment config ของ Heroku ในภายหลัง
สร้าง Procfile
สำหรับ deploy ใน Heroku
ลองรัน application ด้วย Run -> Run 'Application'
ถ้าทุกอย่าไม่มีปัญหาก็จะ start Spring Boot Application และ listen ที่ port 8080
ตอนนี้ยังไม่มีวิธี test ด้วย Postman ดังนั้นจะต้อง deploy ไปที่ Heroku ก่อนแล้วจึงจะ test ได้
commit ไฟล์ทั้งหมดที่สร้างไว้ ไปที่ Heroku และลองทดสอบส่งข้อความจาก LINE มายัง Bot จะได้ข้อความตอบกลับไปเหมือนกับข้อความที่ส่งมา (echo message)
$ heroku git:remote -a {HEROKU_APP_NAME}
$ git add .
$ git commit -m "Initial project"
$ git push heroku master
สร้าง LineBotController
หลังจากที่เราได้สร้าง echo bot แบบง่ายๆ ได้แล้ว แสดงว่าเรา project ของเราทำงานได้ดี ดังนั้นเราจะมา refactor ใหม่ โดยแยก annotation@LineMessageHandler
และ method @EventMapping
ออกมาเป็น LineBotController เพื่อจะเพิ่ม Logic ได้ในภายหลังให้จัดการกับ Message Content ให้หลายรูปแบบ ดังนี้
ลอง commit code ไปที่ Heroku หลังจาก deploy แล้วก็ลองส่งข้อความจาก LINE มาที่ Bot ก็จะทำงานเหมือนเดิม (echo bot)
Get ข้อมูล User Profile
เมื่อเรา refactor project ของเราให้มี controller เป็น LineBotController
ที่ทำหน้าที่จัดการ Message Event ที่เข้ามา และในตอนนี้จะเพิ่มให้ LineBotController
สามารถ handle การร้องขอข้อมูล User Profile ของ user ที่ส่งข้อความว่า “Profile” มาให้ Bot และเราจะเพิ่ม Logging โดยใช้ Lombok library ในการจัดการ ดังนั้นเราจะต้องเพิ่ม Lombok library dependency ในไฟล์ pom.xml ดังนี้
ส่วนของ LineBotController
จะแยกส่วนจัดการข้อความเป็นhandleTextContent
ซึ่งจะรับ Event
และ TextMessageContent
เข้ามาโดยใช้ switch case
เป็นตัวแยกว่าจะจัดการแต่ละข้อความด้วยวิธีไหนบ้าง ซึ่งในที่นี้จะจัดการเฉพาะคำว่า Profile
โดยไปเรียก Message API เพื่อ getProfile
ของ User ผ่าน LineMessagingClient
และจะได้ UserProfileResponse
object ที่เราสามารถดึงเอาข้อมูลของ User ในที่นี้จะใช้ methodgetDisplayname
, getStatusMessage
และ getUserId
ซึ่งหลังจากที่ได้ข้อมูล User แล้วจะส่งข้อความกลับไปหา User ด้วยการสร้าง ReplyMessage
ส่งผ่าน LineMessagingClient
เช่นกัน
เมื่อ deploy ไปที่ Heroku แล้วลองทดสอบด้วยการส่งข้อความ “Profile” ไปหา Bot ซึ่งจะตอบกลับเป็นข้อความที่มีข้อมูลของ User กลับมา (Display name, Status message, User ID)
เพิ่มจัดการข้อความ Sticker
เราสามารถจัดการข้อความที่ส่งเข้ามาแล้ว ขั้นตอนต่อไปก็จะมาจัดการข้อมูลแบบอื่นบ้าง ข้อมูลแรกคือ Sticker โดยจะทำเป็น echo stricker เมื่อ User ส่ง Sticker อะไรมา Bot จะทำการส่งกลับด้วย Stricker package และ ID เดิม โดยเพิ่ม @EventMapping
method คือ handleStrickerMessage
ซึ่งรับค่า event StickerMessageContent
มาและส่งกลับ Stricker ไปหา User
เมื่อ deploy ไปที่ Heroku แล้วลองทดสอบด้วยการส่ง Sticker ไปหา Bot แล้วจะตอบกลับมาเป็น Stricker ที่เราส่งไปโดยอ้างอิงจาก Sticker package และ Sticker ID แต่จากการทดสอบ จะส่งกลับได้เฉพาะ Free Sticker เท่านั้นสำหรับ Sticker ที่ซื้อหรือ Promotion Sticker จะใช้ไม่ได้ จะเกิด exception error เกิดขึ้นตอนส่งกลับ
เพิ่มจัดการข้อความ Location
คราวนี้เราจะมาจัดการข้อความที่เป็น Location บ้าง โดยที่ event message จะเป็น LocationMessageContent
ซึ่งจะมีข้อมูลของ title, address, longitude และ latitude ซึ่งเราจะนำข้อมูลเหล่านี้มาสร้างเป็น Location message เพื่อตอบกลับ User
เมื่อ deploy ไปที่ Heroku แล้วลองทดสอบด้วยการส่งข้อความที่เป็น location ไปหา Bot ซึ่งจะรับข้อมูลและเอาข้อมูลนั้นส่งกลับมาอีกที ดังนี้
เพิ่มจัดการข้อความรูปภาพ (Image)
เราได้สร้างการส่งกลับข้อความแบบง่ายๆ กันไปแล้วแต่ว่าถ้าเป็นข้อความที่เป็นรูปภาพ หรือ วีดีโอ ล่ะ เราจะจัดการมันอย่างไร ซึ่งการจัดการจะแตกต่างจาก ข้อความธรรมดา, Sticker หรือ Location จะยุ่งยากเพิ่มข้ึนนิดหน่อย ตรงที่เราจะต้องนำเอารูปภาพที่ User ส่งมาเก็บไว้ใน folder ชั่วคราว และส่งกลับด้วย ImageMessage ที่จะรับเฉพาะ URI ของรูปภาพที่เก็บไว้ใน folder ชั่วคราว
โดยที่ event message จะเป็น ImageMessageContent
เมื่อเรารับ event เข้ามาแล้วจะต้องไป get ข้อมูลของรูปภาพโดยใช้ lineMessageClinet
ด้วย id ของรูปภาพที่ User ส่งมา เก็บไว้ใน MessageContentResponse
แล้วก็ save ใน format ของ jpg
ซึ่งในที่นี้จะมี inner class DownloadedContent
เก็บที่อยู่ของไฟล์ชั่วคราวและ URI ของ original image และ preview image (resize) เพื่อที่จะส่งกลับไปหา User ด้วย ImageMessage
แต่เนื่องจากที่เก็บไฟล์ชั่วคราว (temporary folder) เราจะเก็บไว้ในที่เดียวกันสำหรับทุกครั้งที่แต่ละ User ส่งรูปภาพมา ดังนั้นเราจะต้องเก็บไว้ในตัวแปรที่เป็น static downloadedContentDir
โดยกำหนดที่ Application
class
แต่เนื่องจากเราไม่ได้ให้ User มาเรียกไฟล์จากที่เก็บไฟล์ชั่วคราวแต่ให้เรียกจาก URI ดังนั้นจะต้องตั้งค่า WebMvcConfigure
ของ Spring Boot ว่าให้เชื่อมกันระหว่าง temp
และ downloaded
(ตรงนี้สำคัญมาก ถ้าเราไม่ตั้งค่าตรงนี้จะทำให้รูปไม่แสดงที่ LINE ของ User เพราะว่าหารูปภาพไม่เจอ)
เมื่อ deploy ไปที่ Heroku แล้วลองทดสอบด้วยการส่งข้อความรูปภาพมาหา Bot ก็จะได้รูปภาพเดิมส่งกลับมา ดังนี้
สรุป
บทความนี้เป็นเพียงตัวอย่างบางส่วนของ LINE Message API ซึ่งมีอีกหลากหลายความสามารถที่เราสามารถนำมาใช้เพื่อสร้างสรรค์ LINE Bot เพื่อตอบสองต่อความต้องการของ User ในแบบของเรา
โค้ดทั้งหมดผมเอาใส่ไว้ใน GitHub ตามลิงค์นี้น่ะครับ