สร้าง LINE Bot ด้วย Spring Boot [Step-by-Step]

Phayao Boonon
4 min readAug 11, 2018

--

Photo by Alex Knight on Unsplash

หลังจากที่เราสร้าง 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 ในแบบของเรา

--

--

Phayao Boonon
Phayao Boonon

Written by Phayao Boonon

Software Engineer 👨🏻‍💻 Stay Hungry Stay Foolish

Responses (2)