基于Node.js+express+MySQL+Bootstrap实现的简单登录注册

来源:互联网 发布:matlab plot函数矩阵 编辑:程序博客网 时间:2024/05/21 06:47

初学node.js及express框架,想要利用express搭建一个服务端实现简单的注册功能,接下来开始简单叙述思想并附上实现代码(代码中已有详细注释,按如下模块顺序学习实现)。

  • 基于Bootstrap实现登录注册切换页面及其交互,包括对输入信息的验证等
  • 利用express搭建一个简单的web服务端,将页面注入服务端,实现通过服务器访问到该页面
  • 利用MySQL建表实现数据持久化,进一步实现登录注册,能实现数据库数据的增删改查

遇到的问题及解决办法:

  • 利用node.js中express.static()设置静态资源,资源放置的路径问题。
    解决办法: express.static是Express 提供的内置中间件,用来设置静态文件如:图片, CSS, JavaScript 等。可以在express安装包目录的同级目录中新建文件夹,用于放置本地的静态资源,这样就可以实现直接通过URL访问本地静态资源。(注:该文件夹中的目录结构也能体现在URL中)


  • 数据库如何设计?
    解决办法: 利用MySQL,用户ID可以设置为自增序列,因此在插入时不用插入ID,更加方便!
    数据库user表设计如下:
    这里写图片描述


  • 如何将与数据库操作相关的数据及方法与服务器搭建相关代码分离
    解决办法: 可以利用node.js模块系统进行解决,初学者可以参考Node.js模块系统,将数据库操作相关的方法均封装在connectMysql.js中,然后在服务器端相关代码封装在service_index.js中,在service_index.js中引入connectMysql.js。
    具体实现方法如下:

    首先在被引用的connectMysql.js中设置一个被访问入口:
