Node.js学习第七天笔记之登录注册项目和留言板项目

1 登录注册项目(form请求)

  • 项目文件:

    • MVC:
      • models:创建db.js,用于引入封装的数据库方法;创建md5.js,用于引入加密函数,对密码加密;
      • views:创建login.ejs和reg.ejs文件,用于呈现登录和注册页面;
      • controllers:管理者,创建router.js,作为管理器;
    • mongodb:数据库;
    • form-app.js:服务器;
    • setting.js:作为db.js中引入,用于设置数据库地址url和数据库名字dbName;
    • 下载模块:express ejs mongodb formidable express-session
    • package.json:用于记录信息;
  • 思路:

    • 服务器中设置请求:
      • get:"/login" => 用于渲染页面login.ejs;
      • post:"/dologin" => 用于提交登录数据;
      • get:"/reg" => 用于渲染页面reg.ejs;
      • post:"/doreg" => 用于提交注册数据;
    • 渲染页面:res.render();
    • 获取表单post提交的数据:formidable;
    • 对密码进行加密处理;crypto md5;
    • 通过db.js中封装的数据库方法;对数据进行查找和插入;
      • db.find():用于查找数据;
      • db.insertOne():用于插入数据;
    • 登录成功和注册成功时,均需要设置session;
  • 知识点:

    • md5加密
      • 模块:node.js中的系统模块crypto;如:const crypto=require("crypto");
      • 创建md5格式的hash;如:const hash=crypto.createHash("md5");
      • 更新和转化数据str;必须为字符串;
        • 代码:var res=hash.update(str).digest("base64")
        • res为32为的乱码字符串;
        • 可进行重复加密,不易解密;如password=crypto.md5(crypto.md5(password)+"guomushan");
      • md5封装函数代码:
       exports.md5=function(str){
           //引入node系统模块
           const crypto=require("crypto");
           //创建hash
           const hash=crypto.createHash("md5");//创建md5格式;
           //加密文件
           return hash.update(str).digest("base64");//加密成64为的字符串;
       };
      
    • get请求用来渲染页面,post请求用来提交数据
    • 用formidable模块,获取表单post请求提交的参数;
    • 使用express模块创建服务器;
    • 使用express-session模块设置session;
      • 注意:引入中间件;获取和设置均用req;
    • 使用ejs模板渲染页面;需要设置模板引擎;
    • 数据库方法的封装中需要通过settings设置url和dbName;
  • 实例代码

    • 服务器form-app.js代码:
     //引入node系统模块
     
     //引入第三方模块
     const express=require("express");
     const session=require("express-session");
     
     //引入自定义模块
     const router=require("./controller");
     
     //创建服务器
     const app=express();
     //设置模板引擎
     app.set("view engine","ejs");
     //引入session中间件
     app.use(session({
         secret: 'keyboard cat',
         resave: false,
         saveUninitialized: true,
         cookie: { secure: false }//设置为false;
     }));
     
     //1.发送请求get:"/login" => 渲染登录页面
     app.get("/login",router.showlogin);
     //1.1 发送请求post:"/dologin" => 提交数据
     app.post("/dologin",router.dologin);
     
     //2.发送请求get:"/reg" => 渲染注册页面
     app.get("/reg",router.showreg);
     //2.1 发送请求post:"/reg" => 提交数据
     app.post("/doreg",router.doreg);
     
     //监听
     app.listen(8080);
    
    • 管理器router.js代码:
     //引入第三方模块
     const formidable=require("formidable");
     
     //引入自定义模块
     const db=require("../models/db");
     const crypto=require("../models/md5");
     
     //导出
     //渲染登录页面;
     exports.showlogin=function (req, res, next) {
         res.render("login");
     };
     //提交登录数据
     exports.dologin=function (req, res, next){
         const form=new formidable.IncomingForm();
         form.parse(req,function (err, fields, files) {
             var username=fields.username;
             var password=fields.password;//在页面中拿到的数据都是字符串;
             //密码加密处理
             password=crypto.md5(crypto.md5(password)+"guomushan");//双重加密
             db.find("users",{username},function (err, result) {
                 if(err){
                     res.send("服务器错误");
                     return;
                 }
                 if(result.length){
                     if(result[0].password===password){
                         //设置session
                         req.session.login="true";
                         req.session.username=username;
                         //登录成功
                         res.send({"bok":true,"msg":"恭喜你,登录成功!!!"})
                     }else{
                         res.send({"bok":false,"msg":"密码不正确,请重新输入"});
                     }
                 }else{
                     res.send({"bok":false,"msg":"用户名不存在,请注册!!!"});
                 }
             })
         })
     };
     
     //渲染注册页面
     exports.showreg=function (req, res, next) {
         res.render("reg");
     };
     //提交注册数据
     exports.doreg=function (req, res, next) {
         //通过formidable模块获取数据
         const form=new formidable.IncomingForm();
         form.parse(req,function (err, fields, files) {
             if(err){
                 res.send("获取数据失败");
                 return;
             }
             //拿到数据后需要对密码加密
             var username=fields.username;
             var password=fields.password;//在页面中拿到的数据都是字符串;
             //密码加密处理
             password=crypto.md5(crypto.md5(password)+"guomushan");//双重加密
             //连接数据库,查找数据,若无,则插入数据
             db.find("users",{username},function (err, result) {
                 if(err){
                     res.send("服务器错误");
                     return;
                 }
                 if(result.length){
                     //长度不为0,则代表数据存在;
                     res.send({"bok":false,"msg":"注册失败,该用户名已被注册!!!"});
                     return;
                 }else{
                     //长度为0,就证明用户名不存在,插入数据到数据库中;
                     db.insertOne("users",{username,password},function (err, result) {
                         if(err){
                             res.send("服务器错误");
                             return;
                         }
                         //设置session
                         req.session.login="true";
                         req.session.username=username;
                         //注册成功
                         res.send({"bok":true,"msg":"注册成功,请登录!!!"});
                     })
                 }
             })
         })
     };
    
    • 页面login.ejs代码:
     <!doctype html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>登录页面</title>
         <style>
             div{
                 width:500px;
                 height: 200px;
                 padding-top: 10px;
                 margin: 150px auto;
                 text-align: center;
                 background-color: lightpink;
             }
         </style>
     </head>
     <body>
     <div>
         <h1 style="color:blue;">登录页面</h1>
         <form action="/dologin" method="post">
             <p>
                 <label for="user">
                     用户名:<input type="text" id="user" name="username"/>
                 </label>
             </p>
             <p>
                 <label for="pass">
                     密  码:<input type="password" id="pass" name="password"/>
                 </label>
             </p>
             <input type="submit" value="请登录"/>
         </form>
     </div>
     </body>
     </html>
    

