• 【node进阶】深入浅出---MVC设计模式&RESTful风格


    ✅ 作者简介:一名普通本科大三的学生,致力于提高前端开发能力
    ✨ 个人主页:前端小白在前进的主页
    🔥 系列专栏 : node.js学习专栏
    ⭐️ 个人社区 : 个人交流社区
    🍀 学习格言: ☀️ 打不倒你的会使你更强!☀️
    💯 刷题网站:这段时间有许多的小伙伴在问有没有什么好的刷题网站,博主在这里给大家推荐一款刷题网站:👉点击访问牛客网👈牛客网支持多种编程语言的学习,各大互联网大厂面试真题,从基础到拔高,快来体验一下吧!


    在这里插入图片描述

    🔥前言

    在前面的文章我们已经会写接口了,但是接口不能瞎写啊,必须要具备规范性,同时为了使我们写的代码更容易维护,必须要学会业务分层(MVC),这样的话使相应的人做相应的事情,接下来正文开始!

    接口规范

    RESTful架构

    • 为什么要用RESTful
      在以往我们去写接口的时候,我们总是自己去命名,虽然不影响正常的使用,但是当你进入到一个大一点的开发团队里面你得遵循团队的接口规范,大多数团队用的就是RESTful规范(当然,不是所有的团队都是,但是你通过学习RESTful就可以轻松入手其他的规范,道理是相差无几的),为了能够无缝衔接的进入到团队开发,RESTful架构是值得学习的。
    • 通俗理解RESTful
      RESTful就是对自己写的接口进行规范化,使用RESTful架构可以充分的发挥GETPOSTPUTDELETE 四种请求方式的意义,简单的来说url地址中只包含名词表示资源,使用http的动词(GET | POST | PUT | DELTE)表示要进行的动作进行操作资源
    • 举例
      • 错误的设计方式

        //添加用户
        router.post('/user/addUser',(req,res)=>{
          //...
        })
        //更新用户信息
        router.put('/user/updateUser',(req,res)=>{
          //...
        })
        //删除用户
        router.delete('/user/delUser',(req,res)=>{
          //...
        })
        //获取用户信息
        router.get('/user/getUser',(req,res)=>{
          //...
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16
      • 正确的设计方式

        //添加用户
        router.post('/user',(req,res)=>{
          //...
        })
        //更新用户信息
        router.put('/user/:id',(req,res)=>{
          //...
        })
        //删除用户
        router.delete('/user/:id',(req,res)=>{
          //...
        })
        //获取用户信息
        router.get('/user',(req,res)=>{
          //...
        })
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13
        • 14
        • 15
        • 16

        注意:后端要跟前端进行语义化的规定,统一战线!例如:想要获取用户信息,前端发送GET请求即可…


    使用方式

    REST要求,必须通过统一的接口来对资源执行各种操作:

    请求方式URL解释
    GEThttp://localhost:8080/user获取全部用户信息
    GEThttp://localhost:8080/user/1 (1是id参数值,同时也是请求路径的一部分)获取单个信息
    POSThttp://localhost:8080/user创建用户
    PUThttp://localhost:8080/user/1更新 id为1的员工信息
    DELETEhttp://localhost:8080/user/2删除 id为2的用户信息
    HEAD获得一个资源的元数据,比如一个资源的hash值或者最后修改日期
    OPTIONS获得客户端针对一个资源能够实施的操作,获取该资源的api

    过滤信息

    一般情况下我们只是把?简单的当做是参数的传递,很容易造成url过于复杂、难以理解。可以把?用于对资源的过滤.
    例如:

    请求方式URL解释
    GEThttp://localhost:8080/user?page=2&limit=5指定获取到第2页数据,限制每一页5条数据
    GEThttp://localhost:8080/user?sortby=name&order=asc指定获取数据按照名字排序,以及按照acs排序
    GEThttp://localhost:8080/user?state=close可以自定义设置筛选条件

    注意:我们在进行筛选的时候一定要与后端做好约定。


    业务分层

    MVC设计模式

    MVC应该是编程界众所周知的,M即Model,V即View,C即Controller。分别对应我们的业务模型,用户界面控制器。用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。

    上面一直用官方的话来说,大家肯定觉得比较抽象,下面我以画图的形式展现了出来(画的不好,大家应该可以看懂),MVC每层之间的逻辑关系:
    在这里插入图片描述
    controller:C层负责业务逻辑(view与model之间的桥梁)
    view:V层负责展现页面
    model:M层负责处理数据(连接数据库进行增删改查)


    node中使用MVC思想

    在这里先分享一下node中的MVC是怎么样实现的,如下图所示:
    在这里插入图片描述


    node中MVC实现代码(RESTful+MVC)

    通过上图我们了解到了MVC思想在node中怎么执行的,接下来,我们通过代码进行分析:

    1. 代码架构
      在这里插入图片描述

    2. db.config.js(连接数据库

      //链接数据库
      
      const mongoose = require("mongoose")
      
      mongoose.connect("mongodb://127.0.0.1:27017/lzq_project")
      //插入集合和数据,数据库lzq_project会自动创建
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
    3. UserService.js(创建模型,配置数据库信息)

      const mongoose = require('mongoose')
      
      const UseeType = {
          username : String,
          password : String,
          age : Number
      }
      const UserModel = mongoose.model('user',new mongoose.Schema(UseeType))
      //模型user 将会对应 users 这个集合,
      module.exports = UserModel
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    4. user.js(用户路由模块)

      var express = require('express');
      const UserController = require('../controllers/UserController');
      var router = express.Router();
      
      /* GET users listing. */
      router.get('/', function(req, res, next) {
        res.send('respond with a resource');
      });
      
      //相应前端post请求-增加用户
      router.post('/user',UserController.addUser)
      //动态路由,获取id
      router.put('/user/:id',UserController.updateUser)
      //删除请求  restful
      router.delete('/user/:id',UserController.delUser)
      
      router.get('/user',UserController.getUser)
      
      
      module.exports = router;
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
    5. UserModel.js(M层,业务逻辑实现数据库增删改查)

      const UserModel = require("../model/UserModel")
      const UserService = {
          addUser : (username,password,age) => {
              return UserModel.create({username,password,age})
          },
          updateUser : (_id,username,password,age)=>{
              return UserModel.updateOne({_id},{
                  username,password,age
                })
          },
          delUser : (_id) => {
              return UserModel.deleteOne({_id})
          },
          getUser : (page,limit) => {
              return UserModel.find({},["username","age"]).skip((page-1)*limit).limit(limit).sort({age:-1})//年龄倒序排列---  -1   正序   1
          }
      }
      module.exports = UserService
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
    6. UserController.js(C层,把M层的数据给V层)

      const UserService = require("../services/UserService");
      
      const UserController = {
          addUser: async (req,res)=>{
              console.log(req.body);
              //插入数据库
              // 1.创建模型,一一对应数据库的集合(users)
              const {username,password,age} = req.body
              await UserService.addUser(username,password,age)
              res.send({
                  ok:1
                })
          },
          //更新用户信息的回调函数
          updateUser: async (req,res)=>{
              console.log(req.body,req.params.id);
              const {username,password,age} = req.body
              await UserService.updateUser(req.params.id,username,password,age)
              res.send({ok:'ok'})
          },
          delUser : async (req,res)=>{
              await UserService.delUser(req.params.id)
              res.send({ok:'1'})
          },
          getUser : async (req,res)=>{ 
              console.log(req.query);
              const {page,limit} = req.query
              const data = await UserService.getUser(page,limit)
              res.send(data)
            }
      }
      module.exports = UserController
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
    7. index.ejs(V层,前端显示的页面)

      <body>
        <h1>mongoDB增删改查的演示</h1>
        <div>
          <div>用户名:<input id="username" /></div>
          <div>密码:<input type="password" id="password" /></div>
          <div>年龄:<input type="age" id="age" /></div>
          <div><button id="register">注册</button></div>
        </div>
        <hr>
        <div>
          <button id="update">更新</button>
          <button id="del">删除</button>
        </div>
        <hr>
      
        <table border="1">
          <thead>
            <tr>
              <td>id</td>
              <td>用户名</td>
              <td>年龄</td>
              <td>操作</td>
            </tr>
          </thead>
          <tbody>
      
          </tbody>
        </table>
        <script>
          let name = document.querySelector('#username')
          let psd = document.querySelector('#password')
          let age = document.querySelector('#age')
          register.onclick = () => {
            console.log(name.value, psd.value, age.value);
            fetch("/api/user", {
              method: 'post',
              body: JSON.stringify({
                username: name.value,
                password: psd.value,
                age: age.value
              }),
              headers: {
                "Content-Type": "application/json"
              }
            }).then(res => res.json())
              .then(res => {
                console.log(res);
              })
          }
          update.onclick = () => {
            fetch("/api/user/634f5d8ed2922eaf4a9972b1", {
              method: 'put',
              body: JSON.stringify({
                username: "修改的名字",
                password: "修改的密码",
                age: 20
              }),
              headers: {
                "Content-Type": "application/json"
              }
            }).then(res => res.json())
              .then(res => {
                console.log(res);
              })
          }
          del.onclick = () => {
            fetch("/api/user/634f5d8ed2922eaf4a9972b1",{
              method:'DELETE'
            }).then(res => res.json())
              .then(res => {
                console.log(res);
              })
          }
      
          fetch("/api/user?page=1&limit=5").then(res => {
            return res.json()
          }).then(res => {
            console.log(res);
            let tbody = document.querySelector('tbody')
            tbody.innerHTML = res.map(item => {
              return `
                    ${item._id}
                    ${item.username}
                    ${item.age}
                     
                   `
            }).join('')
            tbody.onclick = (event) => {
              console.log(event.target);
              if (event.target.id === "btn") {
                fetch(`/api/user/${event.target.dataset.id}`, {
                  method: 'post',
                  body: JSON.stringify({
                    username: "以后绝不压竞猜&阿修",
                    age: 22
                  }),
                  headers: {
                    "Content-Type": "application/json"
                  }
                }).then(res => res.json())
                  .then(res => {
                    fetch("/api/user?page=1&limit=5").then(res => res.json())
                      .then(res => {
                        tbody.innerHTML = res.map(item => {
                          return `
                    ${item._id}
                    ${item.username}
                    ${item.age}
                     
                   `
                        }).join('')
                      })
      
                  })
              }
              if (event.target.id === 'del') {
                console.log(event.target.id);
                fetch(`/api/user/${event.target.dataset.id}`).then(res => res.json()).then(res => {
                  fetch("/api/user?page=1&limit=5").then(res => res.json())
                    .then(res => {
                      tbody.innerHTML = res.map(item => {
                        return `
                    ${item._id}
                    ${item.username}
                    ${item.age}
                     
                   `
                      }).join('')
                    })
                })
              }
      
            }
          })
        </script>
      </body>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
      • 70
      • 71
      • 72
      • 73
      • 74
      • 75
      • 76
      • 77
      • 78
      • 79
      • 80
      • 81
      • 82
      • 83
      • 84
      • 85
      • 86
      • 87
      • 88
      • 89
      • 90
      • 91
      • 92
      • 93
      • 94
      • 95
      • 96
      • 97
      • 98
      • 99
      • 100
      • 101
      • 102
      • 103
      • 104
      • 105
      • 106
      • 107
      • 108
      • 109
      • 110
      • 111
      • 112
      • 113
      • 114
      • 115
      • 116
      • 117
      • 118
      • 119
      • 120
      • 121
      • 122
      • 123
      • 124
      • 125
      • 126
      • 127
      • 128
      • 129
      • 130
      • 131
      • 132
      • 133
      • 134
      • 135
      • 136
    8. 最终效果
      在这里插入图片描述

    MVC的优缺点

    从上面的代码中可以观察得出来一个事情,我们的代码结构很清晰,分离一层一层去写,方便维护,但是同时发现项目明显的便复杂了,所以总结了MVC的优缺点:
    MVC的优点

    1. 耦合性低,方便维护,可以利于分工协作
    2. 代码的复用性比较强

    MVC的缺点:
    项目变得的确优点复杂,对书写代码的小伙伴们要求得比较多


    小结

    大家跟我的node专栏学习走到这里就可以发现一个有趣的事情:node+express+RESTful+MVC嘎嘎好用,其实到这里你的node可以进行适当的开发了,后面的文章加一个身份验证以及写一个全栈项目,node就要完结了,所以下一篇就是我们的身份验证,同时还要更新【node番外】mongoDBmysql两个数据库哦,以及node连接数据库。
    少年,继续加油吧!😀😀


    👑书写不易,希望大家能够给予三连支持,期待我更好的文章哟👑

  • 相关阅读:
    性能指标都不了解,如何做性能测试?
    Linux命令200例:dnsconf用于配置和管理域名解析服务
    Kernel: pipe_read:fread:解释:读取的实际长度与参数里带有的参数的区别。
    力扣(415.482)补8.28
    遇到的问题java和mysql篇
    西门子Mendix低代码资深技术顾问张戟,将出席“ISIG-低代码/零代码技术与应用发展峰会”
    Redisson分布式锁学习
    DSP开发入门
    从解除FB绑定到推出Meta账号系统,Meta在VR社交的新思考
    每天一个前端小知识01——Webpack
  • 原文地址:https://blog.csdn.net/m0_52040370/article/details/127345263