express+mongoose简易登录,以及封装思想(纯新手向)

1,199 阅读6分钟

项目规划

  • 前端页面编写和ajax请求
  • express接收前端数据,mongoose数据库连接验证,登录判断
  • 对mongoose数据库连接的封装

这里是我上传的简单的项目的github地址

github.com/rabZhang/ex…

前端页面的编写

  1. 注册页面

    这里就是简单的编写了个前端页面 用到bootstrap官方演示的登录页面

    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    

    直接引用的bootCDN然后简单的传了个ajax

     $(function(){
          $('.btn').on('click',function(){
            let username=$('#username').val();
            let password=$('#password').val();
            $.ajax({
                  type: "POST",
                  url: "http://127.0.0.1:3000/register",
                  dataType:'json',
                  data:{
                    username,
                    password
                  },    
                  success: function(response) {
                    const result = JSON.parse( response)
                    switch ( result.status ) {
                      case 1:
                        // 注册成功
                        if ( confirm('恭喜您注册成功,是否要跳转到登录页面') ){
                          setTimeout( function () {
                            location.href = "./login.html"
                          },2000)
                        }
                        break;
                        case 2: 
                        // 用户名重复了
                        alert('用户名已经重复,请您确认后在注册')
                        break;
                      }
                  },
                  error: function(response) {
                    console.log(response);
                  }
                }); 
          })
        })
    
  2. 登录页面

    和注册页面几乎一样 无非就是改变了下url的地址

      url: "http://127.0.0.1:3000/login",
    

    然后再加入了登录的token的判断

     const token=cookieUtil.get('token');//这里的cookieUtil是下面封装的
        if(token){
          alert('检测到已经登录,两秒后转到首页');
          setTimeout(function(){
            location.href="./index.html";
          },2000)
        }
    

    期间用到了自己封装的cookie.js用来获取和设置cookie

    const cookieUtil={
        get: function(key) {
            if (document.cookie) { //判断是否有cookie
                let arr = document.cookie.split('; '); //拆分cookie
                for (let i = 0; i < arr.length; i++) {
                    let item = arr[i].split('='); //拆分cookie,获得key和value
                    // 遍历寻找key 返回值
                    if (item[0] === key) return item[1];
                }
                return ''; //如果遍历结束 都没有找到  返回空字符串
            }
        },
        set: function(key, value, day) {
            if (day) {
                var d = new Date();
                d.setDate(d.getDate() + day);
                document.cookie = `${key}=${value};expires=${d};path=/`;
            } else {
                document.cookie = `${key}=${value};path=/`;
            }
        },
        remove: function(key) {
            this.set(key, '', -1);
        }
    };
    

    简单的登录页面也完成了

  3. 忘记密码

    这里忘记密码就是简单的模拟密码修改,从登录页面添加一个按钮跳转到密码修改页面,

     url: "http://127.0.0.1:3000/modify" //就修改下ajax请求的url而已其他都一样
    

    现在前端的基本页面已经做好了,开始处理后端路由。