2 登录注册项目(ajax请求)

  • 请求方式使用ajax请求配合表单
    • ajax请求中主要是需要获取表单中的键值对,通过$("form").serialize();表单序列化拿到{key:val,key:val}格式的数据;与form的action以及method均无关;
    • 与form表单的区别:将submit按钮去掉,换成input(button)按钮,给其添加点击事件;然后触发事件,发送ajax请求;
    • 注意:不能换成<button>按钮,其点击后会默认提交get请求,会出错;
    • 先决条件:必须引入jQuery.js文件,所以需要设置静态资源目录,然后利用相对路径引入js文件;
  • login-ajax.ejs文件
    • form表单用于提供键值对数据,通过$("form").serialize()表单序列化来拿到键值对参数;
    • 设置按钮<input type="button" id="btn" value="请登录"/>;添加点击事件,进行ajax请求;
    • 引入jQuery.js文件;
    • 代码:
     <!doctype html>
     <html lang="en">
     <head>
         <meta charset="UTF-8">
         <title>登录页面</title>
         <style>
             div{
                 width:500px;
                 height: 200px;
                 padding-top: 10px;
                 margin: 150px auto;
                 text-align: center;
                 background-color: lightpink;
             }
         </style>
     </head>
     <body>
     <div>
         <h1 style="color:blue;">登录页面</h1>
         <form>
             <p>
                 <label for="user">
                     用户名:<input type="text" id="user" name="username"/>
                 </label>
             </p>
             <p>
                 <label for="pass">
                     密  码:<input type="password" id="pass" name="password"/>
                 </label>
             </p>
             <input type="button" id="btn" value="请登录"/>
         </form>
     </div>
     <script src="/js/jquery.js"></script>
     <script>
         $("#btn").on("click",function () {
             $.ajax({
                 url:"/dologin",
                 type:"post",
                 data:$("form").serialize(),
                 dataType:"json",
                 success:function (val) {
                     alert(val.msg)
                 }
             })
         })
     </script>
     </body>
     </html>
    
  • ajax-app.js服务器文件
    • 与form-app.js的区别在于,设置静态资源目录,用于引入jQuery.js文件;
    • 在渲染页面时,渲染login-ajax.ejs和reg-ajax.ejs文件;
    • 静态资源设置代码:app.use(express.static("./public"))

3 知识点:form表单submit提交按钮发送请求与ajax发送请求

