• class10:子路由和MVC模型


    一、ejs文件渲染css样式

    如果要给ejs文件添加css样式,我们自然而然的想到使用外联在ejs文件中引入css文件渲染样式。而实际上这样的做法却不能渲染样式。

    正确做法: 新建与views文件夹(ejs文件所在位置)同级的文件夹静态目录public,在静态目录中建立样式文件的css文件。ejs文件中用link标签引入css样式,用 / + css文件名 引入,其中/表示引入静态文件。

    // index.ejs
    <link rel="stylesheet" href="/index.css">
    
    • 1
    • 2
    // index.css
    body{
        background-color: aquamarine;
    }
    
    • 1
    • 2
    • 3
    • 4

    渲染结果:
    在这里插入图片描述

    注意:静态文件资源要提前配置,views只放置ejs文件。

    二、状态码(无太大用途)

    可以认为的在后端返回数据时设置404状态码,导致输出端显示404错误:

    app.get("/test", (req, res)=>{
        res.status("404");
    })
    
    • 1
    • 2
    • 3

    在这里插入图片描述

    三、重定向(无太大用途)

    重定向,即重新定位路由方向(地址),比如我们访问http://localhost:3000/red,使用重定向使得加载地址时访问百度https://www.baidu.com网址:

    app.get("/red", (req, res)=>{
        res.redirect("https://www.baidu.com");
    })
    
    • 1
    • 2
    • 3

    例:当未找到数据或路由时返回404报错页面

    在静态资源中新建404.html文件,在后端配置(写在最后)未找到路由时跳转到404.html的文件:

    app.use("*", (req, res)=>{
        res.redirect("/404.html")
    })
    
    • 1
    • 2
    • 3

    输入一个错误路由:

    在这里插入图片描述

    自动加载404.html文件:

    在这里插入图片描述

    四、子路由

    我们知道,如果路由请求都放在一个文件中将会很拥挤,维护麻烦。例如我们开发一个淘宝页面,将会包括很多子页面,这些子页面(首页、广场、购物车、我的等)都需要一个子路由,我们可以把子路由放在一个文件夹下。

    新建一个与静态资源文件同级的目录router存放子路由,新建一个home.js文件存放首页的路由地址。

    在home.js中引入子路由所需模块:

    const express = require("express");
    let router = express.Router();
    
    • 1
    • 2

    使用子路由发起请求:

    注意发起请求的名称与模块名赋予的变量一致:

    router.get("/", (req, res) => { 
        res.send("长风破浪会有时,直挂云帆济沧海。")
    });
    
    • 1
    • 2
    • 3

    / 代表根路由,我们要配置的是/home页面,需要在后端主目录app.js中声明:

    配置子路由:

    app.use("/home", require("./router/home"));
    
    • 1

    第一个参数/home代表我们配置的子路由是/home,它对应的js文件所在的位置是:./router/home,即home.js文件。

    所以上面第二个代码块中的根路由/表示的是该配置的子路由:/home

    要引入home.js文件,需要将其导出:

    module.exports = router;
    
    • 1

    总结:app.js中配置子路由/home,通过该子路由可以访问到router文件夹下的home.js文件的数据。

    这样,就可以通过子路由访问数据了:

    在这里插入图片描述

    子路由中添加子路由:

    在子路由的配置文件home.js中添加其他子路由:

    const express = require("express");
    let router = express.Router();
    
    router.get("/", (req, res) => { //  /home
        res.send("长风破浪会有时,直挂云帆济沧海。")
    });
    // http://localhost:8080/home
    
    router.get("/left", (req, res) => {
        res.send("南朝四百八十寺,多少楼台烟雨中。")
    });
    // http://localhost:8080/home/left
    
    router.get("/right", (req, res) => {
        res.send("雄关漫道真如铁,而今迈步从头越。")
    });
    // http://localhost:3000/home/right
    
    module.exports = router;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

    五、实例

    上一课中我们做了一个计算偶数的实例,我们可以先进行优化,当我们输入的数字是第一次计算,那我们就计算它的偶数,并将该数字作为文件名生成txt文件,保存在同目录下的data文件夹中;当我们输入的数字之前已经计算过了,那我们读取对应数字的文件名中的数据直接返回到前端。

    假设前端以post发起请求:

    首先我们要拼接路径

    // 引入path模块
    const path = require("path");
    
    let {value} = req.body;
    // 拼接路径
    let pathNameFile=path.join("./data/"+value+".txt"); // value为前端输入框输入的数字
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    然后判断该数字的文件是否存在

    若存在,直接读取文件数据;

    若不存在,进行计算,并写入文件:

    // 引入fs模块
    const fs = require("fs")
    // 返回一个布尔值  判断文件是否存在
    const bol = fs.existsSync(pathNameFile);
    
    // 有则读取返回数据 没有则写入并计算返回数据
    if(bol){ 
    	// 返回数据
        console.log("文件" + value + "已存在,直接读取...");
        // 绝对路径
    	res.sendFile(path.join(__dirname, pathNameFile));
    }else{ //false 不存在
        console.log("文件" + value + "不存在,开始计算...");
    	let arr = [];
    	for(let i=0;i<=value;i++)
    	{
    		if(i%2==0)
    		{
    			arr.push(i)
    		}
    	}
    	// 写入数据---相对路径
    	fs.writeFile(pathNameFile, JSON.stringify(arr),()=>{
    		res.send(arr);
    	});
    }
    
    • 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

    结果截图:
    在这里插入图片描述

    前端代码:

    <body>
        <input id="txt" type="text" placeholder="请输入数字"> <br/>
        <button id="box">提交</button>
        <ul id="list"></ul>
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
        <script>
            box.onclick = () => {
                axios({
                    method: "post",
                    url: "http://localhost:3000/factor",
                    data: {
                        value: txt.value.trim(),
                    }
                }).then(res => {
                    let html = ""
                    res.data.forEach(item => {
                        html += `
                        
  • ${item}
  • `
    }) list.innerHTML = html console.log(res) }) } </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

    六、MVC模型

    M—模块

    V —页面展示

    C —控制器

    m模块:各种功能封装

    v页面展示:静态文件 views

    c控制器:只设置控制数据

    例:我们对上一节的实例使用MVC模型对其进行分开管理:

    在主目录app.js同级目录下新建controlles文件夹,并新建controle文件:

    我们来看看主目录app.js与分目录controlles.js是怎么交互的:

    // controlles.js文件
    const factorFile=(req, res)=>{
        res.send("落霞与孤鹜齐飞,秋水共长天一色。");
    };
    
    module.exports = {
        factorFile,
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    该controlles.js文件定义了factorFile方法,并返回数据,并将该方法用模块导出。

    // app.js
    const app = express();
    const {factorFile} = require("./controlles/controlles");
    app.post("/factor", factorFile);
    
    • 1
    • 2
    • 3
    • 4

    该app.js引入controlles.js中的方法,该方法是发起请求时的回调函数,使post请求变得完整。

    结果:
    在这里插入图片描述

    modules模块:

    对于controlles.js文件,我们只进行数据操作,其它的数学计算、文件的写入等由module模块负责:

    新建module文件夹,在其中新建math.js文件用于数学计算,再新建pathFie.js文件用于数据写入:

    // math.js
    // 用于计算
    const math = (value)=>{
        let  arr = [];
        for (let i=0;i<=value;i++){
            if (i% 2 ==0){
                arr.push(i)
            }
        }
        return arr
    };
    
    module.exports ={
       math,
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在math.js中,传入一个参数value,即前端输入框输入的数字,并计算它的子偶数存入对象math,并将其导出。

    // pathFile.js
    const fs=require("fs");
    const path =require("path");
    
    // 判断文件是否存在  和 文件的绝对路径
    const bol = (value)=>{
        // 拼接路径
        let pathNameFIle=path.join("./data/"+value+".txt");
        //  返回一个布尔值  判断文件是否存在     fs模块的路径 ./路径是以启动文件的地址为初始
        const bols = fs.existsSync(pathNameFIle);
        // 读取文件的绝对地址
        let dataFile = path.resolve(__dirname,"../"+pathNameFIle)
        // 返回值
        return {
            bols,
            dataFile
        }
    };
    
    // 写入文件函数
    const writePath =(value, dataFile)=>{    
        fs.writeFile(dataFile, JSON.stringify(value),()=>{
    
        });
    };
    
    module.exports={
        bol,
        writePath
    };
    
    • 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

    在pathFie.js中,自定义方法bol,传入参数value,即前端输入框输入的数字,将其作为名称并拼接为完整的相对路径,通过fs的方法判断该条路径是否存在,同时使用path的方法得到绝对路径,因为如果文件不存在要新建文件写入数据时需要用到绝对路径。判断完后返回布尔值(文件是否存在)和绝对路径。需要时调用该方法判断文件是否存在然后进行相应操作。

    然后自定义第二个方法writePath,当文件不存在时调用该方法进行数学计算。

    然后将两个方法都导出,使其它文件可以引入。

    controlles模块:

    其中的controlles.js文件只做对数据的操作,首先引入modules的方法,因为原方法得到的是对象所以我们可以同时进行解构赋值:

    // controlles.js
    const { bol, writePath } = require("../modules/pathFile");  // 判断和写入文件
    const { math } = require("../modules/math");    // 计算数学
    
    • 1
    • 2
    • 3

    自定义方法factorFile 用if-else语句执行相应的方法:

    // controlles.js
    const factorFile = (req, res) => {
        let { value } = req.body;
        let { bols, dataFile } = bol(value);
        //有就读取返回数据,没有就写入并计算返回数据
        if (bols) {
            // 读取地址
            res.sendFile(dataFile)
        } else {
            // 没有就要计算并写入
            let data = math(value);
            writePath(data, dataFile)
            res.send(data)
        }
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    然后将该方法导出,便于主目录app.js调用:

    // controlles.js
    module.exports = {
        factorFile,
    };
    
    • 1
    • 2
    • 3
    • 4

    在主目录app.js中导入modules.js文件:

    const express= require("express");
    const app = express();
    app.listen("8080",()=>{ console.log("8080端口启动")});
    
    app.use(express.static("./public"));  // 设置静态资源文件夹
    app.use(require("cors")());  // 设置跨域
    app.use(express.urlencoded({extend:true}));  // 解析post请求
    app.use(express.json());
    
    // app.js目录--默认导出一个对象 解构赋值
    // 引入controlles中导出的模块
    const {factorFile}  = require("./controlles/controlles.js");  
    app.post("/factor",factorFile);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    views模块:

    // index.html
    <body>
        <input id="txt" type="text" placeholder="请输入数字"> <br/>
        <button id="box">提交</button>
        <ul id="list"></ul>
        <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
        <script>
            box.onclick = () => {
                axios({
                    method: "post",
                    url: "http://localhost:3000/factor",
                    data: {
                        value: txt.value.trim(),
                    }
                }).then(res => {
                    let html = ""
                    res.data.forEach(item => {
                        html += `
                        
  • ${item}
  • `
    }) list.innerHTML = html console.log(res) }) } </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

    结果:

    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 相关阅读:
    电商大促就靠RPA,摆脱重复劳动,急速提效
    ffplay 源码剖析——框架分析
    1829. 每个查询的最大异或值
    SparkCore系列-9、共享变量
    1.AVL树:左右旋-bite
    RabbitMQ:简单模式(Hello World)
    【故障分类】基于注意力机制的卷积神经网络结合双向长短记忆神经网络CNN-BiLSTM-attention实现数据分类附matlab代码
    『Vscode 自定义折叠代码』
    DTSE Tech Talk | 第10期:云会议带你入门音视频世界
    学习ASP.NET Core Blazor编程系列二十五——登录(4)
  • 原文地址:https://blog.csdn.net/qq_51667621/article/details/127129825