0
点赞
收藏
分享

微信扫一扫

Nodejs+Express+MongoDB实战

项目安装
  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增删改查

举报

相关推荐

0 条评论