首页 > 数据库 >Nodejs+Express+MongoDB实战

Nodejs+Express+MongoDB实战

时间:2023-09-15 11:35:54浏览次数:45  
标签:function username req err Nodejs MongoDB Express res var

项目安装
  1. 安装express脚手架:npm install express-generator -g
  2. 创建项目:express -e project -e代表使用ejs模板,project是项目名称
  3. 进入项目:npm install下载依赖包
  4. 安装nodemon:npm install nodemon -g 使用nodemon来启动项目,不用node来启动
  5. 启动项目:npm start,端口号在www启动文件中可以看。
项目连接MongoDB数据库
  1. 安装集成与nodejs的mongodb:npm install mongodb -S
  2. 在项目中创建model文件,在下面创建index.js,所有和数据库连接的代码都封装在这个文件下
const MongoClient = require('mongodb').MongoClient;  // 创建Mongo的客户端对象
 const url = 'mongodb://localhost:27017';  // 连接数据库url
 const dbName = 'project';   // 连接的数据库名字
 // 数据库的连接方法封装
 function connect(callback){
     // 使用connect方法连接到服务器
     // err:错误对象。client:客户端连接成功的对象
     MongoClient.connect(url, function(err, client) {
         if(err){ // 如果连接错误,打印错误信息
             console.log('数据库连接错误!',err);
         }else{  // 否则
             const db = client.db(dbName);  // 数据库连接成功的对象
             callback && callback(db);  // 利用回调函数处理
             client.close();  // 每次调用成功,还要再关闭数据库
         }
     });
 }
 
 module.exports = {connect}
  1. 调用:通过路由向数据库写入数据会用到
var express = require('express');
 var router = express.Router();
 var model = require('../model');  // 引入连接数据库方法
 /* GET users listing. */
 router.get('/', function(req, res, next) {
   res.send('respond with a resource');
 });
 
 // 注册接口
 router.post('/regist',function(req, res, next){
   var data = {
     username:req.body.username,
     password:req.body.password,
     password2:req.body.password2
   }
   model.connect(function(db){
     db.collection('users').insert(data,function(err,ret){
       if(err){
         console.log('注册失败!',err);
         res.redirect('/regist');
       }else{
         res.redirect('/login');
       }
     })
   })
 })
 
 module.exports = router;
项目引入MongoDB后的操作数据库语法
  1. 注册时,向数据库中写入用户注册的数据
model.connect(function(db){ // 这里的data是form表单提交过来的数据
     db.collection('users').insert(data,function(err,ret){
       if(err){
         console.log('注册失败!',err);
         res.redirect('/regist');
       }else{
         res.redirect('/login');
       }
     })
   })
  1. 登陆时,在数据库中查找对应的数据,看看是否和数据库中一致
model.connect(function(db){  // 连接数据库
 // 进入users库,寻找data这个数据.toArray转换成数组
 db.collection('users').find(data).toArray(function(err,docs){
   // 如果报错,重新登陆
   if(err){
     res.redirect('/login');
   }else{  
     // 否则校验数据,如果是空数组,说明没找到这个用户,让他去重新登录.找到的话.登陆成功,进入主页面
     if(docs.length > 0){
       // 登陆成功,进行session会话存储(将用户的信息进行存储)
       // 这样的话,前端每次去请求的时候,先去session里面找username,如果有值,那么证明他是登陆状态的,那么直接跳转登陆页面就好
       req.session.username = data.username;
       res.redirect('/'); // 进入主页
     }else{
       res.redirect('/login');
     }
   }
 })

})

登录拦截(登陆成功后,会保存下用户的信息,在指定的时间里,用户再登录就不需要输入帐号和密码了)
  1. 在这里用到了一个工具模块express-session----服务端就是要通过session来保存
  2. 安装:npm install express-session -S
  3. 配置session第一步:在app.js中引入var session = require('express-session');
  4. 配置session第二步:在app.js中配置session中间件
// session配置
 app.use(session({
   secret: 'wangrenke project', // 可以随便改的
   resave: false,
   saveUninitialized: true,
   cookie: { maxAge: 1000 * 60 * 5 }  // 在服务端使用session时,会向客户端写入cookie,所以这里要指定一个cookie的有效期(即用户登陆多久是有效的)这里是五分钟
 }))
  1. 使用:在用户登陆成功的时候,要去做一个会话的存储,将用户用存进session中,这样我们前端再请求的时候,先去seesion中取username,如果有值,说明是登陆状态,直接跳过登陆页面,否则,跳转登陆页面重新登陆
model.connect(function(db){  // 连接数据库
     // 进入users库,寻找data这个数据.toArray转换成数组
     db.collection('users').find(data).toArray(function(err,docs){
       // 如果报错,重新登陆
       if(err){
         res.redirect('/login');
       }else{  
         // 否则校验数据,如果是空数组,说明没找到这个用户,让他去重新注册.找到的话.登陆成功,进入主页面
         if(docs.length > 0){
           // 登陆成功,进行session会话存储(将用户的信息进行存储)
           // 这样的话,前端每次去请求的时候,先去session里面找username,如果有值,那么证明他是登陆状态的,那么直接跳转登陆页面就好
           req.session.username = data.username;
           res.redirect('/'); // 进入主页
         }else{
           res.redirect('/login');
         }
       }
     })
   })
  1. 设置登录拦截
// 登录拦截(当进入系统的时候)
 app.get('*',function(req,res,next){
   var user = req.session.username;
   var path = req.path;
   console.log("session----user",user);
   // 如果是进的登录页或注册页,我们不拦截
   if(path != '/login' && path != '/regist'){
     if(!user){
       res.redirect('/login');
     }
   }
   next();
 })
退出登录
  1. 清除session中的人员信息
  2. 跳转到登陆页面
// 退出登录
 router.get('/loginout',function(req,res,next){
   req.session.username = null;
   res.redirect('/login');
 })
增删改查(写文章发布功能)----增
  1. 写文章时需要用到富文本框插件xhEditor:http://xheditor.com/download
  2. 下载xhEditor后,将xheditor文件夹放在我们项目中,pulice下。
  3. 使用:在相应html 文件中引入依赖的文件并且初始化xheditor
<script type="text/javascript" src="/xheditor/jquery/jquery-1.4.4.min.js"></script>
 <script type="text/javascript" src="/xheditor/xheditor-1.2.2.min.js"></script>
 <script type="text/javascript" src="/xheditor/xheditor_lang/zh-cn.js"></script>
 <script>
 // 其实在本项目中基本上用前两个就行了
 $('#elm1').xheditor({
     tools: 'full',
     skin: 'default',
     showBlocktag: true,
     internalScript: false,
     internalStyle: false,
     width: 300,
     height: 200,
     loadCSS: 'http://xheditor.com/test.css',
     fullscreen: true,
     sourceMode: true,
     forcePtag: true,
     upImgUrl: "upload.php",
     upImgExt: "jpg,jpeg,gif,png"
 });
  1. 在textarea元素上加一个class='xheditor',这样刷新页面就可以看到效果了
  2. 新建一个专门处理写文章的路由article.js。然后在app.js中配置article:var articleRouter = require('./routes/article');app.use('/article', articleRouter);
  3. 写文章提交保存时,我们需要在mongodb数据库中,添加一条保存文章的数据。让我们提交保存时,能够存到数据库中。
文章列表实现
  1. 文章新增----写文章实现后,保存到了mongodb中的数据库中。保存后肯定要跳转到主页,那么主页一定有一个文章列表。那么我们在渲染主页页面路由的时候。操作mongodb,从对应的列表数据中取出来。展示到页面上
router.get('/', function(req, res, next) {
   var username = req.session.username;
   model.connect(function(db){
     // 从库中,将articles文章张列表的数据。取出来转换成数组
     db.collection('articles').find().toArray(function(err,docs){
       console.log('文章列表------',docs);
       var list = docs; // 文章列表,用来传到index.ejs中
       res.render('index', { msg: '首页',username:username,list:list });
     });
   })
 });
  1. 我们存到库中的时间是毫秒。取出来也是,所以要使用一个插件用来转换时间:npm install moment -S
  2. 使用moment:在需要用的文件引入var moment = require("moment");
model.connect(function(db){
     // 从库中,将articles文章张列表的数据。取出来转换成数组
     db.collection('articles').find().toArray(function(err,docs){
       console.log('文章列表------',docs);
       var list = docs; // 文章列表,用来传到index.ejs中
       list.map(function(item){
         item.time = moment(item.id).format("YYYY-MM-DD hh:mm:ss");
         return item;
       })
       res.render('index', { msg: '首页',username:username,list:list });
     });
   })
分页查询
  1. js部分
router.get('/', function(req, res, next) {
   var username = req.session.username || '';
   // 当前页
   var pageIndex = req.query.pageIndex || 1;
   // 分页
   var data = {
     total: 0,  // 文章总共的页数
     curPage: pageIndex,  // 当前页
     list: [],   // 当前页的文章列表
   }
   var pageSize = 10;  // 每次请求10条数据
   model.connect(function(db){
     // 第一步:查询所有文章(从库中,将articles文章张列表的数据。取出来转换成数组)
     db.collection('articles').find().toArray(function(err,docs){
       // 文章列表总条数/每页显示的条数,向上取整。得到一共有多少页。
       data.total = Math.ceil(docs.length / pageSize);
       // 第二步:查询当前页的文章列表(分页查询)
       model.connect(function(db){
         // 重点:sort({_id:-1})表示倒序查询;limit(pageSize)表示限制多少条;skip((pageIndex - 1)*pageSize)从多少条开始查
         db.collection('articles').find().sort({_id:-1}).limit(pageSize).skip((pageIndex - 1)*pageSize).toArray(function(err,doc2){
         // 这里考虑到如果删除的时候,当前页只剩一条数据,那么删完之后,需要把对应的页签也删掉。
           if(doc2.length == 0){
             res.redirect('/?pageIndex='+((pageIndex-1) || 1));
             return;
           }
           doc2.map(function(item){
             item.time = moment(item.id).format("YYYY-MM-DD hh:mm:ss");
             return item;
           })
           data.list = doc2;
         res.render('index', { msg: '首页',username:username,data:data });
         })
       })
     });
   })
 });
  1. ejs部分
<!-- 分页 -->
   <div class="page">
     <span>共<%= data.list.length %>条</span>
     <a class="top">上一页</a>
     <% for(var i = 1; i<=data.total; i++){ %>
       <a href="/?pageIndex=<% i %>" class="pages"><%= i %></a>
     <% } %>
     <a class="next">下一页</a>
   </div>
删除文章
// ejs页面
<a href="/article/delete?id=<%= item.id %>&pageIndex=<%= data.curPage %>">删除</a>
// /delete路由代码
// 删除
router.get('/delete',function(req,res,next){
  var id = parseInt(req.query.id); // 页面传过来的需要删除的id
  var pageIndex = req.query.pageIndex; // 页面传过来的当前页
  model.connect(function(db){
  	// 删除对应id的数据deleteOne()
    db.collection('articles').deleteOne({id: id},function(err,ret){
      if(err){
        console.log('删除失败!!');
      }else{
        console.log('删除成功!!');
      }
      // 删除完成后接着跳转对应的页面路由,这里有一个问题,就是如果删除时只剩一条数据,那么删掉之后需要把那一页的分页也删掉。这个限制在主体路由上。
      res.redirect('/?pageIndex='+pageIndex);
    })
  })
})
修改文章
  1. 点击编辑时,页面和新增共用一个页面
  2. 修改时:和新增共用一个接口,同一个数据路集合