后端请求接收以及逻辑处理

  1. node.js/express基础包配置

    我这里是直接用express-generator 需要的小伙伴可以全局安装

    npm install express-generator -g
    npm install //安装express中的json包依赖
    

    然后直接在项目文件下打开bash输入

    express install '项目名' -e -S
    
    (这里的e指的是express ejs模板引擎的支持,不选的话默认jade)
    

    express安装完之后进入文件夹 没有全局安装的nodemon的小伙伴可以全局安装下nodemon 热更新,不想全局安装的可以安装在包依赖里面

     npm install nodemon
     //装完了包依赖会显示这样,当然全局安装的就不需要执行这一步了
      "dependencies": {
        "nodemon": "^2.0.1"
       }
    

    打开package.json,找到start 修改成下面这样

      "scripts": {
            "start": "nodemon ./bin/www"
        },
    

    然后试运行npm start 没报错就可以啦。

  2. 配置路由 先来想想我们需要配置几个路由

    1. 登录

    在项目文件夹中的routes路由文件夹下面创建login.js文件

     ```
     const express=require('express'); //引入第三方模块
     const router=express.Router();  //配置路由
     const jwt=require('jsonwebtoken'); //登录用的token
     const path=require('path'); //文件路径 内置模块
     const fs=require('fs');//文件操作 内置模块
     const {users}=require('../database'); //后面会讲到的 自定义模块 数据库封装
     router.route('/login') //如果这里写了路由,那么app.js路由组中就不必写路由了  	    
     .post(async (req,res,next)=>{ //三个参数 请求 相应 路由中间件的next (async)设置es6中的generator异步操作
         let results=req.body;
         if(!results.token){ //如果登录没有传token
     	const private_key=fs.readFileSync(path.join(__dirname,'..','rsa/private_key.pem')) //私钥
     	//如果不会配置私钥的朋友可以去查看下npm 中jsonwebtoken手册中 这边配置比较麻烦 另开一贴介绍
     	const token =jwt.sign({username:results.username}, private_key, { algorithm: 'RS256'})//token创建
     	const searchitem = await users.query(results); //(await)es6中的generator异步操作 yield
     	res.json(   //返回searchitme中的返回值
     		JSON.stringify({
     		status:searchitem.status,
     		msg:searchitem.msg,
     		token:searchitem.status==1 && token || '用户名密码错误,token不返回'
     	}))
         }
     
         })
         module.exports=router;//导出自定义模块
     ```
    
    1. 注册

    在项目文件夹中的routes路由文件夹下面创建register.js文件

    const express=require('express'); //引入第三方模块
    const router=express.Router();//路由
    const {users}=require('../database')//自定义数据库连接
    router.route('/register') //register路由
    	.post(async (req,res,next)=>{ //与登录同理
    		const results=await users.add(req.body);
    		res.json(
    			JSON.stringify({
    				status:results.status,
    				info:results.info
    			})
    		)
    	})
    
    module.exports=router	
    
    1. 修改

    在项目文件夹中的routes路由文件夹下面创建modify.js文件

     const express =require('express')
     const router =express.Router();
     const {users} =require('../database');//这里是引入数据库连接自定义模块 后面会讲
     router.route('/modify')
     .post(async (req,res,next)=>{
    	const data =req.body;
    	const results=await users.update(data);
    	res.json(JSON.stringify({
    		status:results.status,
    		msg:results.msg
    	}))
     })
     module.exports=router
    

    这样三个子路由就创建好了 接下来去app.js中引入子路由和配置中间件路由组

    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    var loginRouter = require('./routes/login');
    var registerRouter=require('./routes/register');
    var modifyRouter=require('./routes/modify');
    var cors = require('cors'); //这里提前引入cors的包 等下要解决跨域问题 cors npm直接下
    var app = express();
    

    配置路由中间件

    app.use(cors({   //这里实现跨域 不太懂的可以去https://www.npmjs.com/ 看下cors手册
        "origin": "*",
        "methods": "GET,HEAD,PUT,PATCH,POST,DELETE",
        "preflightContinue": false,
        "optionsSuccessStatus": 200
    }))
    app.use('/', indexRouter); //这里都是中间件的路由组 '/'是路由组 如果子路由配置完 这里就不用再配置了
    app.use('/users', usersRouter);
    app.use('/',loginRouter);
    app.use('/',registerRouter);
    app.use('/',modifyRouter); 
    

    这样配置完后 已经可以从前端发送数据请求然后后端接收了。只不过少了数据库连接模块。 这里我们使用的是mongoose模块来完成,同样你也可以在npmjs.com中查看手册

mongoose实现数据库连接

  1. 安装mongoosedb模块

    npm install mongodb
    

    创建database文件模块

    目录结构分析

  2. 文件分析

    如果简单的按照手册来配置的话可以完全不用这么麻烦,一个文件按照手册从数据库连接再到文档操作 一系列流程下来最多半小时模块就完成了,但是是要有封装思想,可能你着30分钟写完之后你以后再回 来看,或者在对数据维护,其实非常不方便,这时候就需要引入封装思想

    index.js 这是database的入口文件

    //引入mongoose
    
      const mongoose = require('mongoose') //引入模块
    
    //连接数据库
      const connect=require('./connect');//数据库连接封装
      connect();
    // 创建骨架
    
      const {users,shops}=require('./handle')//模型操作
    
    
     module.exports = { //导出
        users,shops
      }
    

    constant.js这里是方便线上修改的模块 ,把以后容易修改的变量值都放入这里

        const HOST='127.0.0.1' //本地服务器域名
        
        //const HOST ='www.baidu.com' //以后项目上线需要的定位地址方便修改
        
        const DB_NAME=1910 //数据库名
        
        const DB_URL=`mongodb://${ HOST }:27017/${ DB_NAME }`;
        
        
        module.exports={
        	DB_URL
        }
    

    connect.js数据库连接操作模块

    const mongoose = require('mongoose');
    
    const {DB_URL}=require('./constant.js')
    
    
    function connect(){
    	mongoose.connect(DB_URL,{
    		useNewUrlParser: true,
    		useUnifiedTopology: true
    	},err=>{
    		if(err){
    			console.log(err)
    		}else{
    			console.log('数据库连接成功');
    		}
    	})
    }
    
    module.exports=connect
    
