express框架rmvp的使用


前言

讲解了用Express框架 搭建了一个简易的rmpv的基本模型,希望这篇博客能够让你对rmvp有更好的了解


一、RMVP是什么?

在这里插入图片描述
mvp的全称为Model-View-Presenter,由mvc的controller变成了Presenter(中间人),Model提供数据,View负责显示,Controller/Presenter负责逻辑的处理,V和M绝不能通信,意味着HTML页面上不能操作数据,同理数据里也不能有模板,他们如果想操作,需要通过controller(Presenter),controller先去数据源Model拿到数据,再去渲染模板,同理模板上有onclick事件 想要修改数据,从V中发起操作给controller,controller再修改数据,这就是MVP模型,一般情况下,前面还有个R,R就是request请求,请求先走controller,controller负责联动view和model,这就是rmvp模型

二、搭建基本服务

1.构建服务器server.js基本组成

const express = require('express')
const app = express() //直接调用即可

const router = require('./router/index')

app.use('/',router)//R也可以理解为路由,引入路由做中间件
/*
中间件可以不给函数,用express的路由来替代中间件,路由是express中间件,称为路由中间件
引入的router是个 Function 中间件是个函数,函数内部做了处理,拿到了req,res,先不用管入参
*/
app.listen(8080,()=>{
    console.log('localhost:8080');
})

2.router文件

	const express = require('express')//加载express 为了从express拿出路由
	//路由中间件
	const router = express.Router()
	//console.log(router);//认为router是函数
	
	//get请求语义 获取数据,从后端拉取数据过来
	//怎么定义的怎么匹配,会自动匹配到对应的路由,发送对应的数据
	router.get("/",(req,res,next)=>{
	    res.send('hello');
	}) 
	router.get('/index',(req,res,next)=>{
	    res.send('index pages');
	})
	module.exports = router
运行结果:证明router是个函数

在这里插入图片描述

	对两个路由进行测试

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

2.1、如何实现数据的获取

在router文件中添加以下内容
GET

如果地址栏输入localhost:8080/idnex?id=2,需要从req中取到数据

	//get请求语义 获取数据,从后端拉取数据过来
router.get('/index',(req,res,next)=>{ //和之前的use不同,这个是怎么定义的怎么匹配,会自动匹配人到对应的路由,发送对应的数据

    //获取get方法再url上传递的数据
    const query = req.query//这个req是被express增强的,所以可以在路由中间件中访问query,访问query以后,可以拿到query对象
    // console.log(query);//{ id: '2' }
    // res.send(query)//可以直接返回,此时返回的就是一个json类型
    res.json(query)//也可以这么返回,这也是返回一个json字符串类型
})//get就是get请求,get里传入两个参数,第一个参数 就是 路径 第二个参数就是一个回调函数,在路径匹配后会执行这个回调函数,执行完成后哪怕不进行res.json(query)进行返回,也不会把访问权交给下个路由,因为下个路由没有匹配

验证是否正确
在这里插入图片描述

POST

需要在server.js导入第三方中间件才能解析,控制台安装body-parser
在这里插入图片描述
在server.js中引入

	//第三方中间件
const bodyParser = require('body-parser')
//这个是用来解析 parse application/x-www-form-urlencoded
//这个配置专门用来收取前端给我发过来的表单数据
app.use(bodyParser.urlencoded({extended:false}))//bodyParser代入 然后调用一个方法,这个方法返回一个中间件
//extended:false表示请求时候的数据的格式问题 bodyParser要不要进行编码解码的问题
//这个定义要放在路由的上面,因为app.use是有顺序的,next给路由,路由才能拿到数据
//这个是用来解析 parse application/json
app.use(bodyParser.json())//可以解析JSON字符串

然后在router中进行post请求

	    //post请求语义 添加数据
    router.post('/index',(req,res,next)=>{
        const data = req.body
        //因为get是通过Query String方式传给后端,后端可以通过query方式来取,但是现在post是通过表单数据方式application/x-www-form-urlencoded方式传送,后端不能通过query,只能通过body方式来取
        // console.log(data);//此时data是undefined因为缺少第三方中间件boby-parser(解析node.js body的中间件)
        //有了插件后 就能正确输出前端发送过来的数据
        res.send(data)
    })

在这里插入图片描述
结果正确

PUT
	    // 修改数据  put表示覆盖式修改 大量修改字段 比如 四个字段 修改三个字段 或者全部修改 直接覆盖
    router.put('/index',(req,res,next)=>{
        const data = req.body
        console.log(data);
        //{ username: 'adimin', password: '123' }
        //PUT方式也和PSOT一样能通过body拿数据

        res.send('put response')
    })

在这里插入图片描述

PATCH
	    //修改数据 patch表示增量式修改,选择式修改
    // 如果 只想修改小部分字段,比如只修改一个,那么用patch 只修改一个 类似于补丁逻辑
    router.patch('/index',(req,res,next)=>{   
        res.send('patch response')
    })

在这里插入图片描述

DELETE
	    //删除数据
    router.delete('/index',(req,res,next)=>{
        res.send('delete response')
    })

在这里插入图片描述

2.2 如果想要不区分请求方式,一律接收

	将上面的各种方式全部注释后,在router文件中书写一下代码,
	无论什么请求方式的请求都不会报404
	但是这样语义会更加不清晰
    router.all('/index',(req,res,next)=>{//无论是get还是post都能请求得到,不报404
        //all 判断的话 需要在req,res试图拿到前端给我的是get还是Post
        res.send('hello')
    })

2.3 做rmvp的抽离,抽离controller

创建一个controller文件

	const list =  (req,res,next) =>{//get请求的控制器
		res.send('hello')
	}
	exports.list= list;

在router中导入

	const { list } = require('../controller')//index.js可以省略
	router.get("/",list)

在这里插入图片描述
测试通过

三、渲染

知识补充

做一个网页可以采用很多种方法架构系统,前后端分离式的架构,和前后端不分离式的架构

需求,现在做一个网页,追求两点,追求最大的速度,第二点追求最好的管理效率(代码的管理效率),这两点矛盾,如果想让代码管理更方便就要拆代码,前后端分离,如果想让页面下载更快访问更快,就要服务端渲染,服务端直接返还页面给前端,前端什么也不需要做,只需要帮助后端做个摸板

前端请求静态资源目录(快)[模板放到后端]

最快的方式,后端直接把静态页面给前端

在这里插入图片描述

第二快的方式,
前端往后端请求数据,但是请求的不是html/css /js请求的式/api/内容

如果向后端请求这样的内容,静态资源里就没有这样的资源,后端需要递交给node,node需要解析路径,执行中间件,最后返回一个页面 res.send(),才能把数据返回给浏览器

在这里插入图片描述
这样服务端 直接把信息给浏览器,但这样的话前端工作较少,这样的模式 将来会难以维护,全部交给后端,前端只是写完页面抛给后端,但是这种方式却有比较好的优点,就是快

前后端分离 (慢) [模板放到前端]

前端请求后端数据的时候,不是以html/css/js直接给前端的方式,而是请求一个接口,后端返回的不是一个具体的html,而是一个json,虽然json在浏览器上也能给用户看,但是看不懂,所以要解析json成一个网页,这种工作都要前端来做,这样就做成了前后端分离,好处就是前端和后端各,而且可以同时进行,之前的方式 不能同时进行,需要前端把页面做好后,丢给后端才能做,因为后端返回的是一个页面 而不是接口

在这里插入图片描述
如果后端返回html ,但是后端需要把数据拿过来渲染摸板,这个摸板出在后端,同理如果后端返回一个JSON给前端 ,前端也需要把JSON放到一个模板里,这个摸板可能是html,但是如果用html需要模板字符串,把变量算出来塞到html 做html拼接

SSR (Server Side Render)

要把纯网页返给前端,需要一个放置静态资源目录的文件夹,里面都是静态资源
在这里插入图片描述

利用expresss 内置的中间件托管静态文件 express.static
express相当于给前端提供了静态资源服务,但是这是静态的
里面只有html/css/js,双击html就能启动服务

第一种方法纯静态资源目录

在server.js文件中书写

	//静态资源服务中间件(内置中间件)
app.use(express.static('./public'))//利用expresss 内置的中间件托管静态文件

开启服务
在这里插入图片描述
服务可以开启,自动跳转静态目录页面上的Index.html

第二种前端请求后端资源

前端请求后代一个接口,后端就会给前端返回一个资源,
请求的这个接口可以通过a链接

在index.html中添加a标签

	<a href="/api/list">获取list</a>

当我点击会跳转到一个新页面,里面什么都没有,因为当前静态资源目录根本没有 /api这个文件夹,也没有/list这个文件或者资源,所以就挂了,但是这个/api/list 一定会被express拦截下来,其实静态资源目录是express帮助搭建的服务,意味着请求的每一个资源都是express帮助递过来,但是当我请求/api/list资源express还要递,express递不了,因为静态资源没有,接口也没有,所以要做一个接口

在router文件中定义,此时页面能跳转到并接受controller返回的内容

	router.get("/api/list",list)

如果在页面上显示100个li

const list =  (req,res,next) =>{
	let data = '<ul>'
    for(var i=0;i<100;i++){
        data += `<li>line${i}</li>`
    }
    data += '</ul>'
    res.send(data)
}

页面正确显示数据
在这里插入图片描述
这样渲染数据 比 静态资源稍慢一点,需要在后端运行下js返回给前端,对于前端来说 还是后端给我的,这种现象就叫做服务端渲染(服务端渲染的页面给前端)
在在渲染页面上查看源代码,能看到服务端给我的代码,爬虫能爬到
如果后端返回给前端的是一个JSONP接口,用ajax请求,然后在前端自己用ul li渲染,这叫前端渲染,客户端渲染


CSR (Client Side Render)

当静态页面满足不了需求,后端用程序渲染一段字符串返给前端,后端还能把HTML渲染给前端,直接把HTML做成一个file读取一下,然后返回给前端

	再次调用list 客服端渲染,需要换一个方式返回数据 
	后端只返回一个line1 line2 的结构化数据
	需要重写controller文件 核心内容
	let data = '{"ret":true,"data":['//后端只发送数据,需要结构化
    for(var i=0;i<100;i++){
        data += `"line${i}",`
    }
    data +=']}'
    res.send(data)
    //两种方式都可以
------------------------------------------
    let dataObj = {
        ret:true,
        data:[]
    }
    for(var i=0;i<100;i++){
        dataObj.data.push('line'+i)
    }
    res.send(dataObj)//返给前端JSON字符串

前端拿到数据JSON字符串
在这里插入图片描述
前端在静态资源里面的JS中 解析字符串,在Index.html引入jquery标签,然后增加存放数据的div

	<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
	<script src="./scripts/common.js"></script>
    <link rel="stylesheet" href="./styles/reset.css">
	<body>
    hello world.
	    <img src="./images/1.jpg" alt="">
	    <a href="/api/list">获取list</a>
	    <div id="list"></div>
	</body>

然后在静态资源中的JS书写以下代码

	$.ajax({//jQuery ajax
    url:'/api/list',//传给后端的地址
    success(result){
        console.log(result);
        let html = '<ul>'
        $.each(result.data,(index,value)=>{
            html += '<li>'+value+'</li>'
         })
        html += '</ul>'
        $('#list').html(html)//html是Jquery方法 把一段Html装载到页面上
    }
})

3.1渲染模板

在根目录创建新的文件夹view 作为模板文件夹使用,利用art-remplate模板引擎

安装art-template

在这里插入图片描述

载入art-template

后端模板

在server文件中 引入

	//后端 view engine setup view模板引擎设置
app.engine('art', require('express-art-template'));
app.set('view options', {//注意这个view options 官网是view 估计官网笔误
    debug: process.env.NODE_ENV !== 'production',
    escape:false
});
app.set('views', path.join(__dirname, './view'));
app.set('view engine', 'art');

在刚刚创建好的view文件夹中 创建list.art,因为配置引擎的时候 写了art,表示set了 view engine 扩展名是art

在list.art中写以下内容,这是字符串拼接的不是对象

{
    "ret":true,
    "data":{{data}}
}