3.1 form表单和ajax发送get请求

  • form表单和ajax提交get请求中如何设置数据参数;
    • form表单中get请求和post请求,区别就在于method设置不同,其余的设置没有区别,设置参数,都是通过name和value值;
    • form表单提交get请求;会默认将参数用问号拼接在url后面,显示在地址栏中;
  • ajax发送get请求如何设置数据参数;
    • ajax发送get请求时,type属性设置为"get",参数以键值对(key=val&key=val)的形式通过问号拼接在域名地址后面;设置url属性中;
    • 代码:
     //点击span发送post请求;
     $("span").click(function () {
         $.ajax({
             url:"/test?meiaho=djfj&tiankong=djid",
             type:"get",
             success:function (val) {
                 alert(val);
             }
         })
     })
    
  • 获取form表单submit提交按钮发送请求与ajax发送请求的参数
    • 在express中用req.query获取参数,为一个对象;

3.2 form表单和ajax发送post请求

  • 注意:
    • ajax设置data属性可以是key=val&key=val键值对;也可以是:{key:val,key:val}对象;
    • ajax中发送get请求和post请求,都可以设置data属性;
  • form表单和ajax提交post请求中如何设置数据参数;
    • form表单中设置post请求提交的参数:在每个文本框中设置name值和value值;通过submit提交自动形成{key:val,key:val}对象形式;参数不会呈现在地址栏中;
    • ajax设置post请求提交的参数:设置data属性,属性值格式为:{key:val,key:val}对象
  • form表单submit提交按钮-发送post请求
    • 表单结构:
      • form标签中设置action,method,enctype
        • action:指的是上传的服务器地址,包括完整的路由,如:http://localhost:8080/dologin;当地址栏中已经是在http://localhost:8080环境下,此时就只写/dologin即可;
        • method:指的是请求样式,一般为get和post请求;
        • ectype:指的是在post请求中根据上传数据的大小来设置;
          • 小数据:application/x-www-form-urlencoded;为默认值;可以省略;
          • 大数据:multipart/form-data;一般用于file文件上传和textarea文本上传;
      • 在表单input中必须设置name值,此值作为上传格式{key:val,key:val}中的key值;表单中输入的内容作value值;
      • 设置input类型为submit;点击默认提交数据;
    • 重要关键:表单发送请求,必须要设置submit类型,点击可提交请求;其他类型都不行;如何没有它,数据根本不能提交;
    • 代码:
     //action设置的前提条件是在"http://localhost:8080"环境下提交,才能省略;否则必须写全;
     <form action="/dologin" method="post">
         <p>
             <label for="user">
                 用户名:<input type="text" id="user" name="username"/>
             </label>
         </p>
         <p>
             <label for="pass">
                 密 码:<input type="password" id="pass" name="password"/>
             </label>
         </p>
         <input type="submit" value="请登录"/>
     </form>
    
  • ajax提交请求
    • 前提条件:必须引入jQuery.js文件或自己封装的ajax.js文件;能够正常使用ajax;
    • 在项目中使用时,
      • 新建public文件夹,存放静态文件,如js等文件;
      • 在服务器中设置静态资源目录为public目录下,如app.use(express.static("./public"));
      • 在html或ejs文件中,通过script引入jQuery.js文件,src设置相对路径在public目录下,才能引入成功;
    • 设置ajax属性参数;
      • url:指的是上传的服务器地址,包括完整的路由,如:http://localhost:8080/dologin;当地址栏中已经是在http://localhost:8080环境下,此时就只写/dologin即可;与form表单中的action设置等同;
      • type:设置"post",指post请求;
      • data:设置参数,格式为{key:val,key:val}
      • dataType:设置接收数据的类型,一般为json格式;
      • success:匿名函数接收服务器中res.send()或res.end()响应回来的数据;
    • 代码:
      • login1.ejs文件代码:
       <!doctype html>
       <html lang="en">
       <head>
           <meta charset="UTF-8">
           <title>ajax发送post请求</title>
       </head>
       <body>
       <div>
           <span style="background-color: red;cursor:pointer">提交</span>
       </div>
       <script src="/js/jquery.js"></script>
       <script>
           //点击span发送post请求;
           $("span").click(function () {
               $.ajax({
                   url:"/href",
                   type:"post",
                   data:{meiaho:djfj,tiankong:djid},
                   success:function (val) {
                       alert(val);
                   }
               })
           })
       </script>
       </body>
       </html>
      
      • 服务器代码:
       //设置静态资源目录,用于引用css或js文件;
       app.use(express.static("./public"));
       
       //设置get请求"/main",渲染login1.ejs页面
       app.get("/main",function (req, res) {
           res.render("login1");
       });
       //发送post请求"/href",提交数据,此地址为ajax中url属性设置;
       app.post("/href",function (req, res) {
           const formidable=require("formidable");
           const form=new formidable.IncomingForm();
           form.parse(req,function (err, fields, files) {
               if (err) {
                   res.send("获取数据失败");
                   return;
               }
               console.log(fields);
               res.send("111");//success接收的数据111
           })
       });
      
  • 获取form表单submit提交按钮发送请求与ajax发送请求的参数
    • 使用formidable模块获取post请求提交的参数;
      • 引入模块const formidable=require("formidable");
      • 新建form对象 const form=new formidable.IncomingForm();
      • 利用form.parse(req,function(err,fields,files){})中的fields获取数据,为一个对象;
    • 总结:不管通过什么形式发送post请求,formidable都能获取到发送请求中的参数;