schema 文件夹
  1. index.js

        const userSchema = require('./userSchema')
        const shopSchema = require('./shopSchema') //引入模块
        
        module.exports = { //一起导出模块
          userSchema,
          shopSchema
        }
    
  2. userSchema.js

     const mongoose = require('mongoose')
    
     const userSchema=new mongoose.Schema({
      username: String,
      password: String  //这里就是你创建mongodb 集合的字段 这里就可以理解为关系型数据库里面的建表环节
     })
     module.exports=userSchema
    
  3. shopSchema.js

    内容同上 自己定义表就好了

model文件夹

这里的操作很简单 就是一个简单的函数

index.js

 const mongoose =require('mongoose');
 const model = ( collectionName, schema ) => {
   return mongoose.model( collectionName, schema ) //两个参数 一个是创建集合的名称 ,一个是传入Schema
   //可以理解为 关系型数据库中的创建表 然后自定义表名
 }
 
 module.exports = model
handle文件夹
  1. index.js
```
const shops =require('./shopHandler');
const users =require('./userHandler'); //导入

module.exports={//导出
	shops,
	users
}
```
  1. shopHandler.js
 const {shopSchema}=require('../schema');
 const model=require('../model')
 const shopModel=model('shops',shopSchema)//使用model文件夹下的函数 实现表创建
 const shops = { //增删查改
   add () {},
   del () {},
   update () {},
   query () {}
 }
 
 module.exports = shops
  1. userHandler.js
 
 const {userSchema}=require('../schema');
 const model=require('../model')
 const userModel=model('users',userSchema)
 const users = {
   add (data) {
   	return new Promise((resolved,rejected)=>{ //和之前路由子文件 下面对应 Promise操作修改异步操作 实现同步
   		userModel.find({},(err,docs)=>{
   			const f=docs.some(item=>data.username==item.username) //如果传来的注册账户和数据库中的有相同的
   			if(f){
   				resolved({
   					status:2,
   					info:'用户名重复'
   				})
   			}else{
   				const userEnity=new userModel(data)
   				userEnity.save(err=>{
   					if(err){
   						rejected({
   							status:0,
   							info:'注册失败'
   						})
   					}else{
   						resolved({  //返回给子路由文件,再由子路由文件传给前端
   							status:1,
   							info:'注册成功'
   						})
   					}
   				})
   			}
   		})
   	})
   },
   del () {},
   update(data) {
      return new Promise((resolved,rejected)=>{
           userModel.find({username:data.username,password:data.password},(err,docs)=>{//mongodb语法
           //查找账户名和密码相同的文档
            if(docs.length!=0){
             userModel.findById(docs[0]._id,(err,doc)=>{
               doc.password=data.newpassword;
               doc.save(err=>{
                 if(err){
                   rejected({
                     status:0,
                     msg:'修改失败'
                   })
                 }else{
                   resolved({
                     status:1,
                     msg:'修改成功'
                   })
                 }
               })
             })
             }else{
               resolved({
                 status:2,
                 msg:'账号或密码不正确,无法修改'
               })
             }
           })
      })
   },
   query (data) {
     return new Promise((resolved,rejected)=>{
       userModel.find({},(err,docs)=>{
         const f=docs.some(item=>(item.username==data.username&&item.password==data.password))
         if(f){
           resolved({
             status:1,
             msg:"登录成功"
           })
         }else{
           rejected({
             status:2,
             msg:"登陆失败,用户名或是密码不正确"
           })
         }
       })
     }).catch((err)=>{
       return err;
     })
   }
 }
 
 module.exports = users

这样一个简单的项目就完成了 。