nodejs实现聊天室

来源:互联网 发布:淘宝店图片轮播尺寸 编辑:程序博客网 时间:2024/05/18 11:47

http://download.csdn.net/download/u013401219/8960433

项目结构图

这里写图片描述
需要安装的模块:express,body-parser,cookie-parser ,ejs,express-session,mysql,socket.io
app.js

var express = require('express'); //引用expressvar crypto = require('crypto'); //加密var path = require('path');var bodyParser = require("body-parser");var app = express();var server = require('http').Server(app);var mysql = require("mysql"); //数据库模块var io = require('socket.io').listen(server); //socket io模块var session = require('express-session'); //如果要使用session,需要单独包含这个模块//连接数据库var connPool = mysql.createPool({    host: '127.0.0.1', //主机    user: 'root', //MySQL认证用户名    password: '123456', //MySQL认证用户密码    port: '3306', //端口号    database: 'sv_chat', //数据库    waitForConnections: true, //当连接池没有连接或超出最大限制时,设置为true且会把连接放入队列    //connectionLimit:10,//连接数限制});/*conn.connect(function(err) {    if (err) {        console.log('[mysql connect] failed:' + err);        return;    }    console.log('[mysql connect] succeed!');});*///express基本配置app.set('port', 3000);app.set('views', __dirname + '/views');app.set("view engine", "ejs");app.use(bodyParser.urlencoded({    extended: false}));app.use(session({    secret: 'ScumVirus',    name: 'sv_chat', //这里的name值得是cookie的name,默认cookie的name是:connect.sid    cookie: {        maxAge: 3600000    }, //设置maxAge是3600000ms,即1h后session和相应的cookie失效过期    resave: false,    saveUninitialized: true,}));app.use(express.static(path.join(__dirname, 'static')));//配置路由//登录页app.get('/', function(req, res) {    //res.send('hello world');    //console.log(getTime() + "  " + req.ip + "  visited.");    //var ip = req.ip.substring(req.ip.lastIndexOf(":") + 1);    res.redirect('/login');});app.get('/login', function(req, res) {    res.sendFile(app.get("views") + '/login.html');});//登录方法 postapp.post('/login', function(req, res) {    var name = req.body.name;    var pwd = getMD5(req.body.pwd);    var ip = req.ip.substring(req.ip.lastIndexOf(":") + 1);    var time = getTime();    var resData = {};    getUserById(name, function(obj) {        if (pwd == obj.pwd) {            var params = [time, ip, obj.id];            updateLoginInfo(params);            resData.msg = 0;        } else {            resData.msg = -1;        }        //设置session        req.session.user = name;        res.send(resData);    });});//注册页app.get('/register', function(req, res) {    res.sendFile(app.get("views") + '/register.html');});//注册方法 postapp.post('/register', function(req, res) {    var name = req.body.name;    var pwd = getMD5(req.body.pwd);    var email = req.body.email;    var phone = req.body.phone;    var time = getTime();    var params = [name, pwd, email, phone, time];    var resData = {};    addUser(params, function(flag) {        if (flag) {            resData.msg = 0;        } else {            resData.msg = -1;        }        res.send(resData);    });});//聊天室首页app.get('/index', function(req, res) {    if (req.session.user == undefined) {        res.redirect('/login');    } else {        res.render("index", {            "user": req.session.user        });        //res.sendFile(app.get("view") + '/index.html');    }});//监听服务器启动server.listen(app.get('port'), function() {    console.log("Express server listening on port " + app.get('port'));});//全局变量var onlineMember = [];//WebSocket连接监听io.on('connection', function(socket) {    //socket.emit('open',onlineMember); //通知客户端已连接    // 打印握手信息    // console.log(socket.handshake);    // 构造客户端对象    var client = {        name: '',    }    // 对message事件的监听    //登录事件    socket.on('login', function(name) {        var time = getTime();        client.name = name;        var index = getArrIndex(name,onlineMember);        if(index == -1){            onlineMember.push(client.name);            console.log(time + " " + client.name + " login");        }        var obj = {            time: time,            author: client.name,            text: '',            type: 'login',            member: onlineMember        };        socket.emit('system', obj);        socket.broadcast.emit('system', obj);    });    //消息事件    socket.on('message', function(msg) {        var obj = {            time: getTime(),        };        obj['msg'] = msg;        obj['author'] = client.name;        obj['type'] = 'message';        // 返回消息(可以省略)        socket.emit('message', obj);        // 广播向其他用户发消息        socket.broadcast.emit('message', obj);    });    //监听退出事件    socket.on('disconnect', function() {        var index = getArrIndex(client.name, onlineMember);        if (index > -1) {            onlineMember.splice(index, 1);        }        var time = getTime();        var obj = {            time: time,            author: client.name,            text: '',            type: 'loginout',            member: onlineMember        };        console.log(time + " " + client.name + " loginout");        // 广播用户已退出        socket.broadcast.emit('system', obj);    });});//获取当前的时间yyyy-MM-dd HH:ii:ssvar getTime = function() {    var date = new Date();    return date.getFullYear() + "-" + tc(date.getMonth() + 1) + "-" + tc(date.getDate()) + " " + tc(date.getHours()) + ":" + tc(date.getMinutes()) + ":" + tc(date.getSeconds());}//不足10的首位补0var tc = function(num) {    if (num >= 10) {        return num;    } else {        return "0" + num;    }}//根据用户获取用户信息var getUserById = function(name, callback) {    //执行SQL语句    var sql = 'select * from sv_user where name=?';    var params = [name];    connPool.query(sql, params, function(err, result) {        if (err) {            console.log('[SELECT ERROR] - ', err.message);            return;        }        return callback(result[0]);    });}//添加新用户var addUser = function(params, callback) {    //执行SQL语句    var sql = 'insert into sv_user(`name`,`pwd`,`email`,`phone`,`create_time`) values(?,?,?,?,?)';    connPool.query(sql, params, function(err, result) {        if (err) {            console.log('[INSERT ERROR] - ', err.message);            return callback(false);        } else {            console.log('INSERT ID:', result.insertId);            return callback(true);        }    });}//更新登录时间和ipvar updateLoginInfo = function(params) {    var sql = 'update sv_user set login_time=?,login_ip=? where id=?';    connPool.query(sql, params, function(err, result) {        if (err) {            console.log('[UPDATE ERROR] - ', err.message);        } else {            console.log('affectedRows:', result.affectedRows);        }    });}//获取md5加密后的值var getMD5 = function(str) {    var md5 = crypto.createHash('md5');    md5.update(str);    var d = md5.digest('hex');    return d;}//获取数组中指定值的下标var getArrIndex = function(str, arr) {    var index = -1;    for (var i = 0; i < arr.length; i++) {        if (arr[i] == str) {            index = i;            break;        }    }    return index;}

