nodejs实现聊天室

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

项目结构图

nodejs实现聊天室_第1张图片
需要安装的模块:express,body-parser,cookie-parser ,ejs,express-session,mysql,socket.io
app.js

var express = require('express'); //引用express
var 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');
});
//登录方法 post
app.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');
});
//注册方法 post
app.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:ss
var 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的首位补0
var 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);
        }
    });
}

//更新登录时间和ip
var 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 = '

' + obj.time + '' + obj.author + '进入了聊天室。

'
; $(".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 = '
  • ' + member[i] + '
  • '
    ; $("#memer-list").append(html); } } else if (obj.type === "loginout") { //登出消息 var msg = '

    ' + obj.time + '' + obj.author + '离开了聊天室。

    '
    ; $(".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 = '
  • ' + member[i] + '
  • '
    ; $("#memer-list").append(html); } } }); socket.on('message', function(obj) { if (obj.type === "message") { //发送消息 var msg = '

    ' + obj.time + '' + obj.author + '' + obj.msg + '

    '
    ; $(".chat-panel").append(msg); } }); $("#send").on("click", function() { var msg = $("#text").val(); if (msg !== "") { socket.emit('message', msg); $("#text").val(""); } }); });

    index.ejs

    
    <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">0span>span>
                    div>
                    <ul id="memer-list">
                        
                    ul>
                div>
                <div class="chat-panel">
                    
                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

    
    <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

    
    <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>

    你可能感兴趣的:(nodejs)