Chapter 15 聊天室
本章提要 15 - 1 聊天室程式的架構 15 - 2 Index.htm 與 Global.asax 應用程式檔 15 - 3 接收使用者發言的 Input.aspx 15 - 4 顯示所有發言的 ShowMsg.aspx 15 - 5 新增表情圖示與自訂文字顏色的功能 15 - 6 改良儲存與顯示發言的方式
聊天室 從本章開始, 我們會提供許多網頁應用程式的範例, 讓您瞭解如何應用前面所學的各項技術, 實際撰寫 ASP.NET 的網頁應用程式。
15 - 1 聊天室程式的架構 本章將製作如下聊天室:
聊天室程式的架構 聊天室程式乍看之下可能會覺得複雜, 但其實只要將架構拆解, 便可以發現其原理相當簡單。以下是本章聊天室程式的架構示意圖:
聊天室程式的架構 上圖中的 Index.htm 被分成上下兩個頁框 (frame), 頁框的功用是將一個網頁畫面切割成多個區域, 每個區域可各自顯示不同網頁。 而 Index.htm 網頁以頁框切割成兩部分:上頁框的來源為 ShowMsg.aspx, 下頁框的來源則為 Input.aspx。 Input.aspx 檔案會顯示可輸入的文字欄位, 讓使用者在其中輸入要發言的內容, 然後將使用者輸入的文字儲存在 Application 物件內的變數。
聊天室程式的架構 在第 7 章曾經說明 Application 是 Web 應用程式中各網頁都能存取的物件, 由於 Input.aspx 會將使用者的發言存放在 Application 物件內, 所以 ShowMsg.aspx 檔案只要從 Application 物件中逐一讀取所有的值, 即可將使用者的發言顯示於網頁上。
15 - 2 Index.htm 與 Global.asax 應用程式檔
Index.htm 的內容 從 15-1 節的架構說明中, 我們知道 Index.htm 會被分割為上下兩個頁框, 上頁框由 ShowMsg.aspx 檔顯示所有使用者的發言, 下頁框則是 Input.aspx 讓使用者輸入文字。 所以 Index.htm 的內容非常簡單, 只要使用 HTML 的頁框 (frame) 語法, 設定網頁視窗如何分割, 以及分割後各頁框的來源檔案即可:
Index.htm 的內容
Index.htm 的內容 第 8 行『rows = “*, 100”』表示要將頁框切割為上下兩個部分, 下頁框的高為 100 像素, 其餘部分皆屬於上頁框。 所以不論瀏覽器的視窗大小如何, 下頁框都會永遠保持 100 像素高, 而上頁框則會隨著視窗大小 改變高度:
Index.htm 的內容 第 9、10 行分別設定上下頁框的來源檔案為 ShowMsg.aspx 與 Input.aspx, 其中 name 屬性設定頁框名稱, 至於 scrolling 屬性則為是否要顯示捲動軸, 設定為 auto 表示如果網頁內容大於視窗才會顯示捲動軸。
Global.asax 應用程式檔 將使用者的發言存放於 Application 物件時, 最好先設定儲存的數量上限, 當發言數超過上限, 最舊的發言便不再保留, 以節省伺服器資源。 我們將在 Application 物件中定義一個名為 ChatMsgMax 的變數來設定此上限值, 並且在 Global.asax 檔案的 Application_Start 程序內設定其初始值:
Global.asax 應用程式檔
Global.asax 應用程式檔 第 7 章曾經說明 Global.asax 包含了網頁應用程式各工作階段的處理程序, 而 Application_Start 是應用程式第一次啟動時會執行的程序, 所以聊天室程式第一次執行時, 便會自動在 Application 物件內新增 ChatMsgMax 變數, 並且設定其值為 100, 表示聊天室程式最多只儲存 100 筆發言記錄。
Global.asax 應用程式檔 ChatMsgMax 變數是聊天室程式各個檔案都會使用的變數, 因此我們若是在 Application_Start 程序宣告並且定義這個變數, 之後在各 .aspx 檔案中便可以直接存取, 不需要每個檔案都重新定義 ChatMsgMax 變數。 而且未來如果想要增加儲存的發言筆數, 只要修改 Global.asax 檔即可, 不用一一修改其他檔案。
Global.asax 應用程式檔 所以建議您撰寫應用程式時, 將這種所有檔案都會用到的變數, 以中央控管的方式來定義, 對於程式的使用與維護都會比較方便。
15 - 3 接收使用者發言的 Input.aspx 下頁框的來源為 Input.aspx, 用來接收使用者發言, 然後將使用者輸入的文字儲存在 Application 物件內的變數。 Input.aspx 的控制項與運作原理 Input.aspx 的程式碼
Input.aspx 的控制項與運作原理 Input.aspx 所包含的控制項如下:
Input.aspx 的控制項與運作原理 當使用者在 UserName 與 UserMsg 欄位輸入名稱與發言後, 按下 ButtonSend 按鈕時會觸發 ButtonSend_Click 事件處理程序。 此程序會依序將發言分別儲存在 Application 物件的 ChatMsg1、ChatMsg2、ChatMsg3...變數內, 儲存數量則依 ChatMsgMax 變數而定。
Input.aspx 的控制項與運作原理 例如假設 ChatMsgMax 變數的值為 10, 則發言會儲存在 ChatMsg1 ~ ChatMsg10 共 10 個變數內 (隨後會以 ChatMsgX 稱呼這些變數)。 下面則是發 言儲存方式 的示意圖:
Input.aspx 的控制項與運作原理 從示意圖中可以看到, 舊的發言會依序往下搬移, 最舊的發言會因為被覆蓋而消失, 然後空出的 ChatMsg1 變數則用來儲存最新的發言。 所以未來要顯示發言時, 只要依序從 ChatMsg1 往後讀取各變數, 便可以讓發言依照時間順序顯示。
Input.aspx 的控制項與運作原理 總結前述, Input.aspx 的程式流程如下:
Input.aspx 的程式碼 依照前面說明的邏輯, Input.aspx 的程式碼如下:
Input.aspx 的程式碼
Input.aspx 的程式碼
Input.aspx 的程式碼 第 27 行使用 Now 取得目前伺服器的時間, 因為通常聊天室只會顯示發言時間而不顯示日期, 所以使用 ToShortTimeString() 方法, 只輸出時間的部分, 並且使用簡短的格式, 例如『下午 02:10』。
Input.aspx 的程式碼 第 30〜32 行會將留言中出現的空白及 < 、 > 符號取代為 HTML 特殊符號表示法, 雖然聊天室通常以一句話為單位, 不會遇到換行, 但是仍然會遇到空白字元的問題, 所以程式第 30 行使用字串物件的 Replace() 方法, 將空白字元代換為 HTML 的特殊符號。
Input.aspx 的程式碼 HTML 語法中, < 與 > 是用來設定標籤的字元, 如果要在網頁上顯示這兩個字元, 也必須使用特殊符號來表示, 所以程式第 31、32 行會將設定標籤的字元代換為特殊符號, 如此除了可以在網頁上顯示 < 與 >, 也能避免使用者在發言時, 夾帶惡意的 HTML 或 JavaScript 語法。
15 - 4 顯示所有發言的 ShowMsg.aspx ShowMsg.aspx 位於上頁框中, 用以顯示所有使用者的發言, 其中只有一個 Label 控制項: ShowMsg.aspx 的運作方式相當簡單, 在 Page_Load 程序一一讀取所有使用者的發言, 然後將發言顯示於 Label 控制項。
顯示所有發言的 ShowMsg.aspx 因為 Input.aspx 會由新至舊將發言依序儲存於 Application 物件的 ChatMsgX 變數, 所以 ShowMsg.aspx 要顯示發言時, 只要使用迴圈逐一讀取 ChatMsgX 變數的值, 並附加於 Label 控制項的 Text 屬性, 這樣網頁上自然會由新至舊依序顯示所有發言。 依照前面說明的邏輯, ShowMsg.aspx 的原始碼如下:
顯示所有發言的 ShowMsg.aspx
顯示所有發言的 ShowMsg.aspx
顯示所有發言的 ShowMsg.aspx 上面第 25 行是 HTML 語法, 表示網頁會於 3 秒後重新轉址到 Showmsg.aspx, 因為是同一個網頁, 所以這個語法便具有網頁自動重新整理的效果:每 3 秒便會自動重新讀取並顯示所有發言, 才能讓新的發言顯示於網頁上。 至此一個簡易的聊天室已經完成, 只要執行 Ch15-01 資料夾內的 Index.htm, 便會顯示以下聊天室功能:
顯示所有發言的 ShowMsg.aspx
15 - 5 新增表情圖示與自訂文字顏色的功能 前面已經製作出一個簡易聊天室, 對於聊天室的原理與架構也有了基本的瞭解。從本節開始針對程式進行改良, 加入表情圖示與文字顏色的功能。
如何加入表情圖示與顏色 文字對談最大的缺點就是無法看到對方的表情, 所以一般聊天室或是即時通訊都會具備表情圖示的功能:
如何加入表情圖示與顏色 製作這樣的功能並不難, 只要在程式中進行下面的字串代換即可: 除了表情圖案以外, 許多聊天室或是即時通訊都可以讓使用者自訂文字的顏色, 不然所有使用者的發言都是標準的黑色, 混雜在一起時實在不易分辨每個人的發言。
如何加入表情圖示與顏色 要讓發言的文字加上顏色, 只要在程式中, 將使用者的發言加上包含顏色樣式的 <span> 標籤即可:
製作表情圖示的功能 我們將表情圖示的圖檔存於網站的 images 資料夾, 並將代換的語法都放在 Global.asax 的 Application_Start 程序:
製作表情圖示的功能
製作表情圖示的功能 上面使用 N x 2 的二維陣列儲存使用者資料, Smile (0, 0)、Smile (1, 0)、Smile (2, 0)...代表各表情符號, 而 Smile (0, 1)、Smile (1, 1)、Smile (2, 1)...則是對應的圖示檔名。
製作表情圖示的功能 設定好表情符號與圖案檔的對應後, 便可以在接收使用者發言的 Input.aspx 檔的 ButtonSend_Click 程序中加入相關程式, 在使用者發言儲存於 ChatMsgX 變數之前, 先依序將表情符號代換為顯示圖案檔的 HTML 標籤即可:
製作表情圖示的功能 程式第 34 行要使用迴圈逐一代換表情時, 必須先算出目前有多少筆設定, 才能設定迴圈的結束條件。
製作表情圖示的功能 前面第 3 章曾經說明『陣列名稱 .Length』可以取得陣列的長度, 對於二維陣列, 此屬性傳回的長度為『所有』元素的個數, 例如上面程式的 4 x 2 陣列, Length 屬性會傳回 8, 所以要將 Length 除以 2, 才能得到已設定的表情筆數。
製作自訂文字顏色的功能 為了讓使用者可以選擇訊息的顏色, 可在接收發言的 Input.aspx 檔加入一個 DropDownList 控制項, 列出可用的顏色名稱:
製作自訂文字顏色的功能
製作自訂文字顏色的功能 程式在儲存使用者發言之前, 將發言內容加上 HTML 的 <span> 標籤與顏色設定:
製作自訂文字顏色的功能 目前聊天室已經具備了表情圖示與自訂文字顏色的功能, 請執行 Ch15-02 資料夾內的 Index.htm, 便會顯示以下聊天室功能:
製作自訂文字顏色的功能
15 - 6 改良儲存與顯示發言的方式 現在我們的聊天室已經具備基本與常用功能了, 不過還有下面 2 個缺點可以改善: 1. 儲存發言的方式效率不佳:目前聊天室使用 15-6 頁所示範的方式儲存發言, 一旦 ChatMsgMax 變數值設定得較大, 假設為 1000, 此時聊天室可儲存 1000 筆發言, 當最新的發言輸入時, 這種方式必須先移動 999 筆舊發言, 才能空出 ChatMsg1 變數存放最新發言, 所以此方式雖然簡單易懂, 卻是一個效率不佳的方式。
改良儲存與顯示發言的方式 2 .顯示發言的方式與一般習慣不同:一般聊天室與即時通訊都是將最新發言放在最下面, 而目前我們的聊天室是將最新發言顯示於最上方, 與一般的習慣不相同。
使用指標的方式儲存最新發言 為了改善效率的問題, 我們將改用類似指標的方式來儲存最新發言, 假設聊天室最多可記錄 5 筆發言數 (ChatMsgMax 變數值為 5), 則新的儲存方式示意圖如下 (方框內的數字代表發言時間):
使用指標的方式儲存最新發言
使用指標的方式儲存最新發言 從上面可以看到, 改良過的方式直接將最新發言存放在指標所指向的變數, 即可省去將舊發言逐一向下搬移的步驟。 另外因為指標所指的變數便是目前最新的發言, 加上各發言儲存於變數時仍然帶有時間上的順序, 所以若需由新至舊顯示發言, 只要從指標所指之處向上讀取即可;如果要由舊至新顯示, 則從指標所指之下一處開始, 往下讀取就可以了。
使用指標的方式儲存最新發言 這種方式需要注意的地方, 在於指標累加之後, 可能會超出 ChatMsgMax 所限制的筆數範圍, 此時只要讓指標的值減去 ChatMsgMax, 即可將指標拉回至最前面。 筆者將指向最新發言的指標變數稱為 ChatMsgLast, 在 Global.asax 的 Application_Start 程序建立 Application 物件的 ChatMsgLast 變數, 並且設定其值為 0:
使用指標的方式儲存最新發言 所以聊天室的其他程式只要存取 Application 物件的 ChatMsgLast 變數, 即可取得目前最新發言的位置。
在 Input.aspx 改用新的發言儲存方式
在 Input.aspx 改用新的發言儲存方式 如此即可讓使用者的發言依照新的方式, 儲存於 Application 物件的 ChatMsgX 變數中。
在 ShowMsg.aspx 改用新方式讀取並顯示發言 修改完儲存發言的 Input.aspx 檔案後, 接著便是將顯示發言的 ShowMsg.aspx 改換成新方式, 兩者要使用同一方式才能互相配合, 正確地儲存與顯示使用者的發言。 另外如本節最前面所述, 我們想要將最新發言放在最下面, 以符合一般的使用習慣, 所以依照 15-15 頁的說明, 要由舊至新顯示發言時, 應該從指標所指之下一處開始, 逐一往下讀取就可以了。ShowMsg.aspx 的原始碼如下:
在 ShowMsg.aspx 改用新方式讀取並顯示發言
在 ShowMsg.aspx 改用新方式讀取並顯示發言
在 ShowMsg.aspx 改用新方式讀取並顯示發言 如此修改後, 聊天室便完成改用新的儲存方式, 並且也會由舊至新顯示發言:
在 ShowMsg.aspx 改用新方式讀取並顯示發言 不過, 這樣的聊天室還有一個問題, 因為最新發言顯示於舊發言的下面, 所以當上頁框的內容超過一頁時, 便看不到新的發言了。為了解決這個問題, 我們可以在上頁框的網頁中加入一段自動往下捲頁的 JavaScript 程式:
在 ShowMsg.aspx 改用新方式讀取並顯示發言 上面程式第 48 行的 document.body.scrollHeight 可取得目前頁面能捲動的高度, 然後使用 scrollTo( ) 函式即可將頁面捲動至最下面: