104-《Nodejs开发》-MVC

103 阅读4分钟

目录

  • MVC的概念
  • mvc的组成
  • 项目中使用mvc进行优化

一、 MVC 简介

1.1 为什么要用mvc

  • 在生活中,我们用衣柜存储服饰物品,但是如果一股脑全放进去,不加整理和归纳,后续的维护和使用就非常麻烦,所以推荐需要对物品进行整理和归纳。如图1 和图2

img

图1

img

图2

  • 在后端编程中,routes/路由.js就包含了路由的业务代码以及数据库的集合模型(Schema和关联)代码,整个文件包含了太多的内容,不方便后续维护。所以可以使用mvc模式对后端代码进行拆分,把不同作用的的代码放在不同的js文件中,对后续代码的维护和扩展更有帮助。

1.2 MVC 概念

  • MVC是一种软件的架构思想。主要是指规范了一个拥有良好扩展性、维护性的程序应该包含哪些部分。

  • MVC的主要内容:一个程序应该由三个部分组成

    • M:model(模型):指的是程序处理的数据部分
    • C:Controller(控制器):指的程序的业务代码
    • V:view(视图):展示程序输出的部分。
  • MVC是通用的程序架构思想,不局限于后端项目,也同样适用其他语言编写的程序。

1.3 MVC在后端项目中的体现

  • 目的:将后端Express项目的书写代码和mvc进行关联

  • 组成

    • M:模型(model):指的集合模型相关代码(Schema以及关联部分),并暴露关联集合生成的集合对象
    • C:控制器(Controller):指的是具体处理数据的业务代码(登录、注册、删除、修改)
    • V:视图(view): 指的是路由匹配的部分。指当哪个前端url对应哪个业务代码。
  • 文件划分

    • mvc三个部分的代码都是放在不同的文件中,并且都有文件夹放置。按照mvc模式,可以将程序代码主要划分为三个文件及:

      • models:包含所有集合的模型相关代码,每个集合也是一个独立的js文件
      • controllers:包含所有处理前端数据的业务代码,每一类数据的处理代码都是放在该文件夹下独立的一个js文件
      • routes:包含了所有的路由js文件,里面仅仅包含了路由地址和业务代码的匹配部分(需引入控制器的js文件)
    • 例子: 蜗牛电影系统

      moviesystem10
      --- models
         --- userModel.js
         --- movieModel.js
         --- movieTypeModel.js
         --- actorModel.js
      --- comtrollers
         --- userController.js
         --- movieController.js
         --- actorController.js
      --- routes
         --- movieRoute.js
         --- userRoute.js
         --- movieTypeRoute.js
         --- actorRoute.js
      

二、MVC例子:movieType.js

2.1 MVC优化之前

  • 一个/routes/movieType.js就包含了集合模型代码、业务代码以及路由匹配在内的所有代码

    var express = require(‘express’);
    var router = express.Router();
    const mongoose = require(‘mongoose’);
    const movieTypesSchema = new mongoose.Schema({
        //_id是自动引入并转换name:String
        },{
        //取消_v字段生成versionKey:false
        })
    ​
    let movieTypesModel = mongoose.model(“movieTypesModel”,movieTypesSchema,’movieTypes’);
    //查找所有
    router.get(‘/findall’,async function(req, res, next) {
    let result = await movieTypesModel.find();
    res.send({code:200,message:’查询成功’,data:result})
    });
    ​
    //模糊查询
    router.get(‘/find’,async function(req, res, next) {
    let {name} = req.query;let result = await movieTypesModel.find({    
        name:{$regex:new RegExp(name),$options:"$i"}});
        res.send({code:200,message:'查询成功',data:result})});
    ​
    //添加
    router.get(‘/add’,async function(req, res, next) {
        let {name} = req.query;//先尝试能不能查找到数据,如果查到了,说明已经有该电影类型了
        let result = await movieTypesModel.find({name});if(result.length > 0){    res.send({code:200,message:'添加失败,已有该类型'})}else{    let end = await movieTypesModel.create({name});    res.send({code:200,message:'添加成功'})}
    });
    // 删除
    router.get(‘/delete’,async function(req, res, next) {
        let {_id} = req.query;let {deletedCount} = await movieTypesModel.deleteMany({_id});if(deletedCount > 0){    res.send({code:200,message:'删除成功'})}else{    res.send({code:200,message:'删除失败'})}
      });
    ​
    //修改名称:根据_id来查找
    router.get(‘/update’,async function(req, res, next) {
        let {_id,name} = req.query;//先确定要修改的名称是否已存在,已存在则修改失败
        let arr = await movieTypesModel.find({name});if(arr.length >0 ){    res.send({code:200,message:'修改失败,已有该类型'});    return;}let {modifiedCount} = await movieTypesModel.updateMany({_id},{name});if(modifiedCount > 0){    res.send({code:200,message:'修改成功'})}else{    res.send({code:200,message:'修改失败'})}
        });
    //分页查询
    router.get(“/findByPage”,async function(req,res){
        try {    let {pageNum,pageSize} = req.query;//分页查询// 跳过的数量; (pageNum - 1) * pageSize 
         let result = await movieTypesModel.find().skip((pageNum - 1) * pageSize).limit(pageSize);    res.send({code:200,message:'分页查询成功',data:result})} catch (error) {    console.log('报错来源',error);    //告诉用户参数有问题  
         res.send({code:-1,message:'分页查询失败,参数有误'})}
             })
    ​
    //测试 skip limit Documentcount
    router.get(‘/find2’,async function(req,res){
        //skip// let result = await movieTypesModel.find().skip(5)//limit 获取前三个数据//
        let result = await movieTypesModel.find().limit(3);//返回第二到第五个数据// 
        let result = await movieTypesModel.find().skip(2).limit(2);//查看该集合数据的个数
        let result = await movieTypesModel.countDocuments()res.send({code:200,message:'查询成功',data:result})
       
    ​
    module.exports = router;
        ### 2.2 MVC优化之后- 需要再`models``controllers`以及`routes`新建三个文件  - `models/movieType.js`:包含电影类型的集合模型代码  - `controllers/movieTypeController.js`:包含了处理电影类型的所有业务代码  - `routes/movieTypeRoute.js`:包含了电影类型的所有路由匹配代码- 1.models/movieType.js:  ```js  const mongoose = require('mongoose');  const movieTypesSchema = new mongoose.Schema({      //_id是自动引入并转换      name:String  },{      //取消_v字段生成      versionKey:false  })  //需要暴露生成的集合对象  let movieTypesModel = mongoose.model("movieTypesModel",movieTypesSchema,'movieTypes');  //暴露movieTypesModel  module.exports = movieTypesModel
    
  • 2.controllers/movieTypeController.js:

    const movieTypesModel = require("../models/movieTypeModel");
    //查询所有
    async function findAll (req, res, next) {
        let result = await movieTypesModel.find();
        res.send({code:200,message:'查询成功',data:result})
     }
    //模糊查询
    async function find(req, res, next) {
        let {name} = req.query;
        let result = await movieTypesModel.find({
            name:{$regex:new RegExp(name),$options:"$i"}
        });
        res.send({code:200,message:'查询成功',data:result})
     }
     // 添加
     async function add(req, res, next) {
        let {name} = req.query;
        //先尝试能不能查找到数据,如果查到了,说明已经有该电影类型了
        let result = await movieTypesModel.find({name});
        if(result.length > 0){
            res.send({code:200,message:'添加失败,已有该类型'})
        }else{
            let end = await movieTypesModel.create({name});
            res.send({code:200,message:'添加成功'})
        }
     }
    //修改
    async function update(req, res, next) {
        let {_id,name} = req.query;
        //先确定要修改的名称是否已存在,已存在则修改失败
        let arr = await movieTypesModel.find({name});
        if(arr.length >0 ){
            res.send({code:200,message:'修改失败,已有该类型'});
            return;
        }
        let {modifiedCount} = await movieTypesModel.updateMany({_id},{name});
        if(modifiedCount > 0){
            res.send({code:200,message:'修改成功'})
        }else{
            res.send({code:200,message:'修改失败'})
        }
    }
    //分页查询
    async function findByPage(req,res){
        try {
            let {pageNum,pageSize} = req.query;
        //分页查询
        // 跳过的数量; (pageNum - 1) * pageSize  
            let result = await movieTypesModel.find().skip((pageNum - 1) * pageSize).limit(pageSize);
            res.send({code:200,message:'分页查询成功',data:result})
        } catch (error) {
            console.log('报错来源',error);
            //告诉用户参数有问题
            res.send({code:-1,message:'分页查询失败,参数有误'})
        }
    }
    //删除
    async function deleteType(req, res, next) {
        let {_id} = req.query;
        let {deletedCount} = await movieTypesModel.deleteMany({_id});
        if(deletedCount > 0){
            res.send({code:200,message:'删除成功'})
        }else{
            res.send({code:200,message:'删除失败'})
        }
     }
    //暴露所有函数
    module.exports ={
        find,
        findAll,
        findByPage,
        update,
        add,
        deleteType
    }
    
    • 包含了处理数据的所有函数,并暴露所有函数
  • /routes/movieRoute.js:包含路由地址匹配代码

    var express = require("express");
    var router = express.Router();
    //引入控制器代码:业务代码
    const {
      find,
      findAll,
      findByPage,
      deleteType,
      add,
      update,
    } = require("../controllers/movieTypeController");
    //查找所有
    router.get("/findall", findAll);
    //模糊查询
    router.get("/find", find);
    //添加
    router.get("/add", add);
    // 删除
    router.get("/delete", deleteType);
    //修改名称:根据_id来查找
    router.get("/update", update);
    //分页查询
    router.get("/findByPage", findByPage);
    module.exports = router;
    

2.3 MVC 各文件之间的引入关系