4 留言板项目

  • 项目效果:
    • 通过地址栏输入地址,来获取留言页面;数据更新显示
    • 输入留言内容,点击提交按钮后,页面刷新,数据更新;
    • 刚刚提交的数据在第一页显示;
    • 页面进行分页显示;默认第一页显示;
    • 点击页面删除按钮,数据删除,页面更新;
  • 思路:
    • get:"/liuyan" => 渲染页面,展现留言面板;
    • post:"/doliuyan" => 提交数据,利用ajax提交,提交成功后需要刷新页面,所以不能使用表单提交;
    • 页面在渲染打开后,直接发送get请求,向数据库获取数据;
      • get: "/getliuyan" => 向数据库获取数据,通过DOM操作插入到页面中;
    • 所有数据都显示在页面中;
    • 实现排序和分页;
      • 在获取数据时,传入实参sort,来控制降序还是升序,此时用的是降序,通过time属性排序;
      • 是在获取数据时,传入实参page和pageamount,来设置分页;
        • 在第三步发送get请求"/getliuyan"时,需要给ajax设置data属性,传入page和pageamount属性;来获取分页数据;
    • 所以需要在获取数据之前先获取数据的总个数,然后计算出page页码个数;在拿数据,pageamount设置定值就好;
    • 设置ajax请求,get:"/getcount" => 获取所有数据的总个数;通过计算得到page页码个数;
      • 根据页码个数,插入DOM中,显示页码;
    • 页面加载后,默认在第一页显示,显示第一页的数据;所以需要设置page为0;$Li中第一个添加active类名;
    • 页码与数据进行同步设置
      • 给每个页码添加点击事件;然后拿到页码的索引值;
      • 设置点击谁,给谁添加active类名,将其点亮,其他的兄弟元素删除active类型;
      • 通过索引值来设置page值,进而再次请求数据,拿到数据,插入DOM;所以需要将获取数据的ajax封装在一个函数中;然后调用函数,传入实参,为索引值;
    • 点击页面上的删除按钮,删除数据,重新刷新页面;
      • 通过数据库中每条数据中的唯一的"_id"值,来进行查找;
      • 发送请求:通过a标签中的href来发送get请求,请求的地址为"/delete/id值";
      • 在服务器中通过设置get请求地址为正则表达式的地址"/delete/:xx";这样id的值为任意值,通过req.params.xx就能拿到请求时的id值;
      • 在数据库中数据为一个对象,对象中的属性为"_id",属性值为:ObjectId("5c16fef27b4f0c2374efd5ae");所以在调用deleteMany方法时,设置的json格式也为此格式;
      • 所以需要用到mongdb中的模块ObjectID,则需要引入模块;即const ObjectID = require('mongodb').ObjectID;
      • 查找数据时的json为:{"_id":ObjectID(id)};
      • 在删除数据成功后,需要跳转到原来页面,也就是再发送一次"/liuyan"的请求;用到的知识点为:res.redirect("/liuyan");;即,跳转到某页面;
      • 如果想要对删除成功后做出响应,可以使用ajax请求;通过success函数内操作;
  • 注意:
    • 重点:
      • 在此项目中需要用到jQuery.js和bootstrap.js等文件;需要在页面中引用;所以必须设置静态资源目录;
      • 引入css和js文件时,在静态资源目录相对路径下设置;
    • 此项目中,指对页面进行了三次刷新;
      • 第一次:地址栏输入"/liuyan";打开留言页面;
      • 第二次:提交数据完成后,前端刷新页面;用到的代码:window.location.href="/liuyan";
      • 第三次:在删除数据后,服务器端通过res.redirect()跳转页面;即再次发送请求;代码:res.redirect("/liuyan");
      • 注意:在页面刷新后,就会默认设置第一页数据显示,所以在分页点击时,不能刷新页面;必须重新调用findData函数,获取数据,重新插入DOM;
    • 此项目均使用ajax提交请求,不用表单的原因:ajax提交请求,可以通过success拿到响应结果,对其进行操作,而表单不能对响应结果进行操作;
    • 项目中ajax请求默认是异步操作的,所以想让其同步运行,必须设置async属性为false;
    • 项目中ajax请求的两种形式都使用了;
      • post请求提交数据,get获取数据;
      • 二者的参数都是通过data属性进行设置,一般设置为对象,也可以是键值对格式的字符串;
      • ajax请求中,get请求提交的参数,在服务器端通过req.query来拿,拿到一个对象;
      • ajax请求中,post请求提交的参数,在服务器端通过formidable模块来拿;拿到的也是一个对象;
    • 此项目中,从数据库中获取数据,封装为一个函数;总共调用了两次
      • 第一次:默认设置页面为第一页,显示第一页的数据,调用findData()函数,传入实参为0;即设置page值为0;进而获取第一页的数据;
      • 第二次:分页设置点击事件中,当点击某一页时,获取此元素的索引,作为调用findData()函数的实参,即设置page的值,从而拿到对应页码的数据,然后插入DOM显示;
    • 时间的设置,通过第三方模块silly-datetime,设置成固定格式,然后插入到数据库;
  • 代码:
    • levmes.ejs文件代码:
     <!DOCTYPE html>
     <html lang="zh-CN">
     <head>
         <meta charset="utf-8">
         <title>留言板</title>
         <link href="/css/bootstrap.css" rel="stylesheet">
         <style>
             body{
                 font-size: 18px;
             }
             @media (min-width: 768px){
                 .form-horizontal .control-label{
                     padding-top: 0;
                 }
             }
         </style>
     </head>
     <body>
     <div class="container">
         <h1 style="text-align: center;padding:20px;">我的留言板</h1>
         <form class="form-horizontal" style="width: 50%;margin:0 auto;">
             <div class="form-group">
                 <label for="user" class="col-md-2 control-label">姓 名</label>
                 <div class="col-md-10">
                     <input type="text" class="form-control" id="user" name="username" placeholder="请输入姓名">
                 </div>
             </div>
             <div class="form-group">
                 <label for="contents" class="col-md-2 control-label">留 言</label>
                 <div class="col-md-10">
                     <textarea class="form-control" name="contents" id="contents" cols="20" rows="5" placeholder="请输入留言"></textarea>
                 </div>
             </div>
             <div class="form-group">
                 <div class="col-sm-offset-2 col-sm-10">
                     <input type="button" class="btn btn-default" id="btn" value="请提交">
                 </div>
             </div>
         </form>
     </div>
     <div class="container">
         <nav aria-label="Page navigation" style="width: 50%;margin:10px auto 0; font-size:14px;padding-left: 30px;">
             <ul class="pagination" id="ul2">
                 <!--<li><a href="#">1</a></li>-->
             </ul>
         </nav>
         <ul class="list-group" id="ull" style="width: 50%;margin:10px auto 0; font-size:14px; padding-left: 30px;">
             <!--<li class="list-group-item">
                 <p>【姓名】:xxx</p>
                 <p>【留言】:xxx</p>
                 <p>【事件】:xxx</p>
                 <p><a href="">删除</a></p>
             </li>-->
         </ul>
     </div>
     <script src="/js/jquery.js"></script>
     <script src="/js/bootstrap.js"></script>
     <script>
         var $user=$("#user"),
             $contents=$("#contents"),
             $time=new Date(),
             pageamount=3;
     
         //1. ajax发送post请求,提交表单数据
         $("#btn").on("click",function () {
             $.ajax({
                 url:"/doliuyan",
                 type:"post",
                 data:{username:$user.val(),contents:$contents.val()},//时间通过后台传入
                 success:function (val) {
                     if(val.bok){
                         //alert(val.msg);
                         window.location.href="/liuyan";//数据提交成功后,重新刷新页面;
                     }else{
                         console.log(val.msg);
                     }
                 }
             })
         })
         //2. get请求,获取数据库中的数据总个数,算出页码个数,插入DOM
         $.ajax({
             url:"/getcount",
             type:"get",
             async:false,//必须设置为同步
             success:function (val) {
                 if(val.bok){
                     //获取到总个数,计算分页的个数page
                     var countAll=val.msg;
                     var pageAll=Math.ceil(countAll/pageamount);//向上取整
                     //确定页码的个数,然后插入DOM
                     var str="";
                     for(var i=0; i<pageAll; i++){
                         str+=`<li><span style="cursor:pointer">${i+1}</span></li>`;
                     }
                     $("#ul2").html(str);
                 }else{
                     console.log(val.msg);
                 }
             }
         })
     
         //3. 插入DOM后,获取元素li,默认设置第一个页码点亮,并显示第一页数据;注意:jQuery中无DOM映射;
         var $aLi=$("#ul2").children("li");
         //默认让第一页显示;并显示第一页的数据
         $($aLi[0]).addClass("active");
         findData(0);//默认获取第一页数据;
     
         //4.每个li添加点击事件,然后点亮它,点击事件触发后,不能请求页面;否则会默认为第一页;
         $aLi.click(function () {
             //获取页码索引
             var n=$(this).index();
             $(this).addClass("active").siblings("li").removeClass("active");
             //设置同步数据
             findData(n);//设置page值,拿到对应的数据,插入页面;
         })
     
         //封装方法findData:ajax发送get请求,拿数据,放入DOM,只要页面一加载,立刻发送请求,拿数据;
         function findData(index) {
             $.ajax({
                 url:"/getliuyan",
                 type:"get",
                 data:{page:index,pageamount},//分页传参
                 async:false,
                 success:function (val) {
                     if(val.bok){
                         //拿到数据库数据,将其插入到DOM中;
                         var str="";
                         $.each(val.msg,function () {
                             str+=`<li class="list-group-item"><p>【姓名】:${this.username}</p><p>【留言】:${this.contents}</p><p>【时间】:${this.time}</p><p><a href="/delete/${this._id}">删除</a></p></li>`})
                         //插入到DOM
                         $("#ull").html(str);
                     }else{
                         console.log(val.msg);
                     }
                 }
             })
         }
     
         //5.点击页面删除按钮,数据删除,页面更新;
         //此处利用a标签href提交get请求;
         //如果想要对删除成功后做出响应,可以使用ajax请求;通过success函数内操作;
     </script>
     </body>
     </html>
    
    • levmes-app.js服务器代码:
     const express=require("express");
     const router=require("./controller/router2");
     const app=express();
     app.listen(8080);
     
     //设置模板引擎
     app.set("view engine","ejs");
     //设置静态资源目录
     app.use(express.static("./public"));
     
     //1.渲染页面
     app.get("/liuyan",router.showIndex);
     //2.post提交数据,ajax请求的数据
     app.post("/doliuyan",router.doliuyan);
     //3.get请求,拿到数据库中的数据,ajax发送get请求
     app.get("/getliuyan",router.getliuyan);
     //4.get请求,拿到数据库中的数据总个数,ajax发送get请求;
     app.get("/getcount",router.getcount);
     //5.get请求,删除数据,更新页面,a标签中href提交的get请求;
     app.get("/delete/:id",router.deleteData);
    
    • router2.js管理器代码:
     //引入模块
     const db=require("../models/db");
     const formidable=require("formidable");
     const ObjectID = require('mongodb').ObjectID;
     const sd = require('silly-datetime');
     
     //导出
     //渲染留言板页面
     exports.showIndex=function (req, res, next) {
         res.render("levmes");
     };
     //提交数据到数据库
     exports.doliuyan=function (req, res, next) {
         //拿到前端ajax提交过来的数据;
         var form=new formidable.IncomingForm();
         form.parse(req,function (err, fields, files) {
             //插入时间数据
             fields.time=sd.format(new Date(),"YYYY-MM-DD HH:mm:ss");
             db.insertOne("liuyan",fields,function (err, result) {
                 if(err){
                     res.send({"bok":false,"msg":"提交数据失败"});
                     return;
                 }
                 res.send({"bok":true,"msg":"留言成功!!!"})
             })
         })
     };
     //获取数据库中数据,响应会前端
     exports.getliuyan=function (req, res, next) {
         //获取前端传来的参数
         var page=req.query.page;
         var pageamount=req.query.pageamount;
         //向数据库获取数据find
         db.find("liuyan",{},{"sort":{"time":-1},page,pageamount},function (err, result) {
             if(err){
                 res.send({"bok":false,"msg":"获取数据库数据失败"});
                 return;
             }
             res.send({"bok":true,"msg":result});
         })
     };
     //获取数据库中的总个数
     exports.getcount=function (req, res, next) {
         db.count("liuyan",{},function (err, result) {
             if(err){
                 res.send({"bok":false,"msg":"获取数据库数据总个数失败"});
                 return;
             }
             res.send({"bok":true,"msg":result});
         })
     };
     //删除数据
     exports.deleteData=function (req, res, next) {
         var id=req.params.id;//通过params拿到冒号后面的数据;
         //拿到数据库每个数据的id值;然后通过ObjectID拼接id处理查找数据;
         db.deleteMany("liuyan",{"_id":ObjectID(id)},function (err, result) {
             if(err){
                 res.send("删除数据失败");
                 return;
             }
             //数据删除成功之后,通过res.redirect()来跳转会原页面;
             res.redirect("/liuyan");
         });
     };
    
    • db.js数据库封装方法代码:
     //引入mongodb模块
     const MongoClient=require("mongodb").MongoClient;
     //引入自定义模块setting
     const setting=require("../setting-liuyan");
     //数据库地址
     const url=setting.url;
     //数据库名
     const dbname=setting.dbName;
     
     //连接数据库
     function mongoConnect(callback) {
         MongoClient.connect(url,{ useNewUrlParser: true },function (err, client) {
             if(err){
                 console.log("连接数据库失败");
                 return;
             }
             //将client通过callback回调函数传出;
             callback(client);
         });
     }
     
     //1.在数据库中指定集合插入一条数据;
     //参数:集合, 插入数据,callback导出信息
     exports.insertOne=function (collectionName, json, callback) {
         mongoConnect(function (client) {
             //获取数据库db,注:3.0以上版本获取数据库会有差异;
             var db=client.db(dbname);
             var col=db.collection(collectionName);
             col.insertOne(json,function (err, result) {
                 callback(err,result);
                 client.close();//关闭与数据库的连接
             })
         })
     };
     
     //2.查找数据库中集合下的数据
     //参数:集合 待查找的数据  分页和排序参数 callback导出信息
     //其中第三个分页和排序参数可传可不传;
     exports.find=function (collectionName,json1,json2,callback) {
         if(arguments.length===3){
             //说明json2没有传;第三个参数传的是回调;
             callback=json2;
             json2={};
         }
         var sort=json2.sort || {};//默认值为空对象,即乱序;
         var limit=Number(json2.pageamount) || 0;//默认值为0,必须为数字
         var skip=Number(json2.page) || 0;//默认跳过0;
         mongoConnect(function (client) {
             var db=client.db(dbname);
             var col=db.collection(collectionName);
             //用toArray将获取的数据以数组的形式传出;
             col.find(json1).sort(sort).limit(limit).skip(skip*limit).toArray(function (err, doc) {
                 callback(err,doc);
                 client.close();//关闭与数据库的链接
             })
         })
     };
     //3 修改更新数据
     //参数:集合 待修改数据  修改后的数据 callback导出信息
     exports.updateMany=function (collectionName, json1, json2, callback) {
         mongoConnect(function (client) {
             var db=client.db(dbname);
             var col=db.collection(collectionName);
             col.updateMany(json1,json2,function (err, result) {
                 callback(err,result);
                 client.close();
             })
         })
     };
     //4 删除
     //参数:集合 待删除 callback导出信息
     exports.deleteMany=function (collectionName, json, callback) {
         mongoConnect(function (client) {
             var db=client.db(dbname);
             var col=db.collection(collectionName);
             col.deleteMany(json,function (err, result) {
                 callback(err,result);
                 client.close();
             })
         })
     };
     //5 获取集合下满足条件的总个数
     //参数:集合 数据 callback导出信息
     exports.count=function (collectionName, json, callback) {
        mongoConnect(function (client) {
            var db=client.db(dbname);
            var col=db.collection(collectionName);
            col.countDocuments(json,function (err, count) {
                callback(err,count);
                client.close();
            })
        })
     };
    
    • setting-liuyan.js设置数据库地址和名称文件代码:
     //设置数据库地址
     exports.url="mongodb://localhost:27017";
     //设置数据库名称
     exports.dbName="liuyankuang";
    

