4、页面静态化

为什么要进行页面静态化?
从搜索功能来看,搜索出来的列表数据是固定的50条数据,详情页面的访问量是搜索的30多倍,如果用户访问量有百万级别,那就不能频繁渲染页面和
访问数据库查数据了,此时就需要将我们的前端和服务端请求,都通过Nginx做反向代理。
我们项目基于这两个点来解决的,方案是使用的模板引擎技术,当用户首次访问时候,我们使用Freemarker技术生成静态页面响应给用户,同时放到Nginx指定的代理目录下,再次访问时候直接从Nginx代理目录下查找进行响应
线上时候还会采用CDN技术,同时指向Nginx代理的静态页面的路径,来提高用户的访问速度
页面静态化会造成一个问题:数据库数据改变后需要怎么进行同步页面,我们采用RabbitMQ做异步处理,修改后通过MQ发送消息,服务端收到消息后会发送消息重新生成一个html页面,跟数据库进行同步

Freemarker

Freemarker是一个用Java开发的模板引擎,用来生成输出文本的工具
模板+数据模型=输出

1、数据模型

基本类型、List、Map、Pojo等复杂类型。
工作原理:

pom中添加freemarker跟common-io依赖
yml文件中配置freemarker
后台拼接完数据后返回模板文件名称(test)
例如:return "test1";,访问该controller,会访问test1.ftl页面自动填充数据

代码实现:
使用freemarker中的Configuration类获取到模板文件,接口获取到数据模型map,然后利用

String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);

将数据静态化,然后利用common-io包中的IOUtils将HTML数据文件输出即可

指令:

1、注释:<#‐‐和‐‐>
2、取值:即${内容}部分
3、FTL指令:
循环:名字前加#予以区分,例如:<#list stus as stu>遍历该集合
_index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始,例如:${stu_index + 1}
判断:if判断,例如:<#if stu.name =='小明'>style="background:red;"</#if>
空值处理:
判断某变量是否存在:<#if stus??> 如果该变量存在返回true,否则返回false
${name!''}表示如果name为空显示空字符串。
内建函数:
日期格式化:
显示年月日: ${today?date}
显示时分秒:${today?time}
显示日期+时间:${today?datetime}
自定义格式化: ${today?string("yyyy年MM月")}

具体代码:
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
<#--取值-->
Hello ${name}!
<br/>
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#--遍历list集合stus-->
    <#list stus as stu>
        <tr>
            <#--_index:得到循环的下标,从0开始-->
            <td>${stu_index + 1}</td>
            <td <#if stu.name =='小明'>style="background:red;"</#if>>${stu.name}</td>
            <td>${stu.age}</td>
            <td>${stu.mondy}</td>
        </tr>
    </#list>

</table>
<br/><br/>
输出stu1的学生信息:<br/>
<#--输出map集合stuMap中的stu1内容-->
姓名:${stuMap['stu1'].name}<br/>
年龄:${stuMap['stu1'].age}<br/>
输出stu1的学生信息:<br/>
<#--遍历对象stu1-->
姓名:${stu1.name}<br/>
年龄:${stu1.age}<br/>
遍历输出两个学生信息:<br/>
<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
<#--遍历map集合stuMap-->
<#list stuMap?keys as k>
<tr>
    <td>${k_index + 1}</td>
    <td>${stuMap[k].name}</td>
    <td>${stuMap[k].age}</td>
    <td>${stuMap[k].mondy}</td>
</tr>
</#list>
</table>
</br>
<table>
    <tr>
        <td>姓名</td>
        <td>年龄</td>
        <td>出生日期</td>
        <td>钱包</td>
        <td>最好的朋友</td>
        <td>朋友个数</td>
        <td>朋友列表</td>
    </tr>
    <#--判断某变量是否存在使用“??-->
    <#if stus??>
        <#list stus as stu>
        <tr>
            <#--给变量设置默认值使用 “!”,当变量为空时显示默认值。-->
            <td>${stu.name!''}</td>
            <td>${stu.age}</td>
            <td>${(stu.birthday?date)!''}</td>
            <td>${stu.mondy}</td>
            <#--如果stu或bestFriend或name为空默认显示空字符串。-->
            <td>${(stu.bestFriend.name)!''}</td>
            <#--查询某个集合的大小-->
            <td>${(stu.friends?size)!0}</td>
            <td>
                <#if stu.friends??>
                <#list stu.friends as firend>
                    ${firend.name!''}<br/>
                </#list>
                </#if>
            </td>
        </tr>
        </#list>
    </#if>

</table>
<br/>
<#--将json字符串text转成对象data-->
<#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
<#assign data=text?eval />
开户行:${data.bank} 账号:${data.account}
</body>
</html>

代码效果:
在这里插入图片描述

项目运用

模板信息存储在MongoDB数据库,模板文件存储在GridFS文件系统中
需求:cms系统为了实现快速根据用户需求修改页面内容并上线的需求
以前:之前都是由开发者人工编写html及JS文件,CMS系统是通过程序自动化对页面内容进行修改,通过页面静态化技术生成html页面
如何实现:一个页面等于模板加数据,在添加页面的时候我们选择了页面的模板
具体流程:

1、获取模型数据,先知道数据模型的结构才可以编写模板
2、制作模板
3、将模型和模板组成的页面进行静态化
4、将静态化生成的html页面存放文件系统GridFS中
5、将存放在文件系统中的html文件发布到服务器

如何获取页面的数据模型?

在编辑页面信息时指定一个DataUrl,此url基于Http方式,cms通过Http远程调用的方法请求DataUrl获取数据模型
此页面是轮播图页面,它的DataUrl由开发轮播图管理的前端来提供
DataUrl就是一个请求后端数据的接口,该接口查询数据库获取数据模型
页面静态化流程:

1、静态化程序首先读取页面获取DataUrl
2、静态化程序远程请求DataUrl得到数据模型
3、获取页面模板
4、执行页面静态化

DataUrl:
"dataUrl" : "http://localhost:31001/cms/config/getmodel/5a791725dd573c3574ee333f"

为什么要使用远程请求?

前端是使用ajax去请求接口,后端不同模块之间的调用就会使用到远程调用
远程请求接口:
使用OkHttpClient完成http请求
具体流程:

1、pom中添加okhttp依赖
2、在SpringBoot启动类中配置 RestTemplate
3、调用RestTemplate的getForEntity方法即可请求url获取参数

ResponseEntity<Map> forEntity = restTemplate.getForEntity
("http://localhost:31001/cms/config/get/5a791725dd573c3574ee333f", Map.class);

GridFS介绍

GridFS是MongoDB提供的用于持久化存储文件的模块,CMS使用MongoDB存储数据,使用GridFS可以快速集成开发
工作原理:

GridFS存储文件是将文件分块存储,文件会按照256KB的大小分割成多个块进行存储
GridFS使用两个集合(collection)存储文件,一个集合是chunks, 用于存储文件的二进制数据
一个集合是files,用于存储文件的元数据信息(文件名称、块大小、上传时间等信息)

1、存文件

通过文件输入流读取到该文件
然后使用GridFsTemplate的store方法存储文件

ObjectId objectId = gridFsTemplate.store(fileInputStream, "index_banner.ftl");
存储原理说明:

文件存储成功得到一个文件id
此文件id是fs.files集合中的主键
可以通过文件id查询fs.chunks表中的记录,得到文件的内容

2、读取文件

定义Mongodb的配置类MongoConfig
使用GridFsTemplate中findOne获取到该文件内容
使用GridFSBucket中openDownloadStream获取流对象数据

3、删除文件

通过主键id使用GridFsTemplate中delete删除文件

整个页面静态化的流程:

1、在编辑cms页面信息界面填写DataUrl,将此字段保存到cms_page集合中
2、静态化程序获取页面的DataUrl—通过pageId获取到该DataUrl字段
3、静态化程序远程请求DataUrl获取数据模型
4、静态化程序获取页面的模板信息
5、执行页面静态

通过id到cmsPage表中找到DataUrl字段
通过restTemplate请求dataUrl获取数据
通过id到cmsPage表中找到TemplateId字段
通过TemplateId到CmsTemplate表中找到模板文件TemplateFileId字段
通过TemplateFileId到fs.files表获取到模板文件
通过generateHtml方法执行静态化
其中重要的方法:String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, model);,传模板文件和模板数据
最后将该方法返回的结果返回;

页面预览开发:

页面在发布前增加页面预览的步骤,方便用户检查页面内容是否正确
页面预览流程:

1、用户进入cms前端,点击“页面预览”在浏览器请求cms页面预览链接
2、cms根据页面id查询DataUrl并远程请求DataUrl获取数据模型
3、cms根据页面id查询页面模板内容
4、cms执行页面静态化
5、cms将静态化内容响应给浏览器
6、在浏览器展示页面内容,实现页面预览的功能

环境配置:
1、pom中引入freemarker依赖
2、在application.yml中配置freemarker
创建CmsPagePreviewController类,用于页面预览;
将静态化后的数据输出到浏览器:

ServletOutputStream outputStream = response.getOutputStream(); 
outputStream.write(pageHtml.getBytes("utf‐8"));
通过nginx代理进行页面预览:

1、虚拟主机配置:

#页面预览 
location /cms/preview/{ 
	proxy_pass http://cms_server_pool/cms/preview/; 
}

2、配置cms_server_pool将请求转发到cms:

#cms页面预览 
upstream cms_server_pool{ 
	server 127.0.0.1:31001 weight=10; 
}

重启Nginx
从cms_page找一个页面进行测试。注意:页面配置一定要正确,需设置正确的模板id和dataUrl。 在浏览器打开:http://www.xuecheng.com/cms/preview/5a795ac7dd573c04508f3a56 5a795ac7dd573c04508f3a56:轮播图页面的id
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rsun04551

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值