Learn programming in Myanmar
Simple chat application with Spring WebSocket and Angular 10 Part (2)
What I’ll do
ဒီတစ်ခါမှာတော့ Angular နဲ့ client-side application တစ်ခုရေးပြီးတော့ ကျွန်တော်တို့ရဲ့ spring boot server နဲ့ ချိတ်ကြည့်ပါမယ်။ ပထမဉီးဆုံး စက်ထဲမှာ node js နဲ့ Angular CLI ရှိဖို့လိုပါတယ်။ Angular CLI setup လုပ်တာကို https://angular.io/cli မှာ ကြည့်ပါ။ Part 1 ကို ဖတ်ထားမှ အဆက်အစပ်ရှိမှာဖြစ်လို့ မဖတ်ရသေးရင် part 1 ကိုအရင်ဖတ်ဖို့ ပြောချင်ပါတယ်။ Part 1 link ကို အောက်ဆုံးမှာ ထည့်ပေးထားပါတယ်။
What I’ll use
- Angular CLI 10.0.6
- node 12.18.3
- Bootstrap 4.5.2
- jQuery 3.5.1
- stompjs 2.3.3
- sockjs-client 1.5.0
- VS Code
Project set up
Angular CLI ကို သုံးပြီးတော့ angular application တစ်ခုကို generate လုပ်ပါမယ်။ ကျွန်တော်က customize လုပ်ထားတဲ့အတွက် spec file တွေနဲ့ css file တွေပါမှာမဟုတ်ပါဘူး။
ng new websocket-client -s -S
Routing ယူမလားမေးရင် N လို့နှိပ်ပေးပါ။ Stylesheet format ကိုလည်း CSS ကိုဘဲ ရွေးပါမယ်။ ကျွန်တော်တို့ရဲ့ ရည်ရွယ်ချက်က websocket ကို လေ့လာနေတာဖြစ်တဲ့အတွက် ရှုပ်ထွေးမှု အနည်းဆုံးနဲ့ ကျွန်တော်တို့သိချင်တာကို စမ်းကြပါမယ်။ ခဏလောက်စောင့်လိုက်ရင် websocket-client ဆိုတဲ့ angular application လေးတစ်ခုရလာပါပြီ။ ကိုယ်သုံးနေကျ code editor or IDE မှာ project ကိုဖွင့်လိုက်ပါ။
Download the required modules
အရင်ဆုံး terminal/command prompt ကနေ project ရဲ့ directory ကိုသွားပေးပါ။ ကျွန်တော့်ဆီမှာတော့ cd websocket-client ဆိုပြီး သွားပေးရပါတယ်။
cd websocket-client
ပြီးရင်တော့ လိုအပ်တဲ့ module တွေကို npm ကိုသုံးပြီးတော့ install လုပ်ပါမယ်။ yarn ကိုသုံးလို့လည်းရပါတယ်။
npm install bootstrapnpm install jquerynpm install jquerynpm install --save stompjsnpm install --save sockjs-client
လိုအပ်တဲ့ modules တွေကိုတော့ ထည့်ပြီးသွားပါပြီ။ Bootstrap ကိုသုံးနိုင်ဖို့အတွက် angular.json ထဲမှာ သွားပြီး relative path ကိုပြန်ညွှန်းပေးရပါမယ်။
Write a model class
ပထမဉီးဆုံး src/app အောက်မှာ model ဆိုတဲ့ directory တစ်ခုကို ဆောက်ပါမယ်။ ဒီထဲမှာတော့ chat.model.ts ဆိုတဲ့ backend ChatMessage နဲ့ ပုံစံတူ model class တစ်ခုကို ရေးထားပါမယ်။
Write a service
ဒီ service class က ကျွန်တော်တို့ spring boot backend နဲ့ချိတ်ဆက်မယ့် အပိုင်းဖြစ်ပါတယ်။ src/app အောက်မှာ service ဆိုတဲ့ directory တစ်ခုထပ်ဆောက်ပြီး message.service.ts ဆိုတဲ့ service class တစ်ခုရေးပါမယ်။ ကျွန်တော်တို့ သုံးချင်တဲ့ class တွေကို import ကြိုလုပ်ထားပါမယ်။
socket: any နဲ့ stompClient: any ဆိုတဲ့ variable နှစ်ခုယူထားပါမယ်။ Server ပေါ်ကနေ broadcast လုပ်မယ့် message တွေကိုသိမ်းဖို့အတွက် chats: ChatModel[] ဆိုတဲ့ array တစ်ခုကို ကြိုသတ်မှတ်ထားပါမယ်။
ကျွန်တော်တို့ရဲ့ class ထဲမှာ connect(), disconnect() နဲ့ sendMessage(message: any) ဆိုတဲ့ method အခွံသုံးခုကို ရေးထားပါမယ်။
connect()
Websocket object တစ်ခုအဖြစ် SockJS ကို server ရဲ့ websocket endpoint ကို constructor parameter အနေအဲ့ parse လုပ်ပြီး object ဆောက်ပါမယ်။ Endpoint ကတော့ part 1 မှာ ကျွန်တော် သတ်မှတ်ထားပြီးပါပြီ။
this.socket = new SockJS('http://localhost:8080/chatty');
Server နဲ့ message တွေအပြန်အလှန်ပေးပို့နိုင်ဖို့အတွက် StompClient တစ်ခုလိုပါတယ်။ ပုံမှန် WebSocket object ဆိုရင်တော့ Stomp.client(url) ဆိုပြီး stomp client object တစ်ခုကို ဆောက်လို့ရမှာဖြစ်ပါတယ်။ ကျွန်တော်တို့က websocket ကို support မပေးတဲ့ browser တွေအတွက် အဆင်ပြေအောင် SockJS ဆိုတဲ့ websocket နောက်တစ်မျိုးကို သုံးထားပါတယ်။ ဒီလိုမျိုးအခြေအနေတွေအတွက် Stomp.over() ဆိုတဲ့ method ကိုပြင်ပေးထားပါတယ်။ ဒီ method က websocket definition တွေကိုလိုက်နာတဲ့ object တစ်ခုကို parameter အနေနဲ့လက်ခံပြီးတော့ stomp client object ကိုထုတ်ပေးပါတယ်။ ကျွန်တော်တို့လက်ရှိအခြေအနေမှာဆိုရင် SockJS object ဖြစ်ပါတယ်။
this.stompClient = Stomp.over(this.socket);
Stomp client ရပြီဆိုတာနဲ့ connect() ဆိုတဲ့ method ကိုခေါ်ပြီး STOMP server နဲ့ authentication process ကိုလုပ်ဆောင်ရမှာဖြစ်ပါတယ်။ ဒီ method ကိုခေါ်လိုက်တာနဲ့တစ်ပြိုင်နက် client-side ကနေ websocket(in our case, it’s socket) ကိုသုံးပြီးတော့ server နဲ့ connection ကိုဖွင့်ပါတယ်။ ပြီးရင်တော့ server ပေါ်ကို CONNECT frame တစ်ခုကို ပို့မှာဖြစ်ပါတယ်။ Connection ဟာ asynchronously အလုပ်လုပ်တာဖြစ်တဲ့အတွက် connect method ရဲ့ parameter မှာ mandatory user credential object တစ်ခုအပြင် connection success ဖြစ်သွားရင်ခေါ်မယ့် callback နဲ့ connect လုပ်လို့မရရင်ခေါ်မယ့် callback နှစ်ခုကိုလက်ခံပါတယ်။
onConnectCallback မှာဆိုရင် server ရဲ့ message broker ကပို့နေတဲ့ destination ကို ပြန် subscribe လုပ်ထားတာဖြစ်ပါတယ်။ Server ဘက်မှာ controller ထဲက သက်ဆိုင်ရာ method တစ်ခုခု အလုပ်လုပ်ပြီးရင် သတ်မှတ်ထားတဲ့ destination ကို frame တစ်ခုကို ပြန်ပို့ပေးပါတယ်။ Frame ရဲ့ body မှာ ကျွန်တော်တို့လိုချင်တဲ့ ChatModel object က text format နဲ့ ပါလာမှာဖြစ်ပါတယ်။ ကျွန်တော်တို့ frame ဆိုတာကို debug ထောက်ကြည့်ရင် ဒီလိုတွေ့ရပါမယ်။
ကျန်တာကတော့ server ပေါ်က ပြန်ပို့ပေးတဲ့ message တွေကို chats array ထဲကို push လုပ်ပြီး သိမ်းသွားပါမယ်။ onDisconnectCallback မှာတော့ log ဘဲထုတ်ပြထားပါတယ်။
disconnect()
ကျွန်တော်တို့ Angular component တွေမှာ lifecycle တွေရှိပါတယ်။ ကျွန်တော်တို့ရဲ့ message service ကို inject လုပ်ထားတဲ့ component ရဲ့ onInit method မှာ connection ကိုဖွင့်ထားမယ်ဆိုရင် onDestroy မှာလည်း connection ကိုပြန်ပိတ်ပေးမှ သင့်တော်ပါမယ်။ ကျွန်တော်တို့ရှေ့မှာ stomp client ကနေ connect လုပ်တာကို မှတ်မိဉီးမယ်ထင်ပါတယ်။ Connection ကိုပိတ်ချင်ရင်လည်း stomp client ကနေဘဲပြန်ပိတ်ပေးရပါတယ်။
this.stompClient.disconnect();
sendMessage(message: any)
Server ကို STOMP message တွေပို့နိုင်ဖို့အတွက် stomp client မှာ send() ဆိုတဲ့ method ရှိပါတယ်။ ဒီ method ရဲ့ ပထမ argument မှာ STOMP destination ကိုမဖြစ်မနေထည့်ပေးရပါမယ်။ နောက်တစ်ခါ optional argument တွေအနေနဲ့ header နဲ့ body ကိုလက်ခံပါတယ်။ Header ဆိုတာကတော့ message headers တွေပါတဲ့ javascript object တစ်ခုဖြစ်ပါတယ်။ Body မှာတော့ server ကို ပို့ချင်တဲ့ message object ကိုထည့်ပေးရပါမယ်။
this.stompClient.send('/app/send', {}, JSON.stringify(message));
“/app” ဆိုတာက ကျွန်တော်တို့ server ရဲ့ application destination prefix ဖြစ်ပြီးတော့ “/send” ဆိုတာကတော့ controller class တွေထဲက @MessageMapping annotation တပ်ထားတဲ့ method တွေရဲ့ url နဲ့ map လုပ်ခံရမှာဖြစ်ပါတယ်။
Use MessageService inside a component
Component ထဲမှာတော့ MessageService ကို constructor injection လုပ်ပြီး component ရဲ့ သင့်တော်ရာ lifecycle method တွေမှာ websocket connection အဖွင့် အပိတ်လုပ်ပေးရပါမယ်။ ဒီအပိုင်းကတော့ UI ဆွဲပြီး service နဲ့ data ပြန် bind တဲ့အပိုင်းတွေနဲ့ Angular အပိုင်းတွေဖြစ်တဲ့အတွက် အသေးစိတ်မပြောတော့ပါဘူး။ ကျွန်တော့်ရဲ့ code နမူနာကို အောက်မှာ github link တင်ပေးထားပါတယ်။
What we‘ve done so far?
အခုဆိုရင် ကျွန်တော်တို့ server-side မှာ message တွေကိုလက်ခံမယ့် destination တစ်ခု၊ server ပေါ်ကိုရောက်လာတဲ့ message တွေကို broadcast လုပ်မယ့် destination တစ်ခု စုစုပေါင်းနှစ်ခုကို ဖွင့်ထားပေးပြီးပါပြီ။ Client-side မှာတော့ websocket အတွက် SockJS ကိုအသုံးပြုပြီး websocket တစ်ခုကို တည်ဆောက်ပါတယ်။ STOMP messaging protocol ကိုသုံးနိုင်ဖို့အတွက် ကျွန်တော်တို့ ဆောက်ထားတဲ့ sockjs obj ကိုသုံးပြီး stomp client ကိုတည်ဆောက်ပါတယ်။ ဒါဆိုရင်တော့ stomp client ကနေ message တွေပို့တာ၊ message တွေ subscribe လုပ်တာတွေကို လုပ်လို့ရပါပြီ။ ကျွန်တော့် project ကို clone လုပ်ပြီး ကိုယ့်စက်ထဲမှာ host လုပ်လိုက်ရင် ဒီလိုတွေ့ရမှာဖြစ်ပါတယ်။
ကျွန်တော် ဒီ article ကိုရေးတဲ့နေရာမှာ websocket ကိုသိပြီးသားသူတွေ မြန်မြန်ဆန်ဆန်နဲ့ language တစ်ခုမှာ adapt လုပ်နိုင်ဖို့ကို အဓိကထားပြီးရေးထားတာဖြစ်ပါတယ်။ တစ်ကယ်လို့ ကိုယ်က websocket ကို မသိသေးဘူးဆိုရင် websocket ဆိုတာ ဘာလဲ၊ ဘာကြောင့်သုံးရလဲဆိုတာကို အရင်လေ့လာသင့်ပါတယ်။ ကျွန်တော်တို့ရေးထားတဲ့ websocket endpoint တွေကို secure ဖြစ်အောင် ဘယ်လိုလုပ်မလဲဆိုတဲ့အပိုင်းကလည်း ဆက်လက်လေ့လာရမယ့် အရာဖြစ်ပါတယ်။
Source code: https://github.com/kyaw-codes/websocket-full-demo.git