exports.connectMysql = function() {    var testValue;    function testFunc() {       /* 此处省略具体方法及数据 */    }    return {'testFunc':testFunc,'testValue':testValue}}

       然后在调用外部js(connectMysql.js)的service_index.js文件中引入connectMysql.js(注:注意路径问题,此处将两个文件放在同一文件夹下

引入方法

var connectMysql = require('./connectMysql');

调用方法

var connection = connectMysql.connectMysql();//获取入口/* 如下方式调用方法及变量 */connection.queryData("SELECT * FROM user");



  • node.js连接数据库、操作数据库均使用了回调函数,回调函数的确能解决I/O阻塞问题,但若想将回调函数的值作为函数的返回值却遇到了难题,直接利用return返回。

    解决办法: 初学者可以参考
    node.js如何获取异步函数回调的返回值。
    采用Async、Q、Promise等第三方库处理异步回调
    我在此处利用了第三方库——Async进行解决
    简单介绍一下,Async是第三方专门处理异步的库,能很好的控制异步流程,一个简单的例子读取两个文件的内容,并对合并结果进行处理的例子如下:

var async = require('async')  , fs = require('fs');async.parallel([  function(callback){    fs.readFile('/etc/passwd', function (err, data) {      if (err) callback(err);      callback(null, data);    });  },  function(callback){    fs.readFile('/etc/passwd2', function (err, data2) {      if (err) callback(err);      callback(null, data2);    });  }],function(err, results){  // 在这里处理data和data2的数据,每个文件的内容从results中获取  // results是一个包含结果的数组[data,data1]});

另外,除了需要控制异步流程,为了获取回调函数异步处理后的值,还需要继续借助回调函数获取原本需要return的值,如下为一个例子:

function getTBS(callback){    ng.get("http://tieba.baidu.com/dc/common/tbs",function(data,status,headers){        callback(null,data)    },headers,'utf8')}getTBS(function(err,result){    if(err) throw err;    console.log(result) //{"tbs":"a2bdd05a3fd08e561463670847","is_login":1}});

用以上方法,利用回调函数获取数据是一种不错的解决办法。
在本实例中,以插入注册用户为例,具体解决办法如下:
首先,在connectMysql.js中,由于在添加用户时应该先查询是否已存在该用户,需要先进行查询操作,判断后再进行插入操作,因此需要引入async库控制流程,下为数据库操作方法:

function addUser(response, callback) {        //顺序执行回调函数        async.parallel([                //查询是否已有该记录                function(callback) {                    var sql = 'SELECT passwd FROM user WHERE username="' + response.username + '"';                    connection.query(sql, function(err, result) {                        if (err) callback(err);                        var res = false;                        if (result.length == 0) {                            res = true;                        }                        callback(null, res)                    });                }            ],            function(err, results) {                //根据查询记录进行分别处理                var flag = false;                console.log(results);                if (results[0]) {                    var addSql = 'INSERT INTO user(userId,username,phonenum,passwd) VALUES(0,?,?,?)';                    var addSqlParams = [String(response.username), String(response.phonenum), String(response.passswd)];                    //增                    connection.query(addSql, addSqlParams, function(err, result) {                        if (err) {                            console.log('[INSERT ERROR] - ', err.message);                        }                        console.log('--------------------------INSERT----------------------------');                        //console.log('INSERT ID:',result.insertId);                                console.log('INSERT ID:', result);                        console.log('-----------------------------------------------------------------\n\n');                    });                    flag = true;                } else {                    flag = false;                }                callback(null, flag);            });    }

另外,在service_index.js中需要利用回调函数异步调用上述addUser方法返回的结果值以进行进一步判断操作(用户已存在则提示用户已存在,成功插入则进入欢迎界面)

app.post('/register_post', urlencodedParser, function(req, res) {    var response = {        "phonenum": req.body.phonenum,        "username": req.body.usernameR,        "passswd": req.body.passswd1,    };    connection.addUser(response, function(err, result) {        if (err) throw err;        console.log(result);        if (result) {            //插入成功            res.send("嘿," + response.username + ",欢迎加入!");        } else {            res.send("用户已存在"); //成功则返回带有用户名的页面        }    });})



  • 连接数据库时出现Cannot enqueue Handshake after invoking quit.

    解决办法: 该问题出现的原因是在于node连接上mysql后如果因网络原因丢失连接或者用户手工关闭连接后,原有的连接挂掉,需要重新连接,但连着多次connect 或 end 都会报错,因此解决办法是在一会话中只进行一次连接和一次断开。



结果截图

登录界面
登录界面

注册界面
注册界面

登录输入
登录输入

登录成功
登录成功

登录失败
登录失败

注册界面提示信息
注册提示信息

注册失败
注册失败

注册成功
注册成功


附录(代码):

  1. register.html
<!DOCTYPE html><html><head>    <meta charset="UTF-8">    <title>注册/登录</title>    <!-- 包含头部信息用于适应不同设备 -->    <meta name="viewport" content="width=device-width, initial-scale=1">    <style>        .nav-tabs>li {            width: 50%;            text-align: center        }        .nav-tabs>li.active>a,        .nav-tabs>li.active>a:focus,        .nav-tabs>li.active>a:hover {            color: #FFF !important;            cursor: default;            background-color: #2e6da4 !important;            border: 1px solid #ddd !important;            border-bottom-color: transparent;        }        .tab-pane {            margin-top: 20px;        }        .requisiteTip {            color: red;        }        .tip {            /* size: 0.6em; */            /* display: none; */        }    </style>    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.5/css/bootstrap.min.css">    <!-- Normalize.css在 HTML 元素的默认样式中提供了更好的跨浏览器一致性。 -->    <link rel="stylesheet" href="../css/Normalize.css">    <script src="https://cdn.bootcss.com/jquery/3.2.1/jquery.min.js"></script>    <script src="https://cdn.bootcss.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>    <script src="../js/angular.js"></script>    <script src="../js/angular.min.js"></script></head><body>    <div class="container">        <ul id="myTab" class="nav nav-tabs">            <li class="active"><a href="#login" data-toggle="tab">账号登录</a></li>            <li><a href="#reg" data-toggle="tab">账号注册</a></li>        </ul>        <div id="myTabContent" class="tab-content">            <div class="tab-pane fade in active" id="login">                <form role="form" class="form-horizontal" action="http://127.0.0.1:8088/login_post" method="POST">                    <div class="form-group">                        <label for="username" class="col-sm-2 control-label pull-left">&nbsp;<span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;名称&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10">                            <input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名">                        </div>                    </div>                    <div class="form-group">                        <label for="passwd" class="col-sm-2 control-label">&nbsp;<span class="glyphicon glyphicon-lock"></span>&nbsp;&nbsp;密码&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10">                            <input type="password" class="form-control" id="passwd" name="passwd" placeholder="请输入密码">                        </div>                    </div>                    <div class="form-group">                        <div class="">                            <div class="checkbox pull-left" style="display:inline-block;margin-left:5%">                                &nbsp;&nbsp;<label><input type="checkbox" id="remember">请记住我 </label>                            </div>                            <div class="checkbox pull-right" style="display:inline-block;margin-right:8%">                                <a href="#">忘记密码</a>                            </div>                        </div>                    </div>                    <div class="form-group">                        <input type="submit" id="loginBtn" class="btn btn-primary btn-lg" value="登录" style="width:92%;margin-left:4%">                    </div>                </form>            </div>            <div class="tab-pane fade" id="reg">                <form role="form" class="form-horizontal" action="http://127.0.0.1:8088/register_post" method="POST">                    <div class="form-group">                        <label for="phonenum" class="col-sm-2 control-label pull-left">&nbsp;<span class="glyphicon glyphicon-phone"></span>&nbsp;&nbsp;手机&nbsp;<span class="requisiteTip">*</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10">                            <input type="text" class="form-control" id="phonenum" name="phonenum" placeholder="请输入您的手机号">                        </div>                    </div>                    <div class="tip" id="phonenumTip"></div>                    <div class=" form-group">                        <label for="usernameR" class="col-sm-2 control-label pull-left">&nbsp;<span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;用户名&nbsp;<span class="requisiteTip ">*</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10">                            <input type="text" class="form-control" id="usernameR" name="usernameR" placeholder="请输入用户名 ">                        </div>                    </div>                    <div class="tip" id="usernameTip"></div>                    <div class="form-group ">                        <label for="passswd1 " class="col-sm-2 control-label ">&nbsp;<span class="glyphicon glyphicon-lock"></span>&nbsp;&nbsp;密码&nbsp;<span class="requisiteTip ">*</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10 ">                            <input type="password" class="form-control " id="passswd1" name="passswd1" placeholder="请输入密码">                        </div>                    </div>                    <div class="tip" id="passswd1Tip"></div>                    <div class="form-group ">                        <label for="passswd2" class="col-sm-2 control-label ">&nbsp;<span class="glyphicon glyphicon-lock "></span>&nbsp;&nbsp;确认密码&nbsp;<span class="requisiteTip ">*</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</label>                        <div class="col-sm-10 ">                            <input type="password" class="form-control " id="passswd2" name="passswd2" placeholder="请再次输入密码 ">                        </div>                    </div>                    <div class="tip" id="passswd2Tip"></div>                    <br>                    <div class="form-group ">                        <input type="submit" id="registerBtn" class="btn btn-primary btn-lg " style="width:92%;margin-left:4% " value="注册">                    </div>                </form>            </div>        </div>        <div style="height:200px "></div>        <nav class="navbar navbar-default navbar-fixed-bottom " style="background-color:inherit ">            <div style="text-align:center ">                版权所有 <span class="glyphicon glyphicon-copyright-mark "></span> hxy            </div>        </nav>    </div></body><script>    $('.navbar').css('position', 'absolute');    $('li[name="reg_tag "]').on('click', function() {        if (!$(this).hasClass('active')) {            $(this).addClass('active');            $('li[name="login_tag "]').removeClass('active');        }    })    $('li[name="login_tag "]').on('click', function() {        if (!$(this).hasClass('active')) {            $(this).addClass('active');            $('li[name="reg_tag "]').removeClass('active');        }    })</script><script src="../nodeJs/connectMysql.js"></script><script src="../js/pageJs/register.js"></script></html>

2.register.js

var flag1 = false;var flag2 = false;var flag3 = false;var flag4 = false;$("#passswd1").on('click', function() {    console.log($(this).val());    var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;6-16位常用数字,字母及常用符号,区分大小写</h6> <br > ';    if ($(this).val() == "") {        $("#passswd1Tip").html("");        $("#passswd1Tip").append(text);        $("#passswd1Tip").css('display', 'block');    }});$("#passswd1").on('blur', function() {    var keywd = $(this).val();    if (keywd != '') {        console.log(keywd);        var patt = /^[0-9a-zA-Z~!@#$%^&*()_+=-\[\]\;',./|:"<>?"\{\}]{6,16}$/;        console.log(patt.test(keywd));        if (!patt.test(keywd)) {            $("#passswd1Tip").html("");            var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;输入密码格式错误,6-16位常用数字,字母及常用符号,区分大小写</h6> <br > ';            $("#passswd1Tip").append(text);            $("#passswd1Tip").css('display', 'block');            flag3 = false;            enableBtn("registerBtn");        } else {            $("#passswd1Tip").html("");            $("#passswd1Tip").css('display', 'none');            flag3 = true;            enableBtn("registerBtn");        }    }});$("#passswd2").on('blur', function() {    var keywd = $(this).val();    var keywd1 = $("#passswd1").val();    console.log(keywd);    console.log(keywd1);    if (keywd != '') {        if (keywd1 != keywd) {            $("#passswd2Tip").html("");            var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;两次输入的密码不相同,请重新输入</h6> <br > ';            $("#passswd2Tip").append(text);            $("#passswd2Tip").css('display', 'block');            flag4 = false;            enableBtn("registerBtn");        } else {            $("#passswd2Tip").html("");            $("#passswd2Tip").css('display', 'none');            flag4 = true;            enableBtn("registerBtn");        }    } else {        $("#passswd2Tip").html("");        var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;请再次输入密码</h6> <br > ';        $("#passswd2Tip").append(text);        $("#passswd2Tip").css('display', 'block');        flag4 = false;        enableBtn("registerBtn");    }});$("#phonenum").on("click", function() {    var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;请输入11位手机号码</h6> <br> ';    if ($(this).val() == "") {        $("#phonenumTip").html("");        $("#phonenumTip").append(text);        $("#phonenumTip").css('display', 'block');    }});$("#phonenum").on("blur", function() {    var phonenum = $(this).val();    if (phonenum != '') {        console.log(phonenum);        var patt = /^1[3,5,7,8,9]{1}\d{9}$/;        console.log(patt.test(phonenum));        if (!patt.test(phonenum)) {            $("#phonenumTip").html("");            var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;输入密码格式错误,6-16位常用数字,字母及常用符号,区分大小写</h6> <br > ';            $("#phonenumTip").append(text);            $("#phonenumTip").css('display', 'block');            flag1 = false;            enableBtn("registerBtn");        } else {            $("#phonenumTip").html("");            $("#phonenumTip").css('display', 'none');            flag1 = true;            enableBtn("registerBtn");        }    }});$("#usernameR").on("click", function() {    console.log("www");    var text = '<h6 class="text-info"> &nbsp;&nbsp;<span class="glyphicon glyphicon-exclamation-sign"></span> &nbsp;&nbsp;请输入您的用户名</h6> <br> ';    if ($(this).val() == "") {        $("#usernameTip").html("");        $("#usernameTip").append(text);        $("#usernameTip").css('display', 'block');    }});$("#usernameR").on("blur", function() {    var username = $(this).val();    if (username == '') {        flag2 = false;        enableBtn("registerBtn");    } else {        $("#usernameTip").html("");        $("#usernameTip").css('display', 'none');        flag2 = true;        enableBtn("registerBtn");    }});function enableBtn(btnId) {    console.log(flag1);    console.log(flag2);    console.log(flag3);    console.log(flag4);    if (flag1 && flag2 && flag3 && flag4) {        $("#" + btnId).attr("disabled", false)        console.log("1");    } else {        $("#" + btnId).attr("disabled", "disabled")        console.log("2");    }    console.log($("#" + btnId).attr("disabled"));}$("#remember").on('click', function() {    if ($(this)[0].checked) {        setCookie('username', $("username").val());        setCookie('passwd', $("passwd").val());    } else {        deleteCookie('username');        deleteCookie('passwd');    }});function setCookie(name, value) {    var argv = setCookie.arguments;    var argc = setCookie.arguments.length;    var expires = (argc > 2) ? argv[2] : null;    if (expires != null) {        var LargeExpDate = new Date();        LargeExpDate.setTime(LargeExpDate.getTime() + (expires * 1000 * 3600 * 24));    }    document.cookie = name + "=" + escape(value) + ((expires == null) ? "" : ("; expires=" + LargeExpDate.toGMTString()));}function getCookie(Name) {    var search = Name + "="    if (document.cookie.length > 0) {        offset = document.cookie.indexOf(search)        if (offset != -1) {            offset += search.length            end = document.cookie.indexOf(";", offset)            if (end == -1) end = document.cookie.length            return unescape(document.cookie.substring(offset, end))        } else return ""    }}function deleteCookie(name) {    var expdate = new Date();    expdate.setTime(expdate.getTime() - (86400 * 1000 * 1));    setCookie(name, "", expdate);}$("#loginBtn").on('click', function() {    var sessionStorage = new window.sessionStorage();    sessionStorage.setItem("username", $("#username").val());    sessionStorage.setItem("passwd", $("#passwd").val());    console.log("session:%s-%s", sessionStorage.username, sessionStorage.passwd);});

3.service_index.js

var express = require("express");var bodyParser = require('body-parser');var connectMysql = require('./connectMysql');var session = require('express-session');var cookieParser = require('cookie-parser');var app = express();app.use(cookieParser());app.use(session({    secret: '12345',    cookie: { maxAge: 60000 },    resave: false,    saveUninitialized: true}));// 创建 application/x-www-form-urlencoded 编码解析var urlencodedParser = bodyParser.urlencoded({ extended: false })var connection = connectMysql.connectMysql();app.use(express.static('note-taking'));app.get('/', function(request, response) {    var connection = connectMysql.connectMysql();    connection.queryData("SELECT * FROM user");})app.post('/login_post', urlencodedParser, function(req, res) {    var response = {        "username": req.body.username,        "passwd": req.body.passwd    };    connection.checkUser(response, function(err, result) {        if (err) throw err;        if (result) {            //用户名及密码正确            req.session.username = response.username;            req.session.passwd = response.passwd;            console.log("session:%s-%s", req.session.username, req.session.passwd);            res.send(req.session.username); //成功则返回带有用户名的页面        } else {            res.send("用户名或密码错误"); //成功则返回带有用户名的页面        }    });})app.post('/register_post', urlencodedParser, function(req, res) {    var response = {        "phonenum": req.body.phonenum,        "username": req.body.usernameR,        "passswd": req.body.passswd1,    };    connection.addUser(response, function(err, result) {        if (err) throw err;        console.log(result);        if (result) {            //插入成功            res.send("嘿," + response.username + ",欢迎加入!");        } else {            res.send("用户已存在"); //成功则返回带有用户名的页面        }    });})var server = app.listen(8088, 'localhost', function(req, res) {    console.log(__dirname);    console.log("The Server is running at http://%s:%s", server.address().address, server.address().port);});

4.connectMysql.js

var async = require('async');exports.connectMysql = function() {    /* 此处省略具体方法及数据 */    //连接数据库    var mysql = require('mysql');    var connection = mysql.createConnection({        host: 'localhost',        user: 'root',        password: '123456',        database: 'nodetest'    });    connection.connect();    function test() {        console.log("nihao");    }    function checkUser(response, callback) {        var sql = 'SELECT passwd FROM user WHERE username="' + response.username + '"';        connection.query(sql, function(err, result) {            var res = false;            if (result.length > 0) {                if (result[0]['passwd'] == response.passwd) {                    res = true;                }            }            callback(null, res)        });    }    function addUser(response, callback) {        //顺序执行回调函数        async.parallel([                //查询是否已有该记录                function(callback) {                    var sql = 'SELECT passwd FROM user WHERE username="' + response.username + '"';                    connection.query(sql, function(err, result) {                        if (err) callback(err);                        var res = false;                        if (result.length == 0) {                            res = true;                        }                        callback(null, res)                    });                }            ],            function(err, results) {                //根据查询记录进行分别处理                var flag = false;                console.log(results);                if (results[0]) {                    var addSql = 'INSERT INTO user(userId,username,phonenum,passwd) VALUES(0,?,?,?)';                    var addSqlParams = [String(response.username), String(response.phonenum), String(response.passswd)];                    //增                    connection.query(addSql, addSqlParams, function(err, result) {                        if (err) {                            console.log('[INSERT ERROR] - ', err.message);                        }                        console.log('--------------------------INSERT----------------------------');                        //console.log('INSERT ID:',result.insertId);                                console.log('INSERT ID:', result);                        console.log('-----------------------------------------------------------------\n\n');                    });                    flag = true;                } else {                    flag = false;                }                callback(null, flag);            });    }    return { 'checkUser': checkUser, 'test': test, 'connection': connection, 'addUser': addUser };}
阅读全文
0 0