5 留言板项目复习

  • 思路:
    • 通过res.render()来向ejs模板发送参数,前端通过获取的参数渲染DOM页面;
    • 进行分页显示时,可以通过拿到page参数进行跳转设置,get请求:/liuyan?page=2
  • 代码
    • guestbook.ejs代码:
     <!DOCTYPE html>
     <html lang="zh-CN">
     <head>
         <meta charset="utf-8">
         <meta http-equiv="X-UA-Compatible" content="IE=edge">
         <meta name="viewport" content="width=device-width, initial-scale=1">
         <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
         <title>留言板实例</title>
     
         <!-- Bootstrap -->
         <link href="/css/bootstrap.css" rel="stylesheet">
         <link href="/css/guestbook.css" rel="stylesheet">
         <!-- HTML5 shim 和 Respond.js 是为了让 IE8 支持 HTML5 元素和媒体查询(media queries)功能 -->
         <!-- 警告:通过 file:// 协议(就是直接将 html 页面拖拽到浏览器中)访问页面时 Respond.js 不起作用 -->
         <!--[if lt IE 9]>
         <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
         <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
         <![endif]-->
     </head>
     <body>
     <div class="container">
         <div class="guestcon">
             <h1 style="text-align: center;padding: 20px;">留言板</h1>
             <form class="form-horizontal">
                 <div class="form-group">
                     <label for="user" class="col-sm-2 control-label">姓 名</label>
                     <div class="col-sm-10">
                         <input type="text" class="form-control" name="user" id="user" placeholder="请输入姓名" required>
                     </div>
                 </div>
                 <div class="form-group">
                     <label for="liuyan" class="col-sm-2 control-label">留 言</label>
                     <div class="col-sm-10">
                         <textarea class="form-control" name="msg" id="liuyan" cols="10" rows="5" placeholder="请输入留言" required="required"></textarea>
                     </div>
                 </div>
                 <div class="form-group">
                     <div class="col-sm-offset-2 col-sm-10">
                         <input type="button" id="btn" class="btn btn-primary" value="提交留言"/>
                     </div>
                 </div>
             </form>
             <div class="panelcon">
                 <nav aria-label="Page navigation">
                     <ul class="pagination">
                         <%for(var j=0; j<count; j++){%>
                         <%if(j===page){%>
                         <li class="active"><a href="/liuyan?page=<%= j+1%>"><%= j+1%></a></li>
                         <%}else{%>
                         <li><a href="/liuyan?page=<%= j+1%>"><%= j+1%></a></li>
                         <%}%>
                         <%}%>
                     </ul>
                 </nav>
                 <div class="panel panel-default">
                     <ul class="list-group">
                         <%for(var i=0; i<datas.length; i++){%>
                         <li class="list-group-item">
                             <p>【姓名】:<%= datas[i].username%></p>
                             <p>【留言】:<%= datas[i].msg%></p>
                             <p>【时间】:<%= datas[i].curtime%></p>
                             <p style="text-align: right;margin-bottom: 0;"><a href="/delete/<%= datas[i]._id%>">删除</a></p>
                         </li>
                         <%}%>
                     </ul>
                 </div>
             </div>
         </div>
     </div>
     <script src="/js/jquery.js"></script>
     <script src="/js/bootstrap.js"></script>
     <script>
         //1.按钮点击事件提交数据
         $("#btn").click(function () {
             $.ajax({
                 url:"/doliuyan",
                 type:"post",
                 data:$("form").serialize(),
                 dataType:"json",
                 success:function (val) {
                     if(val.bok){
                         if(val.curr){
                             alert(val.msg);
                             //重新刷新页面
                             window.location.href="/liuyan";
                         }
                     }else{
                         if(val.curr){
                             alert(val.msg);
                         }else{
                             console.log(val.msg);
                         }
                     }
                 },
                 error:function (err) {
                     console.log(err);
                 }
             })
         });
     </script>
     </body>
     </html>
    
    • app.js代码:
     //引入模块
     const express=require("express");
     
     //引入自定义模块
     const router=require("./controllers/router");
     
     //创建服务器
     const app=express();
     
     //设置模板引擎
     app.set("view engine","ejs");
     //设置静态资源目录
     app.use(express.static("./public"));
     //路由设置
     //get:"/liuyan" 渲染留言板页面,并获取指定页码内的数据
     app.get("/liuyan",router.showIndex);
     //post:"/doliuyan" 提交留言数据
     app.post("/doliuyan",router.toLiuyan);
     //get:"/:id" 删除数据
     app.get("/delete/:id",router.deleteData);
     
     
     //端口号监听
     app.listen(5555,function () {
         console.log("5555 server is running");
     });
    
    • router.js代码:
     const formidable=require("formidable");
     const sd=require("silly-datetime");
     const db=require("../models/guestdb");
     const ObjectID=require("mongodb").ObjectID;
     
     module.exports={
         //渲染留言板页面,并获取指定页码内的数据
         showIndex:function (req, res, next) {
             //前端获取参数,如:"/liuyan?page=2"
             var pageobj=req.query;
             //创建page,pageamount
             var page=pageobj.page-1 || 0;
             var pageamount=3;
             //获取所有的数据
             db.find("liuyan",{},{sort:{"curtime":-1},page,pageamount},function (err, docs) {
                 if(err){
                     res.send(err);
                 }
                 //获取所有数据的总个数
                 db.count("liuyan",{},function (err, count) {
                     if(err){
                         res.send(err);
                     }
                     res.render("guestbook",{
                         datas:docs,
                         count:count/pageamount,
                         page:Number(page)
                     });
                 });
             });
         },
         //提交留言数据到数据库
         toLiuyan:function (req, res, next) {
             var form=new formidable.IncomingForm();
             form.parse(req,function (err, fields) {
                 if(err){
                     res.send({"bok":false,"curr":false,"msg":err});
                 }
                 if(fields.user.length && fields.msg.length){
                     var time=sd.format(new Date(),"YYYY-MM-DD hh:mm:ss");
                     //插入到数据库
                     db.insertOne("liuyan",{"username":fields.user,"msg":fields.msg,curtime:time},function (err, doc) {
                         if(err){
                             res.send({"bok":false,"curr":false,"msg":err});
                         }
                         res.send({"bok":true,"curr":true,"msg":"提交成功"});
                     });
                 }else{
                     res.send({"bok":false,"curr":true,"msg":"输入框内不能为空,请输入内容"});
                 }
             })
         },
         //删除数据
         deleteData:function (req, res, next) {
             db.deleteOne("liuyan",{_id:ObjectID(req.params.id)},function (err, doc) {
                 if(err){
                     res.send(err);
                 }
                 res.redirect("/liuyan");
             })
         }
     };
    
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,552评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,666评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,519评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,180评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,205评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,344评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,781评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,449评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,635评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,467评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,515评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,217评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,775评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,851评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,084评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,637评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,204评论 2 341

推荐阅读更多精彩内容