聊天室 ( 原理 )
接下來的兩篇文章,要來談談「網路聊天室」,網路聊天室和智慧插座能有什麼交集呢?因為智慧插座既然可以透過 Webduino 變成一個網頁裏的變數,那麼理所當然就可以在網路聊天室和這個插座聊天,舉例來說,當輸入「開燈」訊息,燈泡就會打開,接著燈泡還會回傳「我打開囉」的訊息,或是你也可以輸入「開電扇」,電扇就會打開,如果再加個溫濕度感應器,也會透過聊天室回報溫度。
這篇將會介紹如何實做一個網路聊天室,下一篇再繼續介紹將聊天室與我們的智慧插座串接。
註冊 Firebase
要實作一個聊天室,Google 的 Firebase 服務大概是現在市面上最簡便的做法了,先來看一下 Firebase 的故事,Firebase 原本是 2011 年的一家提供雲端服務公司,在 2012 年他們開發的即時雲端資料庫,提供許多相對應的 API ,讓開發人員能儲存或同步不同平台之間的資料,而 Firebase 在 2014 年被 Google 收購,被收購之後更推出了多項新的功能。
要使用 Firebase 前一定要有一個 Google 的帳號,用 Google 帳號登入。
Firebase:https://firebase.google.com/
登入進去之後,如果你想瞭解更多的用法,可以點選上方的「Docs」,這裡要用 JavaScript 來操控,就往下拉看到「Installation & Setup in JavaScript」的部分,一些太細節的部分在這邊就不多做描述,重點還是擺在如何打造一個網頁聊天室。
起手式:https://firebase.google.com/docs/database/web/start
完整 API:https://firebase.google.com/docs/reference/js/index-all
開始使用
要使用 Firebase 首先你要先載入 Firebase JavaScript。
<script src="https://www.gstatic.com/firebasejs/3.6.2/firebase.js"></script>
先進入個人控制台,建立新專案,幫你的專案設定個好名字。
左邊選單選擇 Database,就可以看到你專案專屬的資料庫,雖然你可以自訂專案名稱,但實際上系統會在你自訂的名稱後方加上一串代碼避免和別人重複。
現在要做的是一個公開的聊天室 ( 讓所有人都能聊 ),所以先把資料庫的安全性設定為公開 ( 當這麼做的時候會出現警告訊息 ),就可以開始使用這個資料庫了,當然如果你比較重視安全性,就可以加入 apiKey
作為一些保護。
{
"rules": {
".read": true,
".write": true
}
}
資料庫建立之後,要在網頁端使用就是要先初始化 Firebase,在舊版的 Firebase 是用 new
一個 Firebase 物件 ( 現在還是可以用 ),新版則是要使用一個 config 設定,裡面就包含了像是 apiKey
之類的安全性設定。
舊版:
myFirebase = new Firebase("你的 Firebase 資料庫");
新版:
var config = {
apiKey: "apiKey",
authDomain: "projectId.firebaseapp.com",
databaseURL: "你的 Firebase 資料庫",
storageBucket: "bucket.appspot.com"
};
firebase.initializeApp(config);
因為是用公開的資料庫來讀寫,設定檔就只需要 databaseURL
即可。
var config = {
databaseURL: "你的 Firebase 資料庫"
};
firebase.initializeApp(config);
更新、寫入資料
要來寫資料進資料庫了,如果是舊版的 Firebase,直接用 push
的方法就可以,而在新版的文件裡,反而沒有提到 push
的用法 ( 雖然還是可以用呦~ ),反而是先用 push
產生一組 key
,接著透過 update
的方式寫入,如果沒有這組 key
或是 key
相同,update
基本上就是「複寫更新」的指令。
var firebase;
var config = {
databaseURL: "你的資料庫名稱"
};
firebase.initializeApp(config);
//要寫入的資料物件
var postData = {
id:'a',
num:123
};
//每次寫入資料庫都產生一組 key
var newPostKey = firebase.database().ref().child('posts').push().key;
var updates = {};
updates[newPostKey] = postData;
//寫入資料
firebase.database().ref().update(updates);
如此一來當我們執行網頁的時候,就會順利寫入資料,當然如果覺得這樣比較麻煩,也可以直接使用 push
來實現。
var firebase;
var config = {
databaseURL: "你的資料庫名稱"
};
firebase.initializeApp(config);
var postData = {
id:'b',
num:456
};
firebase.database().ref().push(postData);
再來看到 ref
,裡面是輸入資料庫的目錄結構,舉例來說,如果我寫成像下面這樣,則資料就會存到「路徑/test 」裡頭。
firebase.database().ref('/test/').push(postData);
能夠寫入資料之後,我們練習一下用兩個輸入框加上一個按鈕,在輸入文字後,按下按鈕,就把文字寫入資料庫。首先 HTML 放兩個輸入框,第一個是姓名,第二個是聊天內容,然後放一個送出的按鈕。
姓名:<input id="name"><br/>
聊天內容:<input id="content"><br/>
<button id="btn">送出資料</button>
再來就是 JavaScript 內容,先宣告網頁上輸入欄位與按鈕,在按下按鈕的當下,把欄位的值寫入資料庫,如果你把資料庫在旁邊開一個視窗,就會看到資料即時寫入。 ( 注意,如果像我一樣使用 jQuery,firebase 變數需為全域變數 )
var firebase;
$(function(){
var $name = $('#name'),
$content = $('#content'),
$btn = $('#btn');
var config = {
databaseURL: "你的資料庫名稱"
};
firebase.initializeApp(config);
var database = firebase.database().ref();
$btn.on('click',function(){
var postData = {
name:$('#name').val(),
content:$('#content').val()
};
database.push(postData);
});
});
這裡我們其實還可以在送出的當下,加入下面這行,讓我們按下送出之後,就把內容欄位清空。
$('#content').val('');
讀取資料
既然可以寫入資料,就一定要能夠讀取資料,而「即時」讀取資料正是 Firebase 的強項,這也是為什麼現在許多聊天室都會選用 Firebase 做為資料庫的主因。
這邊使用 .on
來讀取資料,這個方法可以在每次資料庫有變動的時候,就把資料回傳讓我們知道,以下面這段程式碼為例,當我們資料庫變動時,就在 console 裡頭印出來。
database.on('value', function(snapshot) {
console.log(snapshot.val());
});
不過由於讀取到的資料是「物件」,所以這裡透過 for 迴圈轉換成陣列,並將陣列的內容依序顯示在網頁上,就可以看到一個聊天室雛形誕生了,不過要注意的是一開始先把畫面清空,避免產生的內容重複發生。
database.on('value', function(snapshot) {
$show.html('');
for(var i in snapshot.val()){
$show.append('<span>'+snapshot.val()[i].name+' 說:'+snapshot.val()[i].content+'</span><br/>');
}
});
實作聊天室
看完寫入和讀取之後,就真的要來做一個聊天室了,首先來看一下一個基礎的聊天室,需要有哪些功能:
- 姓名
- 發送時間
- 對話內容
- 可以區隔是自己發的內容還是別人發的內容
- 打完字按下 enter 就送出 ( 不然每次還要用滑鼠點也是頗累人 )
由這五個功能可以發現資料庫需要有四個欄位:姓名、時間、內容、id,其他的基本上都可以透過網頁前端來解決,先把寫入資料庫的事情搞定,因為需要「時間」,所以在每次按下按鈕時都會觸發 new Date()
,為了避免個位數與十位數在排版上的差異,所以一律補零,最後就是在寫入的物件新增一個 time
的屬性記錄當下時間。
id 則是在一開始的時候先設定一個變數 ms = new Date().getTime()
,目的是讓打開網頁的使用者知道自己是誰 ( getTime()
的目的在獲取從 1970/1/1 到現在的毫秒數,很難重複 ),這樣子我們讀取資料的時候,才可以知道哪個帳號是自己說的話,就可以透過樣式標記出來。( 當然如果是使用帳號登入之類的方式就更簡單判斷 )
$btn.on('click',write);
//設定在對話框按下 enter 的事件 ( enter 預設 keyCode 為 13 )
$content.on('keydown', function(e){
if(e.keyCode == 13){
write();
}
});
function write(){
var date = new Date();
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
if(h<10){
h = '0'+h;
}
if(m<10){
m = '0' + m;
}
if(s<10){
s = '0' + s;
}
var now = h+':'+m+':'+s; //獲取按下按鈕或 enter 的當下時間
//記得一開始要先宣告 ms = new Date().getTime()
var postData = {
name:$('#name').val(),
content:$('#content').val(),
time:now,
id:'id'+ms
};
database.push(postData);
$content.val('');
}
完成後再來看看讀取的程式,這邊將會用到 .once
以及 .limitToLast(1).on
這兩種方法,第一個 .once
的目的在於資料庫的「完整資料」在「第一次」全部載入,因為沒有必要在每次送出訊息的時候都重新載入一次 ( 如果純粹用 .on
就會全部重新載入 ),而 .once
只會載入一次,而 .limitToLast(1).on
則是在資料庫有變動的時候,載入最後一筆訊息,同樣的,這個步驟也是避免每次發送訊息都載入完整資料庫。
將資料顯示在畫面上則是用了 jQuery 的 prepend
,這樣才會顯示在開頭,然後用一點點 CSS 做顏色的區隔。
//第一次載入資料庫時顯示所有內容
database.once('value', function(snapshot) {
$show.html('');
for(var i in snapshot.val()){
$show.prepend('<div><div>'+snapshot.val()[i].time+'</div>'+snapshot.val()[i].name+' 說:'+snapshot.val()[i].content+'</div>');
}
});
//每一次資料庫有變動時,獲取最新一筆內容呈現
database.limitToLast(1).on('value', function(snapshot) {
for(var i in snapshot.val()){
$show.prepend('<div class="'+snapshot.val()[i].id+'"><div>'+snapshot.val()[i].time+'</div>'+snapshot.val()[i].name+' 說:'+snapshot.val()[i].content+'</div>');
}
//如果是自己發出去的文字,就改變顏色
$show.find('.id'+ms).css({
color:'#f00'
});
$show.find('.id'+ms+' div').css({
color:'#f00'
});
});
最後結果:
在不同視窗下看到的樣子:
小結
如果你覺得程式太多太複雜,其實 Webduino Blockly 線上編輯工具 ( https://blockly.webduino.io ) 也有提供 Firebase 的功能喔!透過積木的組合,我們依然可以寫入資料以及存取資料。
打造簡易聊天室的原理就是這樣,只要熟練 Firebase 的 API 就可以輕鬆上手,接著再繼續介紹如何跟智慧插座串接,真正來和燈泡聊聊天!
聯絡我們
如果對於 Webduino 產品有興趣,歡迎透過下列方式購買:
個人線上購買:https://store.webduino.io/ ( 支援信用卡、超商取貨付款 )
企業&學校採購:來信 [email protected] 或來電 07-3388511。
如果對於這篇教學有任何問題或建議,歡迎透過下列方式聯繫我們:
Email:[email protected] ( 如對於產品有使用上的問題,建議透過 Email 附上照片或影片聯繫 )
Facebook 粉絲團:https://www.facebook.com/webduino/
Facebook 技術討論社團:https://www.facebook.com/groups/webduino/