chat.js

$(function() {    //建立websocket连接    socket = io.connect('http://localhost:3000');    var userName = $("#user").val();    socket.emit('login', userName);    //收到server的系统消息    socket.on('system', function(obj) {        if (obj.type === "login") {            //登录消息            var msg = '<p><span class="time">' + obj.time + '</span><span class="person">' + obj.author + '</span><span class="msg">进入了聊天室。</span></p>';            $(".chat-panel").append(msg);            //刷新在线列表            $("#memer-list").empty();            var member = obj.member;            var cnt = member.length;            $("#memeber-count").text(cnt);            for (var i = 0; i < cnt; i++) {                var html = '<li><span class="label label-info user">' + member[i] + '</span></li>';                $("#memer-list").append(html);            }        } else if (obj.type === "loginout") {            //登出消息            var msg = '<p><span class="time">' + obj.time + '</span><span class="person">' + obj.author + '</span><span class="msg">离开了聊天室。</span></p>';            $(".chat-panel").append(msg);            //刷新在线列表            $("#memer-list").empty();            var member = obj.member;            var cnt = member.length;            $("#memeber-count").text(cnt);            for (var i = 0; i < cnt; i++) {                var html = '<li><span class="label label-info user">' + member[i] + '</span></li>';                $("#memer-list").append(html);            }        }    });    socket.on('message', function(obj) {        if (obj.type === "message") {            //发送消息            var msg = '<p><span class="time">' + obj.time + '</span><span class="person">' + obj.author + '</span>:<span class="msg">' + obj.msg + '</span></p>';            $(".chat-panel").append(msg);        }    });    $("#send").on("click", function() {        var msg = $("#text").val();        if (msg !== "") {            socket.emit('message', msg);            $("#text").val("");        }    });});

index.ejs

<!doctype html><html lang="en"><head>    <meta charset="utf-8">    <title>SV在线聊天系统</title>    <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">    <meta name="viewport" content="width=device-width, initial-scale=1">    <link rel="stylesheet" type="text/css" href="css/bootstrap.css">    <link rel="stylesheet" type="text/css" href="css/font-awesome.css">    <style type="text/css">        * {            font-size: 13px;            font-family: cursive;        }        #header {            position: fixed;            width: 100%;            height: 40px;            background:#0f0f0f;            border-bottom: 1px solid #ddd;        }        #header > h4 {            margin: 0;            padding: 0;            font-weight: bold;            padding-left: 15px;            line-height: 40px;            color:#fff;        }        .online-member-panel {            margin: 55px 0 10px 0;            width: 100%;            padding: 15px;            border:1px solid #ddd;            border-radius: 10px;            overflow-y:auto;            box-shadow:0 0 10px #ccc;         }        .online-member-panel > .header {            width:100%;            padding-left: 15px;            padding-right: 15px;        }        ul {            margin: 10px 0 0 0;            padding: 0;            list-style: none;        }        #memer-list > li {            float: left;            margin-left: 10px;            margin-right: 10px;        }        .chat-panel {            margin: 10px auto;            width: 100%;            height: 300px;            padding: 15px;            border:1px solid #ddd;            border-radius: 10px;            overflow-y:auto;        }        textarea {            resize:none;        }        #send {            margin-top: 10px;            float:right;        }        p {            color:#ccc;        }        p > span.time {            color:#ccc;            margin-right: 10px;        }        p > span.person {            color:#428bca;            padding-right: 5px;            padding-left: 5px;        }        p > span.msg {            color:#666;        }    </style></head><body>    <div id="header">        <h4>SV在线聊天系统</h4>    </div>    <div class="row-fluid">        <div class="col-md-2"></div>        <div class="col-md-8">            <div class="online-member-panel">                <div class="header">                    <span>在线会员:<span id="memeber-count" class="label label-warning">0</span></span>                </div>                <ul id="memer-list">                    <!--<li><span class="label label-info">ScumVirus</span></li>-->                </ul>            </div>            <div class="chat-panel">                <!--<p><span class="time">2015-06-06 06:06:06</span><span class="person">ScumVirus</span>:<span class="msg">233333333333</span></p>-->            </div>            <div class="form-group">                <textarea class="form-control input-sm" rows="3" id="text"></textarea>                <button class="btn btn-success" type="button" id="send">发送消息</button>            </div>        </div>        <div class="col-md-2"></div>        <input type="hidden" value="<%=user%>" id="user" />    </div></body><script src="js/jquery-2.1.1.js" type="text/javascript"></script><script src="js/bootstrap.js" type="text/javascript"></script><script src="/socket.io/socket.io.js"></script><script src="js/chat.js" type="text/javascript"></script></html>

login.html

<!doctype html><html lang="en"><head>    <meta charset="utf-8">    <title>SV在线聊天系统</title>    <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">    <meta name="viewport" content="width=device-width, initial-scale=1">    <link rel="stylesheet" type="text/css" href="css/bootstrap.css">    <link rel="stylesheet" type="text/css" href="css/font-awesome.css">    <style type="text/css">        * {            font-size: 13px;            font-family: cursive;        }        #login-frame {            margin:150px auto;            float:none;            text-align:center;        }        .form-group {            text-align: center;        }        .form-control {            width:200px;            display: initial;        }        #login-frame > h3 {            color:#428bca;        }        .form-group > button {            width: 80px;        }        .form-group > button:nth-child(2) {            margin-left: 15px;        }    </style></head><body>    <div class="container-fluid">        <div class="row-fluid">            <div class="col-md-4" id="login-frame">                <h3>SV在线聊天系统</h3>                <div class="form-group">                    <input type="text" class="form-control input-sm" placeholder="请输入用户名" id="name" />                </div>                <div class="form-group">                    <input type="password" class="form-control input-sm" placeholder="请输入密码" id="pwd" />                </div>                <div class="form-group">                    <button type="button" class="btn btn-success" id="login">登录</button>                    <button type="button" class="btn btn-danger" id="register">注册</button>                </div>            </div>        </div>    </div></body><script src="js/jquery-2.1.1.js" type="text/javascript"></script><script src="js/bootstrap.js" type="text/javascript"></script><script type="text/javascript">    $("#register").on("click",function(){        window.location.href = "/register";    });    $("#login").on("click",function(){        var name = $("#name").val();        var pwd = $("#pwd").val();        if(name == "" || pwd == ""){            alert("用户名和密码不能为空!");            return;        }        $.post("/login",{            name:name,            pwd:pwd,        },function(data){            if(data.msg == '0'){                window.location.href = "/index";            }else{                alert("账号或密码错误!");            }        },'json');    });</script></html>

register.html

<!doctype html><html lang="en"><head>    <meta charset="utf-8">    <title>SV在线聊天系统</title>    <meta content="IE=edge,chrome=1" http-equiv="X-UA-Compatible">    <meta name="viewport" content="width=device-width, initial-scale=1">    <link rel="stylesheet" type="text/css" href="css/bootstrap.css">    <link rel="stylesheet" type="text/css" href="css/font-awesome.css">    <style type="text/css">        * {            font-size: 13px;            font-family: cursive;        }        #login-frame {            margin:100px auto;            text-align:left;        }        .form-group > * {            display: inline-block;        }        .form-control {            width:200px;            display: initial;        }        .alert {            margin: 0 0 0 10px;            padding: 5px;        }    </style></head><body>    <div class="container-fluid">        <div class="row-fluid">            <div class="col-md-12" id="login-frame">                <div class="form-group">                    <label style="margin-right:2px;">用 户 名:</label>                    <input type="text" class="form-control input-sm" placeholder="请输入用户名" id="name" />                    <div class="alert alert-danger">用户名必须为4-16位的英文字母或数字。</div>                </div>                <div class="form-group">                    <label>密  码:</label>                    <input type="password" class="form-control input-sm" placeholder="请输入密码" id="pwd" />                    <div class="alert alert-danger">密码必须为6-16位。</div>                </div>                <div class="form-group">                    <label>确认密码:</label>                    <input type="password" class="form-control input-sm" placeholder="请再次输入密码" id="repwd" />                    <div class="alert alert-danger">两次输入的密码要一致。</div>                </div>                <div class="form-group">                    <label>邮  箱:</label>                    <input type="text" class="form-control input-sm" placeholder="请输入邮箱账号" id="email" />                    <div class="alert alert-danger">Email格式不正确。</div>                </div>                <div class="form-group">                    <label>手  机:</label>                    <input type="text" class="form-control input-sm" placeholder="请输入手机号码" id="phone" />                    <div class="alert alert-danger">手机号码格式不正确。</div>                </div>                <div class="form-group">                    <button type="button" class="btn btn-success form-control" id="register">注  册</button>                </div>            </div>        </div>    </div></body>    <script src="js/jquery-2.1.1.js" type="text/javascript"></script>    <script src="js/bootstrap.js" type="text/javascript"></script>    <script type="text/javascript">    $(".alert").hide();    $("#register").on("click",function(){        $(".alert").hide();        var name = $("#name").val();        var pwd = $("#pwd").val();        var repwd = $("#repwd").val();        var email = $("#email").val();        var phone = $("#phone").val();        if(name.length<4 || name.length>16 || !isName(name)){            $("#name").next().show();            return;        }//      if(pwd.length<6 || pwd.length>16){//          $("#pwd").next().show();//          return;//      }        if(repwd != pwd){            $("#repwd").next().show();            return;        }        if(!isEmail(email)){            $("#email").next().show();            return;        }        if(!isPhone(phone)){            $("#phone").next().show();            return;        }        $.post("/register",{            name:name,            pwd:pwd,            email:email,            phone:phone,        },function(data){            if(data.msg == '0'){                alert("注册成功!");                window.location.href = "/";            }else{                alert("注册失败,该用户名可能已被注册!");            }        },'json');    });    //验证用户名    function isName(value){        var reg = /^(?=.*[a-z])[a-z0-9]+/ig        return reg.test(value);    }    //验证邮箱    function isEmail(value) {       return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(value);    }    //验证手机号    function isPhone(value){       return /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/.test(value);    }</script></html>
原创粉丝点击