Nodejs+Express+MongoDB actual combat

Project installation
  1. Install express scaffolding:npm install express-generator -g
  2. Create a project: express -e project-e represents the use of ejs template, project is the name of the project
  3. Enter the project: npm installdownload the dependency package
  4. Install nodemon: npm install nodemon -guse nodemon to start the project, not node to start
    Insert picture description here
  5. Startup project: npm start,The port number can be seen in the www startup file.
The project connects to the MongoDB database
  1. Install mongodb integrated with nodejs:npm install mongodb -S

  2. Create a model file in the project, create index.js below, and all the code connected to the database are encapsulated in this file

     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}
    
  3. Call: It will be used to write data to the database through routing

     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;
    
Operating database syntax after the project introduces MongoDB
  1. When registering, write user registration data to the database

     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');
           }
         })
       })
    
  2. When logging in, look up the corresponding data in the database to see if it is consistent with the database

     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');
         }
       }
     })
    

    })

Login interception (after the login is successful, the user's information will be saved. In the specified time, the user does not need to enter the account and password when logging in again)
  1. A tool module is used here-the express-sessionserver is to save through the session

  2. installation:npm install express-session -S

  3. The first step in configuring session: Introduce in app.jsvar session = require('express-session');

  4. Configure session second step: configure session middleware in app.js

     // session配置
     app.use(session({
       secret: 'wangrenke project', // 可以随便改的
       resave: false,
       saveUninitialized: true,
       cookie: { maxAge: 1000 * 60 * 5 }  // 在服务端使用session时,会向客户端写入cookie,所以这里要指定一个cookie的有效期(即用户登陆多久是有效的)这里是五分钟
     }))
    
  5. Use: When the user logs in successfully, we need to store a session and store the user in the session, so that when we request again from the front-end, we first go to seesion to get the username. If there is a value, it means the login status, directly Skip the landing page, otherwise, jump to the landing page to log in again

     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');
             }
           }
         })
       })
    
  6. Set up login blocking

     // 登录拦截(当进入系统的时候)
     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();
     })
    
sign out
  1. Clear personnel information in the session

  2. Jump to the landing page

     // 退出登录
     router.get('/loginout',function(req,res,next){
       req.session.username = null;
       res.redirect('/login');
     })
    
Add, delete, modify and check (write article publishing function) ---- add
  1. When writing an article, you need to use the rich text box plugin xhEditor:http://xheditor.com/download

  2. After downloading xhEditor, put the xheditor folder in our project, under pulice.
    Insert picture description here

  3. Use: Introduce dependent files in the corresponding html file and initialize 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"
     });
    
  4. Add one to the textarea element class='xheditor', so you can see the effect when you refresh the page
    Insert picture description here

  5. Create a new route article.js dedicated to writing articles. Then configure article in app.js:var articleRouter = require('./routes/article');app.use('/article', articleRouter);

  6. When writing an article for saving, we need to add a piece of data to save the article in the mongodb database. When we submit it, we can save it in the database.

Article list implementation
  1. New article——After writing the article, it is saved in the database in mongodb. After saving, you must jump to the homepage, so the homepage must have a list of articles. So when we are rendering the home page route. Operate mongodb and fetch it from the corresponding list data. Show on the page

     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 });
         });
       })
     });
    
  2. The time we save to the library is milliseconds. Take it out too, so use a plug-in to convert the time:npm install moment -S

  3. Use moment: Introduce in the file that needs to be usedvar 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 });
         });
       })
    
Paging query
  1. js part

     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 });
             })
           })
         });
       })
     });
    
  2. ejs part

     <!-- 分页 -->
       <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>
    
Delete article
// 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);
    })
  })
})
modify articles
  1. When you click Edit, the page and the new page share the same page

  2. When modified: share the same interface as the new one, and the same data path collection

     // 渲染写文章页面 || 编辑文章页面
     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('/');
               }
           })
         })
       }
     });
    
Article details page (click the title to view the details)
  1. The basic logic is the same as editing

  2. Create a new detail page

     <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});
           }
         })
       })
     })
    
File upload (also via the rich text plugin xheditor)
  1. Configuration parameter
    Insert picture description here

  2. Defined on the server/upload路由

  3. A third-party plug-in is required to process file uploads multiparty, and the fixed format of the upload must bemultiparty/form-data

  4. Download: npm install multiparty -S,Introduction: var multiparty = require('multiparty');,Instantiate: After var form = new multiparty.Form()instantiation, the request body can be parsed through the form object, and the files in the request body can be parsed and processed. Get the result we want;

     // 文件上传
     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});
           })
         }
       })
     })
    
Project summary

A collection of registration, login, login interception, session storage, paging, and mongodb addition, deletion, modification, and checking

Guess you like

Origin blog.csdn.net/weixin_43996999/article/details/103832849