// 渲染写文章页面 || 编辑文章页面
 router.get('/write',function(req,res,next){
   var username = req.session.username;
   var id = parseInt(req.query.id);
   var pageIndex = req.query.pageIndex;
   var item = {
     title:'',  // 标题
     content:''  // 内容
   }
   if(id){  // 如果有id,那么就是编辑
     model.connect(function(db){
       db.collection('articles').findOne({id:id},function(err,docs){
         if(err){
           console.log('查询失败!!!!');
         }else{
           item = docs
           item.pageIndex = pageIndex;
           console.log('aaaaaaa-------',item);
           res.render('write',{msg:'编辑文章',username:username,item:item});
         }
       })
     })
   }else{  // 否则就是新增
     res.render('write',{msg:'写文章',username:username,item:item});
   }
 })
 /* 新增 || 编辑 */
 router.post('/add', function(req, res, next) {
   var id = parseInt(req.body.id);
   if(id){  // 编辑
     var pageIndex = req.body.pageIndex;
     var title = req.body.title;
     var content = req.body.content;
     model.connect(function(db){
       db.collection('articles').updateOne({id:id},{$set:{title:title,content:content}},function(err,ret){
           if(err){
               console.log('文章修改失败!',err);
           }else{
             console.log('文章修改成功!');
               res.redirect('/?pageIndex='+pageIndex);
           }
       })
     })
   }else{   // 新增
     var data = {
       title: req.body.title,  // 标题
       content: req.body.content,  // 内容
       id: Date.now(),   // 时间戳(什么时候提交的)
       username: req.session.username  // 提交的用户(是谁写的)
     }
     model.connect(function(db){
       db.collection('articles').insert(data,function(err,ret){
           if(err){
               console.log('文章发布失败!',err);
               res.redirect('/write');
           }else{
               res.redirect('/');
           }
       })
     })
   }
 });
文章详情页(点击标题可以查看详情)
  1. 基本逻辑同编辑一样
  2. 新建一个详情页
<td><a href="/detail?id=<%= item.id %>"><%= item.title %></a></td>
 ---------------------------------------------------
 // 查看文章详情页面
 router.get('/detail',function(req,res,next){
   var username = req.session.username;
   var id = parseInt(req.query.id);
   var item = {
     title:'',  // 标题
     username:'',  // 作者
     id:'',   // 时间&&id
     content:'',  // 内容
   }
   model.connect(function(db){
     db.collection('articles').findOne({id:id},function(err,docs){
       if(err){
         console.log('查询失败!!!!');
         res.redirect('/');
       }else{
         item = docs;
         item.time = moment(item.id).format('YYYY-MM-DD hh:mm:ss');
         res.render('detail',{msg:'详情页',username:username,item:item});
       }
     })
   })
 })
文件上传(也是通过富文本插件xheditor)
  1. 配置参数
  2. 在服务端定义/upload路由
  3. 处理文件上传需要用到第三方插件multiparty,上传固定格式必须要是multiparty/form-data
  4. 下载:npm install multiparty -S,引入:var multiparty = require('multiparty');,实例化:var form = new multiparty.Form()实例化后就可以通过form对象,来解析请求体,把请求体中的文件解析处理。得到我们想要的结果;
// 文件上传
 router.post('/upload',function(req,res,next){
   var form = new multiparty.Form();
   form.parse(req,function(err,fields,files){
     if(err){
       console.log('上传失败呗!!!');
     }else{
       console.log('文件列表----',files);
       // 这个就是拿到的上传的文件数据,我们需要使用fs管道流的方式,写入到硬盘
       var file = files.filedata[0];
       var newPath = '/uploads/'+file.originalFilename;  // 写入的路径加文件名字
       var rs = fs.createReadStream(file.path);  // 第一个流(读取的)--读的时候,就读带的路径就行
       var ws = fs.createWriteStream("./public"+newPath);  // 第二个流(写入的)--写的时候要写在服务端-这里放在pulice下的uploads中
       rs.pipe(ws);
       // 当写入完成的时候,监听一个on('close')事件
       ws.on('close',function(){
         console.log('文件上传成功!!!');
         res.send({err:'',msg:newPath});
       })
     }
   })
 })
项目总结

集合了注册、登录、登录拦截、会话存储、分页、结合mongodb增删改查

标签:function,username,req,err,Nodejs,MongoDB,Express,res,var
From: https://blog.51cto.com/u_16264339/7479469