因为是后端模板引擎,所以在controller文件中,先注释掉之前的,写入以下内容

	 let dataArray = []

    for(var i=0;i<100;i++){
        dataArray.push('line '+i)
    }
     //需要修改首部格式
    res.set('content-type','application/json;charset=utf-8')
    //安装渲染引擎后,就可以不用res.send 用res.render
    res.render('list',{
       data:JSON.stringify(dataArray) 
    })//art-template 帮助定义了render方法
   //第一个参数只用写文件名,不用写目录
   //第二个参数 写渲染的数据 是一个对象

前端能看到后端发来的数据
在这里插入图片描述

前端模板

需要从art-template官网 把template-web.js下载 下来,然后放到Public中的JS文件夹下,拿到后 导入到index.html中,导入完成后,在JS文件夹中新建一个list.art文件写入以下内容

	<div>{{data}}<div>

然后在public的JS文件中 用模板来代替之前的渲染工作

	$.ajax({//jQuery ajax
    url:'/api/list',//传给后端的地址
    success(result){
        //前端模板
        let templateStr = `
        <ul>
            {{each data}}
            <li>{{$value}}</li>
            {{/each}}
        </ul>
        <div>
            <b>{{x}}</b>
        </div>
    ` 

        let html= template.render(templateStr,{
            data:result.data,
            x:'hello'
        })


        $('#list').html(html)//html是Jquery方法 把一段Html装载到页面上
        
    }
})

页面正常渲染
在这里插入图片描述

后端直接返回页面给前端

修改controller文件 ,把上面的修改首部格式注释,不然整个页面被浏览器解析程JSON字符串,更换controller文件中res.render方式

	res.render('list-html',{
        data:dataArray
    })

在view文件夹中 创建一个list-html.art文件
这个文件是一个html页面

    <!-- 有index.js传过来的数组,需要循环渲染数组 -->
    <ul>
        {{each data}}
        <li>{{$value}}</li>
        {{/each}}
    </ul>

渲染完成
在这里插入图片描述
后端通过node.js已经把页面渲染完后到前端已经传新的页面,不过还不够快,最快的是把这个结果再生成一个HTML页面,因为前端访问这个接口,后端还要运行一段JS,最后返回结果,这个JS可能要读取数据库库,访问一段时间,最后生成一个字符串,然后返给前端,中间有延迟

后端直接返回生成的页面

更改controller文件

	 //如果后端想渲染一个页面的话,需要把它渲染成静态资源目录,不能用render方法,因为直接返回出去,不能生成页面
    //需要拿到模板对象,渲染模板

    var fs = require('fs')
    var path = require('path')
    var template = require('art-template'); 
  
    var html = template(path.join(__dirname,'../view/list-html.art'),{ //这里不能路径解析不能直接写'../view/list-html.art'
        data:dataArray
    });
    // console.log(html);
    fs.writeFileSync(path.join(__dirname,'../public/list.html'),html)
    //自动生成了 list.html 也就是作者或者编辑人员,做文章发布,点个按钮 编辑发布,静态资源在public目录下,当用户想访问时,直接地址栏输入list.html 就可以运行
    res.send("pages has been compiled.")

页面访问时 就会生成list.html,这就是cms网站的原型
在这里插入图片描述
在这里插入图片描述

四、模型

根目录创建一个新的文件夹model,创建一个list.js

	let dataArray = []

	for(var i=0;i<1000;i++){
	    dataArray.push('line' + i)
	}
	
	module.exports={
	    dataArray
	}

controller只管拿到模板,拿到数据进行装填
引入listModel

	var fs = require('fs')
    var path = require('path')
    var template = require('art-template'); 
    
    const listModel = require('../model/list')

    var html = template(path.join(__dirname,'../view/list-html.art'),{ 
        // data:dataArray
        //当使用model中的数据时
        data:listModel.dataArray

    });
    // console.log(html);
    fs.writeFileSync(path.join(__dirname,'../public/list.html'),html)
   
   
    res.send("pages has been compiled.")

该处使用的url网络请求的数据。


总结

以上就是今天要讲的内容,本文仅仅简单介绍了express框架rmvp的使用,数据库部分需要大家自己去参考mongodb资料,连接即可,希望能帮助到你

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值