• Node.js(express) + MongoDB(mongoose) 简单开发(二)


    前面说过,做一个真正意义上的登录注册,接下来就让我们一步一步实现吧~

    首先需要安装mongodb,网上有很多安装教程,这里就不再赘述。

    安装完成后开始与本地数据库连接,可以参考这里:MongoDB介绍及下载与安装

    最后可以安装一个可视化的操作数据库的软件:MongoVUE,配置也很简单:

    image_thumb34_thumb_thumb

    最后在项目级目录下安装mongoose,安装过程自行百度~ 安装成功后可在node_modules下看见mongoose文件夹

    接下来我们测试数据库是否连同:

    新建一个models的文件夹,在这里我们对表进行操作(新建表,引用表)

    在models下新建index.js:

    var mongoose = require("mongoose");
    
    mongoose.connect("mongodb://localhost:27017/blogData");
    
    mongoose.connection.on("error", function (error){
        console.log("连接数据库失败"+error);
    });
    
    mongoose.connection.on("open", function (){
        console.log("数据库连接成功!!!");
    });
    
    var tschema = new mongoose.Schema({
        name  : { type:String },
        date : {type: Date, default: Date.now}
    });
    
    var tmodel = mongoose.model("tdoc", tschema);
    
    var testEntity = new tmodel({    name: "testUser"});testEntity.save(function (error, doc){    if(error){        console.log("error: "+error);    }else{        console.log(doc);    }});
    
    tmodel.find({}, function (error, docs){
        if(error){
            console.log("error: "+error);
        }else{
            console.log(docs);
        }
    });
    
    exports.mongoose = mongoose;

    这里注意 添加过后把添加数据的地方给注释起来,否则每执行一次都会添加一条数据。

    在IDE里debug就可以看到输出的结果:

    image_thumb4_thumb

    同样我们在可视化的数据管理软件上也可以看见:

    image_thumb7_thumb

    让我们精简一下index.js的功能:

    var mongoose = require("mongoose");
    
    mongoose.connect("mongodb://localhost:27017/blogData");
    
    exports.mongoose = mongoose;

    建立一个login.js:

    var mongodb = require("./index");
    
    /*
    * 用户注册
    * */
    
    var Schema = mongodb.mongoose.Schema;
    
    var registerSchema = new Schema({
        username: {type: String},
        password: {type: String},
        createTime: {type: Date, default: Date.new}
    });
    
    var userModel = mongodb.mongoose.model("blogUser", registerSchema);
    
    exports.userList = userModel;

    这样我们就可以在任何地方引用到userLsit了。

    接下来在项目级目录下创建一个dao的文件夹,这个文件夹的作用就是专门用来处理数据的。

    在dao层,新建一个userDAO.js,在userDAO里面封装一些操作数据的方法:

    var userModel = require("../models/login").userList;
    
    var userDAO = function (){};
    
    userDAO.prototype = {
        //
        save: function (json, callBack){
            var newUser = new userModel(json);
    
            newUser.save(function (err){
                callBack(err);
            });
        },
        //
        remove: function (json, callBack){
            userModel.remove(json, function (err){
                callBack(err);
            });
        },
        //
        update: function (json, condition, callBack){
            userModel.update(json, condition, function (err){
               callBack(err);
            });
        },
        //
        findByName: function (name, callBack){
            userModel.findOne({username: name}, function (err, doc){
                callBack(err, doc);
            });
        }
    };
    
    exports.userMethod = new userDAO();

    这样在需要操作数据的地方,我们只需引用这个文件就可以对数据库进行操作了~

    接下来让我们实现注册的接口功能,接口的数据格式同样沿用之前的数据格式。现在我们已连通数据库,所以用POST的方式

    在C层新建login.js,在这个文件里面写注册和登录的方法:

    var userMethod = require("../dao/userDAO").userMethod;
    
    exports.register = function (req, res){
        userMethod.findByName(req.body.username, function (err, doc){
            if(!err){
                if(!doc){
                    var newUser = {username: req.body.username, password: req.body.password};
                    userMethod.save(newUser, function (err){
                        if(!err){
                            res.send({
                                code: 200,
                                msg: "注册成功!(本条消息来自后台)"
                            });
                        }
                    });
                }else{
                    res.send({
                        code: 201,
                        msg: "次用户名已被占用!(本条消息来自后台)"
                    });
                }
            }
        });
    };

    可以看到思路也很简单明确,用我们之前封装的查询数据库的方法,先对输入的用户名进行查询,

    当查询没有错误的时候再判断,如果没有查询到这个用户名,说明该用户名还未注册,反之该用户名被占用~

    现在就可以来实现前端的注册功能了:

    ;(function ($){
        var foo = function (options){
            var self = this;
                self.options = $.extend({
                    parent: $("#myForm"),
                    register: $("[node-type=register]"),
                    submit: $("[node-type=submit]")
                }, options);
            self.bindEvent();
        };
    
        foo.prototype = {
            bindEvent: function (){
                var self = this;
                self.register();
            },
            register: function (){
                var self = this,
                    parent = self.options.parent,
                    register = self.options.register;
    
                register.on("click", function (){
                    var jqXML = $.ajax({
                        url: "/register",
                        dataType: "json",
                        type: "post",
                        data: parent.serialize()
                    });
    
                    jqXML.done(function (json){
                        if(json.code == 200){
                            alert(json.msg);
                        }else{
                            alert(json.msg);
                        }
                    });
                });
            }
        };
    
        new foo();
    })(jQuery);

    同样别忘了在longin.html页面引用

    最后在路由层新增注册的接口:

    //注册接口
    router.post("/register", loginController.register);

    好了,接下来让我们重启服务,看下一效果~

    image_thumb2_thumb

    image_thumb5_thumb

    恭喜~ 注册成功!

    我们可以通过可视化的数据管理软件看下我们刚刚注册的用户,有没有存储到数据库里面:

    image_thumb8_thumb

    刚刚我们注册的用户被完整的写入到数据库里。

    最后让我们按着写注册的思路,来实现一下登录的功能吧~

    首先在C层login.js里面添加登录功能:

    exports.login = function (req, res){
        userMethod.findByName(req.body.username, function (err, doc){
            if(!err && doc && req.body.password === doc.password){
                res.send({code:200, msg:"成功(本条消息来自后台)"});
            }else{
                res.send({"code":201, msg:"用户名或者密码错误(本条消息来自后台)"});
            }
        });
        //if(req.body.username && req.body.password){
        //    res.send({code:200, msg: "登录成功(本条消息来自后台)"});
        //}else{
        //    res.send({code: 201, msg: "帐号或密码错误(本条消息来自后台)"});
        //}
    };

    登录功能的思路也很简单,先查询用户名,如果查询未出错,并且查询到了输入的用户名,并且输入的密码与我们数据库存储的密码一致,

    说明该用户可以正确的登录。

    前端的login.js新增登录功能:

            bindEvent: function (){
                var self = this;
                self.login();
                self.register();
            },
            login: function (){
                var self = this,
                    parent = self.options.parent,
                    submit = self.options.submit;
    
                submit.on("click", function (){
                    var jqXML = $.ajax({
                        url: "/userData",
                        dataType: "json",
                        type: "post",
                        data: parent.serialize()
                    });
    
                    jqXML.done(function (json){
                        if(json.code == 200){
                            location.href = "/home";
                        }else{
                            alert(json.msg);
                        }
                    });
                });
            }

    路由层index.js配置登录接口:

    //登录接口
    router.post("/userData", loginController.login);

    OK~ 重启服务,让我们来测试下我们刚刚注册的帐号是否能成功登录~

    image_thumb10_thumb

    如果你能看到这个界面,那么恭喜你,你的登录功能也实现了~~

    不过问题也来了:翻一下我们曾写的home.html就明白了,我们写的<%= username %>没有正确被解析,仔细想下也不难理解:

    我们在没有连用数据库的时候,登录是用get方式写的,当时的实现思路是登录后把用户名存在了userList对象里面,当我们访问home页时再从这个对象里面读取用户名,此时的<%= username %>完全可以被正确解析

    但是问题是:现在我们用的post方式,用户名理所当然不会被存储到userList里面,当然就更没有里面的用户名了。那么我们应该把用户信息存储到哪里,当跳转到home页,可以从这个地方直接读取用户信息呢?

    接下来轮到他登场:express-session

    安装模块express-session并引用,安装、引用不在讲述。 express-session详解请戳这里 什么是session

    在app.js里使用新模块进行访问时间限制,如下:

    var session = require('express-session');
    
    //set session
    app.use(session({
      secret: "secret",
      resave: true,
      saveUninitialized: false,
      cookie: {
        maxAge: 1000 * 60 * 10 //过时时间设置(毫秒)
      }
    }));

    一定要注意书写顺序,把app.use(session({}))写在app.use('/', routes)的上面,原因是中间件必须放在HTTP动词方法之前,否则不会执行。

    接下来新增中间件并设置模板变量值。这里又涉及到一个新的名词:中间件。什么是中间件? 可一看下这里 express之路由与中间件

    其实我们理解的中间件,就是一个个的组件,一个个的功能,都集成到middleware里面,这样做的好处就是调理清晰,思路明确

    好了,我们在项目级目录下新建一个middleware文件夹,在里面新建一个session.js,代码如下:

    exports.session = function (req, res, next){
        res.locals.user = req.session.user;
        var err = req.session.error;
        res.locals.message = "";
        if(err){
            res.locals.message = "<div style="margin-bottom: 20px; color: #f00;">"+err+"</div>"
        }
        next();
    };

    在路由层的index.js添加对session模板的使用:

    var session = require("../middleware/session");
    
    router.use(session.session);

    然后对登录功能增加一些代码:

    exports.login = function (req, res){
        userMethod.findByName(req.body.username, function (err, doc){
            if(!err && doc && req.body.password === doc.password){
                var user = {
                    username: req.body.username,
                    password: req.body.password
                };
                req.session.user = user;
                res.send({code:200, msg:"成功(本条消息来自后台)"});
            }else{
                res.send({"code":201, msg:"用户名或者密码错误(本条消息来自后台)"});
            }
        });
        //if(req.body.username && req.body.password){
        //    res.send({code:200, msg: "登录成功(本条消息来自后台)"});
        //}else{
        //    res.send({code: 201, msg: "帐号或密码错误(本条消息来自后台)"});
        //}
    };

    在登录成功后,我们把用户名以及密码都存储到user对象里面,并把user对象赋给session下面的一个自定义对象user

    在访问home页的时候我们就可以从session里面读取用户信息了:

    /* GET home page. */
    router.get('/home', function (req, res){
        if(req.session.user){
            res.render("home", {
                title: "登录成功页",
                username:req.session.user["username"]
            });
        }else{
            req.session.error = "请先登录";
            res.redirect("login");
        }
      //res.render('home', {
      //    title: "登录成功页",
      //    username: getLoginController.userList().username
      //});
    });

    判断session下是否有user这个对象,有的话从user里面读取用户信息,否则直接跳转到登录页。

    好了,到这就全部改写完了,重启服务,用注册过的用户名继续测试:

    image_thumb12_thumb

    测试通过!并且可以从session里读取到用户信息,输入一个没注册过的用户:

    image_thumb14_thumb

    并且当我们直接访问home页是,如果session里有用户信息,那么可以直接登录,否则就会跳转到登录页

    还记不记得我们当初还写了一个登出的按钮,现在简单的写一下登出的功能:

    /*GET logout page.*/
    router.get('/logout', function (req, res){
        req.session.user = null;
        req.session.error = null;
        res.redirect("/login");
    });

    登出的时候清空session的信息,并跳转到登录页。

    重启服务进行测试,点退出登录后可以看到返回到了登录页

    此时我们再直接访问home页,由于session信息已被清除,所以也直接跳转到了登录页~ 大功告成!!!

    至此,我们整个的登录注册的功能就算是告一段落,可以发现,其中任何一块写起来都没有难度,难的是将他们之前串联起来,难的是这个整体架构的思路思维,所以平时还是要多思考,

    把整体的逻辑思路弄通了,那问题也就自然而然的解决了~

    无代码,无真相~ 代码请戳这里!

  • 相关阅读:
    Maven笔记(一)
    Oracle JDBC通过占位符可以查询可变长字段,不可查询固定长度字段
    Oracle 汉字在不同字符集下所占字节
    Spring Bean注册解析(一)
    Spring AOP切点表达式用法总结
    ThreadPoolExecutor详解
    数据库索引创建与优化
    ScheduledThreadPoolExecutor详解
    使用三种方法求解前N个正整数的排列
    后缀表达式的计算
  • 原文地址:https://www.cnblogs.com/lvvlan/p/4626578.html
Copyright © 2020-2023  润新知