《基於Node.js實現簡易聊天室系列之詳細設計》
一個完整的項目基本分為三個部分:前端、後台和資料庫。依照軟體工程的理論知識,應該依次按照以下幾個步驟:需求分析、概要設計、詳細設計、編碼、測試等。由於缺乏相關知識的儲備,導致這個Demo系列的文章層次不是很清楚,索性這一章將所有的過程(前後端以及資料庫)做一個介紹,下一章寫完總結就OK了吧。
(1)前端部分
涉及到的技術:html、css、bootstrap、jquery、jquery UI
登錄/註冊界面使用的是bootstrap響應式布局,即支持不同尺寸的客戶端,以此提高用戶的體驗。在這之前我以為聊天室比較適合做成SPA(單頁應用),想採取backbone,但是結合畢設的主題是基於Node.js,如果採用backbone,路由功能就有兩種選擇,backbone和Node.js都有著豐富的路由API,由於之前沒有用Node.js做過相關項目,所以就放棄了backbone。Demo通過改變css中display的屬性來控制div的顯示與隱藏。
頁面:
1
12
13
14
15
17
Or
18
19
20
28
29
30
31
32
33
37
38
39
40
43
44
45
46
47
-
48
- Setting
- Switch
- Layout
49
50
51
52
53
-
54
- Update Password
- Personal Sign
- Head Portrait
55
56
57
58
60
61
62
63
65
66
67
*Double click the picture to select
69
-
71
72
73
74
83
84
86
87
88
90
92
93
96
97
98
99
104
105
106
108
110
113 All Members
114 /
115
116
117
118
119
122 Room Members
123
124
125
-
126
127
128
129
131
132
133
134
135
136
137
138
139
140
141
View Code
js:
1 $(function {
2 var CookieObj = {}, socket = io, headInfo = "群聊 (";;
3 window.onbeforeunload = function (e) {
4 if (document.cookie) return false;
5 }
6 render;
7 /*
8 *登錄
9 */
10 var onLogin = function (e) {
11 var xhr;
12 if (!$("#username").val || !$("#userpassword").val) return;
13 xhr = $.ajax({
14 url: "/login",
15 type: "POST",
16 dataType: "json",
17 data: {
18 name: $("#username").val,
19 password: $("#userpassword").val
20 }
21 })
22 .done(function (data, textStatus, jqXHR) {
23 if (data.value === "Y") {
24 render;
25 } else {
26 $("#SignInErr").html(data.msg);
27 }
28 })
29 .fail(function (jqXHR, textStatus, errorThrown) {
30 $("#SignInErr").html("Error occured! Please try again.");
31 });
32 };
33 /*
34 *註冊
35 */
36 var onSignup = function (e) {
37 var xhr;
38 if (!$("#upName").val || !$("#upPassword").val) return;
39 xhr = $.ajax({
40 url: "/signup",
41 type: "POST",
42 dataType: "json",
43 data: {
44 name: $("#upName").val,
45 password: $("#upPassword").val
46 }
47 })
48 .done(function (data, textStatus, jqXHR) {
49 if (data.value === "Y") {
50 $("#SignUpErr").html(data.msg || "Login now with these credentials.");
51 } else {
52 $("#SignUpErr").html(data.msg || "Invalid username");
53 }
54 })
55 .fail(function (jqXHR, textStatus, errorThrown) {
56 $("#SignUpErr").html("Error occured! Please try again.");
57 });
58 };
59
60 var onMsgSubmit = function {
61 var str = $("#msg").val;
62 var sendMsg = replace_em(str);
63 if (!sendMsg || sendMsg.length > 1261) {
64 alert("err:內容為空或者內容長度超出限制!")
65 $("#msg").val("");
66 return;
67 }
68 var roomOf = $("#headmessages strong").html;
69 socket.emit("chat message", sendMsg, CookieObj.h_imgPath, roomOf);
70 $("#msg").val("");
71 return false;
72 };
73
74 socket.on("sysJoin", function (msg) {
75 var joinInfo = "";
76 joinInfo = "
";
77 $(joinInfo).appendTo($("#messages")).animate({ "opacity": 0.5 }, 2000, function {
78 $(this).animate({ "opacity": 1 }, 1500, function {
79 $(this).animate({ "opacity": 0.3 }, 1000);
80 });
81 });
82 scroll;
83 });
84
85 socket.on("chat message", function (name, msg, img) {
86 var str = "";
87 if (name == CookieObj.name) {
88 str = "
" + msg + "
" + "
";
89 } else {
90 str = "
" + msg + "
";
91 }
92 $("#messages").append(str);
93 scroll;
94 });
95
96 /*房間選擇*/
97 //默認是進廣場,從其他房間執行如下函數
98 $("#selectmenu li").eq(0).on("click", function (e) {
99 e.stopPropagation;
100 $("#selectRoom").hide;
101 $("#headmessages strong").html("Square");
102 socket.emit("join", "Square", $("#gloableName").html);
103 $("#messages").empty;
104 });
105 $("#selectmenu li").eq(1).on("click", function (e) {
106 e.stopPropagation;
107 $("#selectRoom").show;
108 });
109 //選擇秦時明月或火影忍者房間
110 $("#selectRoom li").on("click", function {
111 var roomName = $(this).children("span").html;
112 var userName = $("#gloableName").html;
113 $("#headmessages strong").html(roomName);
114 socket.emit("join", roomName, userName);
115 $("#messages").empty;
116 });
117
118
119
120 /*
121 *接收所有已註冊用戶的信息
122 */
123 socket.on("onlineUser", function (online) {
124 var onlineStr = "";
125 for (var i = 0; i < online.length; i++) {
126 var item = online[i];
127 onlineStr += "
";
128 }
129 $("#AllOnline").empty;
130 $("#oncount").html(online.length);
131 $("#AllOnline").append(onlineStr);
132 });
133 socket.on("outlineUser", function (outline) {
134 var outlineStr = "";
135 for (var i = 0; i < outline.length; i++) {
136 var item = outline[i];
137 outlineStr += "
";
138 }
139 $("#AllOutline").empty;
140 $("#AllOutline").append(outlineStr);
141 });
142 socket.on("allUser", function (doc) {
143 $("#allcount").html(doc.length);
144 });
145 socket.on("disconnect", function (name, msg) {
146 var leftInfo = "";
147 leftInfo = "
";
148 $(leftInfo).appendTo($("#messages")).animate({ "opacity": 0.3 }, 2000, function {
149 $(this).animate({ "opacity": 1 }, 1500, function {
150 $(this).animate({ "opacity": 0.3 }, 1000);
151 });
152 return this;
153 });
154 scroll;
155 });
156
157 /*當前房間人員信息*/
158 var Lastr, r1, r2, r3;
159 socket.on("SquareRoom", function (roomInfo) {
160 r1 = roomInfo;
161 UpdateRoom;
162 });
163 socket.on("QinRoom", function (roomInfo) {
164 r2 = roomInfo;
165 UpdateRoom;
166 });
167 socket.on("NarutoRoom", function (roomInfo) {
168 r3 = roomInfo;
169 UpdateRoom;
170 });
171 function UpdateRoom {
172 var $Nowroom = $("#headmessages strong").html, roomCount, roomStr = "";
173 switch ($Nowroom) {
174 case "Square": Lastr = r1; break;
175 case "The Legend of Qin": Lastr = r2; break;
176 case "Naruto": Lastr = r3; break;
177 default: Lastr = r1;
178 }
179 roomCount = Lastr.length;
180 for (var i = 0; i < roomCount; i++) {
181 var item = Lastr[i];
182 roomStr += "
";
183 }
184 $("#roomCount").html(roomCount);
185 $("#Roommembers ul").empty;
186 $("#Roommembers ul").append(roomStr);
187 }
188 /*
189 *切換/退出賬號
190 */
191 $("#changeUser").on("click", function {
192 var res = confirm("Are you sure you want to quit and switch to another account??");
193 if (res) {
194 UL;
195 } else {
196 $("#control").hide;
197 $("#setContent").hide;
198 $("#stateSelect").hide;
199 }
200 });
201 $("#layout").on("click", UL);
202 function UL {
203 if (document.cookie) {
204 $("#loginDiv").addClass("hidden");
205 $("#main").removeClass("hidden");
206 var uname = getCookie("userInfo");
207 CookieObj = JSON.parse(uname.substr(2));
208 $.ajax({
209 url: "/layout",
210 type: "POST",
211 dataType: "json",
212 data: {
213 name: CookieObj.name
214 }
215 })
216 .done(function (data, textStatus, jqXHR) {
217 if (data.value === "Y") {
218 clearCookie;
219 window.location.reload;
220 }
221 });
222 };
223 }
224
225 $("#signinForm #loginBtn").click(onLogin);
226 $("#signupForm #signupBtn").click(onSignup);
227 $("#chatMsgForm #send").click(onMsgSubmit);
228
229 $("#clear").on("click", function {
230 $("#messages").empty;
231 });
232
233 /*
234 *監聽滾動條事件
235 */
236 $("#messages").get(0).onscroll = function {
237 $("#messages .Liright").css("margin-right", 1);
238 }
239
240 /*
241 *屏蔽回車鍵
242 */
243 $(document).keydown(function (event) {
244 switch (event.keyCode) {
245 case 13: return false;
246 }
247 });
248 /*
249 *用戶信息
250 */
251 $(".headImg").eq(0).on("click", function (e) {
252 e.stopPropagation;
253 if ($("#control").get(0).style.display == "none") {
254 $("#control").show;
255 } else {
256 $("#control").hide;
257 $("#setContent").hide;
258 $("#stateSelect").hide;
259 }
260 });
261
262 /*更改資料*/
263 $("#set").on("click", function {
264 $("#setContent").show;
265 $("#stateSelect").hide;
266 });
267 /*構造頭像選擇內容*/
268 var imgStr = "";
269 for (var i = 1; i <= 18; i++) {
270 imgStr += "
";
271 if (i % 6 == 0) {
272 imgStr += "
";
273 }
274 }
275 $("#setThree #imgContent ul").eq(0).append(imgStr);
276 $("#setThree #imgContent li img").on("click", function (e) {
277 e.stopPropagation;
278 var $index = $(this).attr("data-in");
279 $("#setThree #imgContent img").removeClass("imgSelected");
280 $("#setThree #imgContent img").eq(($index - 1)).addClass("imgSelected");
281 });
282 /*人物頭像模態框*/
283 $("#setThree").dialog({
284 autoOpen: false,
285 title: "Changing Avatar",
286 modal: true,
287 width: 578,
288 resizable: false,
289 buttons: {
290 "Ok": function {
291 var selectedImg = $(".imgSelected").attr("data-in");
292 // alert(selectedImg);
293 $.ajax({
294 url: "/updateImg",
295 type: "POST",
296 data: {
297 name: $("#control div span").eq(0).html,
298 imgIndex: selectedImg
299 }
300 }).done(function (data) {
301 if (data.value === "Y") {
302 $("#setThree").dialog("close");
303 $(".headImg").eq(0).attr("src", "/img/" + selectedImg + ".jpg");
304 $("#setContent").hide;
305 $("#control").hide;
306 // alert(data.msg);
307 }
308 });
309 ;
310 }
311 }
312 });
313 /*個性簽名模態框*/
314 $("#setTwo").dialog({
315 autoOpen: false,
316 title: "Personalized signature setting",
317 modal: true,
318 resizable: false,
319 buttons: {
320 "OK": function {
321 var $newSign = $("#setTwo input[type="text"]").eq(0).val;
322 if ($newSign != "") {
323 $.ajax({
324 url: "/updateSign",
325 type: "POST",
326 data: {
327 name: $("#control div span").eq(0).html,
328 newSign: $newSign
329 }
330 }).done(function (data) {
331 if (data.value === "Y") {
332 $("#setTwo p").eq(0).html(data.msg);
333 setTimeout(function {
334 $("#control div em").eq(0).html($newSign);
335 $("#setTwo").dialog("close");
336 $("#setTwo p").eq(0).html("");
337 }, 1000);
338 }
339 });
340 }
341 },
342 "Cancel": function {
343 $(this).dialog("close");
344 }
345 }
346 });
347 /*密碼模態框*/
348 $("#setOne").dialog({
349 autoOpen: false,
350 title: "Changeing User password",
351 modal: true,
352 resizable: false,
353 buttons: {
354 "Ok": function {
355 var $oldpass = $("#setOne #oldpass").val, $newpass = $("#setOne #newpass").val;
356 if ($oldpass != "" && $newpass != "") {
357 $.ajax({
358 url: "/changepass",
359 type: "POST",
360 data: {
361 name: $("#control div span").eq(0).html,
362 oldpass: $oldpass,
363 newpass: $newpass
364 }
365 }).done(function (data, textStatus, jqXHR) {
366 if (data.value === "Y") {
367 $("#setOne p").eq(0).html(data.msg);
368 setTimeout(function {
369 clearCookie;
370 $("#setOne p").eq(0).html("");
371 window.location.reload;
372 }, 1000);
373 } else if (data.value === "N") {
374 $("#setOne p").eq(0).html(data.msg);
375 $("#setOne #oldpass").val("");
376 $("#setOne #newpass").val("");
377 }
378 });
379 }
380 },
381 "Cancel": function {
382 $(this).dialog("close");
383 }
384 }
385 });
386 $("#setContent li").eq(0).click(function (e) {
387 e.stopPropagation;
388 $("#setOne").dialog("open");
389 });
390 $("#setContent li").eq(1).click(function (e) {
391 e.stopPropagation;
392 $("#setTwo").dialog("open");
393 });
394 $("#setContent li").eq(2).click(function (e) {
395 e.stopPropagation;
396 $("#setThree").dialog("open");
397 });
398
399 /*
400 *成員信息面板控制:包括所有成員和具體房間成員的狀態
401 */
402 $("#rightSide #Roommembers ul").hide;
403 $("#Allmembers div").css({ "backgroundColor": "rgb(70,130,180)", "color": "white" });
404 $("#Allmembers div i").addClass("glyphicon glyphicon-triangle-bottom");
405 $("#Roommembers div i").addClass("glyphicon glyphicon-triangle-right");
406 $("#rightSide div >div").click(function (e) {
407 var $title = $(this), $anotherTitle = $(this).parent.siblings("div");
408 if ($title.next("ul").is(":visible")) {
409 $title.siblings("ul").hide;
410 $title.children("i").removeClass("glyphicon glyphicon-triangle-bottom").addClass("glyphicon glyphicon-triangle-right");
411 $title.css({ "backgroundColor": "", "color": "" });
412 } else {
413 $anotherTitle.children("ul").hide;
414 $anotherTitle.children("div").css({ "backgroundColor": "", "color": "" });
415 $anotherTitle.children("div").children("i").removeClass("glyphicon glyphicon-triangle-bottom").addClass("glyphicon glyphicon-triangle-right");
416 $title.css({ "backgroundColor": "rgb(70,130,180)", "color": "white" });
417 $title.siblings("ul").slideToggle(500).show;
418 $title.children("i").removeClass("glyphicon glyphicon-triangle-right").addClass("glyphicon glyphicon-triangle-bottom");
419 }
420 });
421
422 /*函數集*/
423
424 /*
425 *保證scroll始終在最底端
426 */
427 function scroll {
428 $("#messages,#oldMsg ul").animate({
429 scrollTop: 999999999
430 }, 0);
431 }
432
433 /*
434 *刪除cookie
435 */
436 function clearCookie {
437 var keys = document.cookie.match(/[^=;]+(?==)/g);
438 if (keys) {
439 var i = keys.length;
440 while (i--) {
441 document.cookie = keys[i] + "=0;expires=" + new Date(0).toUTCString;
442 }
443 }
444 }
445
446 /*
447 *獲取cookie
448 */
449 function getCookie(sname) {
450 var aCoookie = document.cookie.split(";");
451 for (var i = 0; i < aCoookie.length; i++) {
452 var aCrumb = aCoookie[i].split("=");
453 if (sname == aCrumb[0])
454 return decodeURIComponent(aCrumb[1]);
455 }
456 return null;
457 }
458
459 /*
460 *界面render
461 */
462 function render {
463 if (document.cookie) {
464 $(".container").addClass("hidden");
465 $("#main").removeClass("hidden");
466 var uname = getCookie("userInfo");
467 CookieObj = JSON.parse(uname.substr(2));
468 socket.emit("join", $("#headmessages strong").html, CookieObj.name);
469 $(".headImg").eq(0).attr("src", CookieObj.h_imgPath);
470 $("#control div span").eq(0).html(CookieObj.name);
471 $("#control div em").eq(0).html(CookieObj.personalizedSign);
472 };
473 }
474 $(".emotion").qqFace({
475 id: "facebox",
476 assign: "msg",
477 path: "img/" //表情存放的路徑
478 });
479 function replace_em(str) {
480 str = str.replace(//g, ">");
482 str = str.replace(/
/g, "
");
483 str = str.replace(/[em_([0-9]*)]/g, "");
484 return str;
485 }
486 /*查詢聊天記錄*/
487 $("#chatRecord").on("click", function {
488 $.ajax({
489 url: "/queryChatMsg",
490 type: "POST",
491 data: {
492 roomName: $("#headmessages strong").html
493 }
494 }).done(function (data) {
495 var Msg = data.msg;
496 var msgStr = "",
497 $name = $("#control div span").eq(0).html;
498 for (var i = 0; i < Msg.length; i++) {
499 var item = Msg[i];
500 if (item.name == $name) {
501 msgStr += "
" + item.msg + "
";
502 } else {
503 msgStr += "
" + item.msg + "
";
504 }
505 }
506 $("#oldMsg ul").empty;
507 $("#oldMsg ul").css({ "background-img": "url("/img/loading.gif")" });
508 $("#rightSide").hide;
509 $("#oldMsg").show;
510 setTimeout(function {
511 $("#oldMsg ul").append(msgStr);
512 scroll;
513 }, 2000);
514 });
515 });
516
517 /*關閉歷史記錄窗口*/
518 $("#oldMsgHead i").on("click", function {
519 $("#oldMsg ul").empty;
520 $("#oldMsg").hide;
521 $("#rightSide").show;
522 });
523 /*清空聊天歷史消息*/
524 $("#clearoldMsg i").on("click", function {
525 var result = confirm("This action will delete the chat record on the database. Do you want to continue?");
526 if (result) {
527 $.ajax({
528 url: "/deleteMsg",
529 type: "POST",
530 data: {
531 roomName: $("#headmessages strong").html
532 }
533 }).done(function (data) {
534 if (data.value === "Y") {
535 alert(data.msg);
536 $("#oldMsg ul").empty;
537 $("#oldMsg").hide;
538 $("#rightSide").show;
539 }
540 });
541 }
542 });
543 //多行文本輸入框自動聚焦
544 $("#msg").focus;
545 //獲取當前城市以及城市天氣
546 function findWeather {
547 var cityUrl = "http://int.dpool.sina.com.cn/iplookup/iplookup.php?format=js";
548 $.getScript(cityUrl, function (script, textStatus, jqXHR) {
549 var citytq = remote_ip_info.city;// 獲取城市
550 var url = "http://php.weather.sina.com.cn/iframe/index/w_cl.php?code=js&city=" + citytq + "&day=0&dfc=3";
551 $.ajax({
552 url: url,
553 dataType: "script",
554 scriptCharset: "gbk",
555 success: function (data) {
556 var _w = window.SWther.w[citytq][0];
557 var _f = _w.f1 + "_0.png";
558 if (new Date.getHours > 17) {
559 _f = _w.f2 + "_1.png";
560 }
561 var img = "";
563 // var tq = citytq + " " + img + " " + _w.s1 + " " + _w.t1 + "℃~" + _w.t2 + "℃ " + _w.d1 + _w.p1 + "級";
564 var tq = img + _w.s1 + " " + citytq + "
 " + _w.t2 + "℃~" + (_w.t1 || 25) + "℃ " + "";
565 $("#weather").html(tq);
566 }
567 });
568 });
569 }
570
571 findWeather;
572 });
View Code
主界面如下圖所示即聊天分為三個模塊(左中右)即:左為功能模塊,用戶可以進行房間的選擇,以及點擊自己的圖像修改個人資料等操作;中為聊天模塊,顯示當前房間聊天內容以及聊天信息輸入框;右為信息展示模塊,默認顯示所有在線用戶信息以及當前房間在線成員信息,用戶可以切換查看當前房間歷史聊天記錄。
(2)資料庫
涉及到的技術:mongoDB、mongoose
由於javascript是一門弱類型語言,所以操作資料庫沒有java、php等語言方便。但是我們可以通過mongoose建立模型model映射到資料庫中去,將對資料庫的操作轉換到操作model中去。
1 var mongoose = require("mongoose");
2 var msgRecord=new mongoose.Schema({
3 name:{
4 type:String,
5 index:true,
6 },
7 roomName:{
8 type:String
9 },
10 msg:{
11 type:String,
12 },
13 saytime:{
14 type:String,
15 }
16 });
17 var UserSchema = new mongoose.Schema({
18 name: {
19 type: String,
20 unique: true,
21 index: true
22 },
23 password:{
24 type: String,
25 index: true
26 },
27 user_id: {
28 type: mongoose.Schema.Types.ObjectId,
29 index: true
30 },
31 updated: {
32 type: Date, default: Date.now
33 },
34 status: {
35 type: Boolean,
36 default: false
37 },
38 h_imgPath: {
39 type: String,
40 default:"/img/1.jpg"
41 },
42 personalizedSign:{
43 type:String,
44 default:"Write something will well`"
45 }
46 });
47
48 var User = mongoose.model("User", UserSchema);
49 var Msg=mongoose.model("Msg",msgRecord);
50 module.exports = {
51 User:User,
52 Msg:Msg
53 };
View Code
(3)後台
涉及到的技術:Node.js,socket.io,Express
後台作為前端和資料庫的橋樑,接收前端傳過來的參數,去請求伺服器,響應不同的服務請求。同時,通過socket.io進行實時通信,實時通信的前提是在客戶端也要引入相關的js文件,通過on和emit方法、自定義事件達到目的
操作socket.io
1 var users = {};
2 var QueryUser = require("./mongoDB/models/model").User;
3 var Msg = require("./mongoDB/models/model").Msg;
4 //獲取實時時間
5 function gettime {
6 var time = new Date;
7 var timepartone = time.getFullYear + "-" + (time.getMonth + 1) + "-" + time.getDate + " ";
8 var timemid = time.getHours, s;
9 if (timemid < 6) {
10 s = "凌晨 " + timemid;
11 } else if (timemid < 12) {
12 s = "上午 " + timemid;
13 } else if (timemid < 18) {
14 s = "下午 " + "0" + (timemid - 12);
15 } else {
16 s = "晚上 " + (timemid - 12);
17 }
18 var timeparttwo = s + ":" + (time.getMinutes < 10 ? "0" + time.getMinutes : time.getMinutes);
19 return timepartone + timeparttwo;
20 }
21 /*創建三個房間:Square、The Legend of Qin、Naruto*/
22 var rooms = { "Square": , "The Legend of Qin": , "Naruto": };
23 var user = "";
24 module.exports = function (app, io) {
25 io.on("connection", function (socket) {
26 socket.on("join", function (roomName, userName) {
27 user = userName;
28 users[socket.id] = userName;
29 for (var i in rooms) {
30 if (roomName != i) {
31 var index = rooms[i].indexOf(user);
32 if (index !== -1) {
33 console.log("刪除前" + rooms[i]);
34 rooms[i].splice(index, 1);
35 io.to(i).emit("sysLeft", user + "退出了房間" + roomName);
36 socket.leave(i);
37 console.log(userName + "離開了房間" + i + ":這個房間里還有" + rooms[i]);
38 }
39 }
40 }
41 var flag = true;
42 for (var j = 0; j < rooms[roomName].length; j++) {
43 if (rooms[roomName][j] == user) {
44 flag = false;
45 }
46 }
47 if (flag) {
48 rooms[roomName].push(user);
49 socket.join(roomName);
50 }
51 io.sockets.in(roomName).emit("sysJoin", user + "加入了房間" + roomName);
52 total;
53 console.log(user + "加入了" + roomName);
54 });
55 socket.on("chat message", function (msg, img, roomOf) {
56 var name = "";
57 name = users[socket.id];
58 var newMsg = new Msg({ name: name, msg: msg, saytime: gettime,roomName:roomOf });
59 newMsg.save;
60 if (rooms[roomOf].indexOf(name) === -1) {
61 return false;
62 }
63 console.log(roomOf + ":" + msg);
64 io.sockets.in(roomOf).emit("chat message", name, msg, img);
65 });
66 socket.on("disconnect", function {
67 var msg = "", name = "", time = "";
68 time = gettime;;
69 name = users[socket.id];
70 for (var i in rooms) {
71 var index = rooms[i].indexOf(name);
72 if (index !== -1) {
73 console.log("刪除前" + rooms[i]);
74 rooms[i].splice(index, 1);
75 io.to(i).emit("sysLeft", name + "退出了房間" + i);
76 socket.leave(i);
77 console.log(name + "離開了房間" + i + ":這個房間里還有" + rooms[i]);
78 }
79 }
80 msg = name + "離開群聊 " + time;
81 io.emit("disconnect", name, msg);
82 var timeTotal = total;
83 });
84 //獲取總用戶
85 function total {
86 QueryUser.find({}, function (err, doc) {
87 io.emit("allUser", doc);
88 });
89 QueryUser.find({ status: false }, function (err, doc) {
90 io.emit("outlineUser", doc);
91 });
92 QueryUser.find({ status: true }, function (err, doc) {
93 io.emit("onlineUser", doc);
94 });
95 //查詢房間里成員的信息
96 /*三個房間:Square、The Legend of Qin、Naruto*/
97 var F_RMInfo = , S_RMInfo = , T_RMInfo = ;
98 for (var k = 0; k < rooms["Square"].length; k++) {
99 QueryUser.findOne({ name: rooms["Square"][k] }, function (err, doc) {
100 F_RMInfo.push(doc);
101 io.sockets.in("Square").emit("SquareRoom", F_RMInfo);
102 console.log(F_RMInfo);
103 });
104 }
105 for (var i = 0; i < rooms["The Legend of Qin"].length; i++) {
106 QueryUser.findOne({ name: rooms["The Legend of Qin"][i] }, function (err, doc) {
107 S_RMInfo.push(doc);
108 io.sockets.in("The Legend of Qin").emit("QinRoom", S_RMInfo);
109 console.log(S_RMInfo);
110 });
111 }
112 for (var j = 0; j < rooms["Naruto"].length; j++) {
113 QueryUser.findOne({ name: rooms["Naruto"][j] }, function (err, doc) {
114 T_RMInfo.push(doc);
115 io.sockets.in("Naruto").emit("NarutoRoom", T_RMInfo);
116 console.log(T_RMInfo);
117 });
118 }
119 }
120 });
121
122 };
View Code
伺服器js
1 var express = require("express"),
2 cookieParser = require("cookie-parser"),
3 bodyParser = require("body-parser"),
4 http = require("http"),
5 path = require("path"),
6 io = require("socket.io"),
7 mongoose = require("mongoose"),
8 app = express,
9 db,
10 userRoutes,
11 socketIO;
12
13 /* 資料庫連接 */
14 mongoose.connect("mongodb://localhost:27017/chatroom");
15 db = mongoose.connection;
16 db.on("error", console.error.bind(console, "資料庫連接失敗!"));
17 db.once("open", function callback {
18 console.log("資料庫連接成功!");
19 });
20
21 /*Express 配置*/
22 app.use(cookieParser);
23 app.use(bodyParser.json);
24 app.use(bodyParser.urlencoded({ extended: true }));
25 app.use(express.static(path.join(__dirname, "public")));
26
27
28 http=http.createServer(app,function(req,res){
29 res.writeHead(200, {"Content-Type": "text/html;charset=utf-8"});
30 });
31 io = io(http);
32
33 indexRoutes = require("./routes/index")(app);
34 userRoutes = require("./routes/users")(app);
35
36 /*綁定io到伺服器上*/
37 socketIO = require("./socketIO")(app, io);
38
39 http.listen(3000, function {
40 console.log("listening on *:3000");
41 });
View Code


※bboss log4j滾動日誌文件擴展插件使用介紹
※bencode對象編碼實現
※Docker Machine 詳解
TAG:科技優家 |
※Node.js 專題系列
※基於 hapi的Node.js 小程序後端開發實踐指南
※簡單理解node.js
※Windows系統下如何搭建Node.js伺服器詳解
※Node.js應用Linux部署實戰
※Node.js之express框架
※Node.js 製作驗證碼API
※基於 node.js 的自動路由組件-HttpPostman
※簡單好上手的node.js ORM框架
※Node.js進階:cluster模塊深入剖析
※Node.js 主題周
※大規模集群下的Hadoop NameNode
※blogfoster-scripts:一款簡化 Node.js 項目初始化的工具
※從Nest到Nesk-模塊化Node框架的實踐
※一篇文章教會你 Event loop——瀏覽器和 Node
※瀏覽器與Node的事件循環(Event Loop)有何區別?
※Node.js用戶想學Rust
※Nodejs建站教程:註冊登錄流程的簡單實現
※node+express+mongoDB寫簡單介面,Vue獲取介面
※DOM探索之-DOM的nodeType、nodeName、nodeValue