相关文章

  • nodejs+koa2+mongodb 从0到1搭建自己的项目
    nodejs+koa2+mongodb从0到1搭建自己的项目YDJFE2018-09-2811:2419207   相信这对于想要入门写nodejs的朋友来说,一定会有所收获,那么,下面开始我们的正题(这里不使用koa-generator脚手架,我们直接自己搭建项目,适用于前后端分离)一:创建项目可以在全局中安装koa依赖包......
  • 在nodejs中使用Typescript 金字教程
    1.首先新建一个项目npminit-yes2.开启Typescript依赖npminstalltypescript--save-dev安装typescript,现在我们可以通过命令行来使用tsc命令3.安装nodejs类型npminstall@types/node--save-dev4.使用命令创建一个tsconfig.json文件npxtsc--init--rootDir......
  • 界面组件DevExpress WinForms v23.1亮点 - 全新升级HTML & CSS模板
    DevExpressWinForms拥有180+组件和UI库,能为WindowsForms平台创建具有影响力的业务解决方案。DevExpressWinForms能完美构建流畅、美观且易于使用的应用程序,无论是Office风格的界面,还是分析处理大批量的业务数据,它都能轻松胜任!DevExpressWinForm 控件已正式发布v23.1版本,此版......
  • nodeJs读取JOSN文件导出多个word文件
    前言最近遇到一个需求,读取JOSN文件,以JSON文件的标题为word的文件名导出多个文档,利用nodeJs和 officegen实现了该功能exportWords.js代码如下/***读取指定文件夹下的JSON文件,导出多个word文件*一个json文件导出多个word文件,通常以json文件中的title作为导出的word的文......
  • nodeJS读取JSON文件导出word文档
    前言最近遇到一个需求,将JSON文件的内容,导出到word文档,利用nodeJs和Officegen实现了文件导出的功能exportAWord.js代码如下/***读取指定文件夹下的JSON文件,导出为word*一个json文件为一个word,以json文件的名称为word文件的名称*/letfs=require("fs");letpath=......
  • MongoDB Sharding深入学习
    对于MongoDB的Sharding(分片)技术并不陌生,但是发现里面其实还是有不少值得深入学习的东西。笔记整理一下发上来跟大家分享。-----------------------------------一、MongoDB分片机制:1、一个分片包含数据的某一子集。若某一分片包含多台服务器。则每台服务器都拥有完整的数据副本。......
  • mongodb
    什么是findAndModify操作?findAndModify是MongoDB中的一个原子操作,它可以在一个操作中查找文档并进行修改。它可以在多线程环境中安全地更新文档,避免了竞态条件。在findAndModify操作中,你可以指定一个查询条件来选择要修改的文档,并可以通过提供更新操作来修改该文档。在修改完成后,f......
  • 界面控件DevExpress WPF TreeMap,轻松可视化复杂的分层结构数据!
    DevExpressWPF TreeMap控件允许用户使用嵌套的矩形块可视化复杂的平面或分层结构数据。P.S:DevExpressWPF拥有120+个控件和库,将帮助您交付满足甚至超出企业需求的高性能业务应用程序。通过DevExpressWPF能创建有着强大互动功能的XAML基础应用程序,这些应用程序专注于当代客户的......
  • vscode 终端报错:无法加载文件 D:\nodejs\npm.ps1,因为在此系统上禁止运行脚本。
    问题:vscode终端执行npm指令时报错如下解决:1.在终端通过输入指令get-ExecutionPolicy得到以下结果:表示当前执行策略为受限的2.执行指令Set-ExecutionPolicy-ScopeCurrentUser,并输入RemoteSigned。Set-ExecutionPolicy语法如下:Set-ExecutionPolicy[-Execu......
  • 如何使用Oracle Enterprise Manager Database Express连接到PDB数据库
    1.问题重复弹出登录框,无法登陆关闭登录框,显示invalidcontainername2.解决方法参考链接为PDB启动EMExpress要为PDB启动EMExpress,请确保PDB以读/写模式打开,然后尝试本主题中描述的以下方法之一(按所示顺序):连接到包含PDB的CDB的CDB$ROOT容器,并发出以下SQL......