第九章 Freemarker 详情页数据静态化
Freemarker 语法
文章静态化技术 与 Freemarker
进阶篇!开启!
1 什么是静态页面技术?
详情页现在还是 html 格式的。我们这个页面现在是“动态页面”。当前页面中的标题,内容这些,都要是发送请求到后端进行获取,返回以后才显示在页面上的。
如果是静态页面的话,【不需要经过后端请求】就能打开。对于一些 媒体网站,电商商品详情页一般都会采用静态化技术
2 静态化优势
SEO的意思是“可以被搜索引擎收录”,那么搜索时被查询到的概率就更高(这块理论自己去补补);
加速用户访问:因为能最先展示文章的主体部分,这些部分不会经过后端发送啥的.
降低数据库压力:降低了数据查询压力.
3 模板引擎技术 实现 静态化
我们使用 Freemarker,比 Thymeleaf 兼容更多的技术栈.
Thymeleaf 是 springboot 官方推荐的模板引擎。
FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个Java类库,是一款程序员可以嵌入他们所开发产品的组件。
模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言, 不是 像PHP那样成熟的编程语言。 那就意味着要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,你可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。
4 页面静态化的过程
模板需要对应的文件:*.ftl。这个的话需要通过 yml 文件进行配置。
还需要一些动态数据,这些数据需要从redis,mongodb中得到。这些数据放入模板类中。
最终,通过 freemarker 结合这两部分,“把动态数据生成到 ftl 中去”,从而形成“静态的html”,此时不再包含动态数据。
之后可以先看看示例代码怎么操作的。当然最后主要还是应用到 详情页。
5 Freemarker官方站点
创建并显示模板ftl:基于Freemarker写一下基本配置和 hello world。
一、引入相关依赖
选择2.2.5 release(和springboot版本匹配)
版本号(顶级工程中)
依赖(放在article模块)
下载依赖:
二、模板页创建与配置
(1)创建
article 中 resources 中新建一个包 templates(叫这个主要是后面yml中配置路径时不用自己改了),里面创建模板文件:
模板页本质和html差不多。
(2)页面框架
(3)介绍 freemarker 语法构成
<#—这种就是注释.
(具体见下图注释)
(4)yml文件中配置 freemarker
在spring下面配置:44-48
字符集utf-8.
内容类型默认是 text/html
后缀默认是ftlh,我们设置成 .ftl
模板加载路径:(这个路径点击进入查看源码时得到,这也解释了之前resources里为啥包名叫这个)
三、模板页测试
1 编写测试方法:当前项目搞一个controller,作为测试:(注释如图)
路由地址我们假设为 free(@RequestMapping注解中),访问路径 /hello。
方法返回“模板页的路径地址”,所以是string类型,return只要是模板也的前缀即可,后缀我们刚才配置过了。
数据要绑定到 model 才能在前端渲染,暂时理解为request。model中属性名称得和模板也中表达式名称对应:模板页是there,所以 model这里也是there。
2 测试(11:50)
(1)如图输入路径:localhost:8001/free/hello
结果不是 “慕课网….”,而是stu、
原因在于使用了注解 @RestController。该注解作用下,给前端回传的都是字符串,我们方法返回的 路径 它搜不到,它直接给搞成 json 返回给前端了。(其实没太懂)
把8行这个注解改成 @Controller 即可。
(2)重测:
==>注意:当前输出的渲染是在“服务端”进行的,并没有输出html。这块后面再深入。
输出对象
上节课是“字符串在模板页中的展示”。
本节课学习“对象在模板页的展示”。
1 创建参与测试的类
老师实现放了两个类在model的pojo包中:spouse 和 stu
spouse是stu的属性,“配偶”的意思
2 对象 构建入 model 中.
controller类
重新写个测试方法,这个方法就是负责给stu类把属性都设置好。
写好这个类后,在/hello方法中调用,这样就能把信息都存进model。
3 模板页构建好
你要是把类已经放入了model中,这里 .属性 时就会弹出提示框。
写好后如下:
4 测试1
(1)报错1:日期类型有点问题
修改,进行日期类型转换:通过一个?来串联一个formate来格式化,25行
重测:
(2)错误2:已育信息有点问题,boolean类型的.
还是类型转化问题.
修改如下:这里 是 否 yes no 都行
重测:
(3)测试输出嵌套的对象:
28补充
测试:(已于这里是老师改成false了)
输出list和map
本节课继续学习 freemarker 语法。
之前输出了 字符串 和 对象.
本节开始学循环输出 list/map
1 Stu类中构建list和map
如下18 19,写完了生成一下get set
2 controller 中填充 list 和 map.
这个方法存3个list:
这个方法存3个map:
调用这俩方法:47 48
3 模板页中输出:
输出时,利用到循环指令,如下:
循环中还可以写一些文本标签;
list标签中article是别名.
map的话,key都不同,我们要先得到key,所以map标签里通过 ?keys as key 的方式得到 key 命名别名。然后输出的时候按图中格式放入key,就可以输出对应的value了。
4 测试(8:00)
指令 if
1 编写模板页输出内容
(1)判断与某个字符串关系时
用 单引号.
(2)与integer.
设置的值还是用之前的:
(3)与booean值
(4)与对象
之前都是判断基本属性,这里拿一个“属性类spouse”来判断.
84行.
??代表“判空”.
2 测试
(1)测试(1/2)
(结果在最下面)
(2)测试(3)
最下边
(3)测试(4)
页面静态化
示例:结合动态数据生成静态html(代码见老师笔记)
根据之前的内容,freemarker的基本语法 算是都演示过了。
本节课的话,主要是演示本章第1节提到的:【模板+动态数据,通过freemarker生成静态html】.
我们数据就基于stu这个类,模板也是之前用的stu的那个。
1 构建freemarker生成文件的位置
(1)配置文件中
去yml文件中写:76-78。
对于win系统,这里要写盘符:盘符:/路径
(??没像之前一样配置路径??)
(2)controller中
18-19:通过 @Value注解 把路径的值传进去.
(这3级的关系就是yml中配置的关系。???后面了解下怎么通过这个注解读到yml属性的吧?)
2 编写文件生成方法
返回一个ok,意思是在页面上提示一下生成成功即可。
这个返回和前几节返回模板路径的意思不同的。
(1)环境配置
Contuguration 是 freemarker 包下的.
具体如下:class里的 / 代表根目录。
32行的这个路径就是我们之前提到的win中要单独写的路径(??win的话是不是写法在这不一样啊???)
32这里形参要求是File.
写完了测试一下:
34 35这sout一下,输出如下:测试完了注释掉.
(2)得到现有ftl文件
(3)动态数据获取
model就调用咱们刚才写的makemodel方法模拟从数据库写入数据了.
然后这里要在方法里补充一下这个model形参,之前没有写。
3 融合,生成html
这里就要用到我们在 1 (2)中写的 freemaker文件生成的位置 这个属性了(23行)
步骤如下:47-54
上来先判断下存在不。htmlTarget就是本节一开始写的 生成路径.
out是一个输出流,形参用 路径+文件名+后缀 拼接,然后通过process生成文件。生成后记得把这个 writer流关掉。
(java输入输出还不是很熟啊,后面复习一下!!)
4 测试(12:20)
(1)报错1:
这里就可以看到41的uft-8写错了,写成uft-8了.
(2)报错2:
这里说了模板页16行有问题.
因为controller方法是我们新写的,所以there没在当前方法赋值.
在当前方法也赋值即可
(3)错误3
ok了
有输出,但是文件有点问题,我们想让它在html这个文件夹下创建,结果因为这里少写了了 / 导致识别目录失败,直接拼接了。
改错如下:52这里加个File.separator,根据OS加 \或者/.
(4)重测
目录对了
双击打开:和之前一样.
打开看看代码:之前写的表达式都没有了
获得tlf:改写详情页为模板tlf
之前都是演示,本节课开始实操。
咱们主要静态化“文章详情”页面.
之前还是用 文章 id 动态访问的,后面我们直接把这个 id 作为静态文件的名字拼接串之一.
现在呢,最主要的是“修改页面中的数据”
一、修改前端页面:如何把 动态页面 改成 模板页?
1 修改路径
(自己不想做前端,可以直接把老师i的前端文件拷贝到自己tomcat配置的地方)
==>不对,【现在不是放在tomcat】!现在是放到老师这写的这个a文件夹,这个路径本节后面写方法的时候涉及到了,看后面的。tomcat的事情后面再说!!
专门创建一个文件夹a,代表article,赋值一个 detail.html 进来,修改这个。
因为detail.html的路径变了,所以里面 js css 相应url位置也得修改!
老师已经改完了,过一遍:
①cs和js的路径
9-14注释掉,改成16-28
下图同理.
② 图片路径:例如 48 49
如下
③ 修改完测试一下
输入如下url:
2 修改为模板
(1)赋值文件到项目中
复制这个.
复制到我们前几节课测试用的地方:顺便后缀改成 ftl
(2)修改页面中内容:
articleDetail是原来动态页面中一个用来保存信息的重要对象,可以去之前基础篇的前端页面查看。我们动态信息就用这个获取.
① titile 改成表达式
38
② 重新获取 页面 id
285-288注释掉.
不再需要通过url路径获取articleId。之后id直接作为文件名。我们重新获取,如下:这里getPageName在原detail 188行,用来获得页面名称。
290-294
③ 涉及 articleDetail 的都改改,用 ctrl+f 一个个去找.(9:50)
…
至此,模板基本改好
后面拿到动态的文章数据,和这个模板议结合,就可以生成静态页面了。
最后生成的html放到如下位置即可:
==>老师建议直接拷贝他的,减少我们改这个的失误率,毕竟涉及前端.
获得动态数据:文章详情ftl生成静态页面
之前提到了:生成静态页面需要 “模板页(上节课)” + “动态数据”。本节课就获取“动态数据”,并且输出静态页面.
当然,文章两种发布形式:自动审核后发布 + 手动审核后发布。
本节处理:手动审核后发布
自动审核 我们之前注释掉了,后面再说怎么弄。
————————————————————————-
1 配置 静态页面“生成位置”
(1)配置文件
老师这里可以拷贝路径,win好像上面能拷贝.
我们新增一个节点即可,就按上节课选的那个a文件夹就行.
定义好后,目录如下:
(2)controller中 定义 生成方法
① 跟之前例子一样,写一个属性,用@Value获取配置中的生成路径。
155 156
② 静态化文件方法1:拷贝之前例子中方法,修改第一波
首先,不需要返回值了,return也删掉。之前写返回值纯粹为了测试。
形参不用model了,用文章id作为形参即可.
方法名改了.
171 文件名改改,是deatil不是stu。
③ 静态化文件方法2: 编写远程调用代码
根据文章id获取文章详情的方法,不再当前controller中。去ArticlePortalController中去找detail方法。
其中的VO的数据我们需要拿到页面中渲染.、
现在有个问题:我们“不能在当前controller直接调用 当前工程中 另外一个controller”,除非是一个 重定向(??复习?)。
==>即使在同一个服务中,我们也应该“发起一个http请求,获取另一个controller的方法”。
如下:基本和之前写的远程调用一致,找一个复制过来改改(6:10).
(restTemplate得去BaseController中把private改成public)
191-204
④ 静态化文件方法3: 通过远程调用,调用另一个controller的方法detail()——根据文章id得到文章详情
调用方法,进行相应修改。(小细节挺多,看不懂来再回来听)
(3)controller中 调用 生成方法
① 确定方法的业务位置.
打开articleController,有个doReview方法.
这个是admin调用的接口(复习一下业务逻辑).
134 135 这里,如果“审核成功”的话,就该生成静态页面了!(whywhywhy!复习下业务)
??是审核完就可以发布文章,所以需要生成文件,然后把文件发出去的意思???
② 调用(2)中写好的controller方法:
2 测试(11:00)
得去审核通过一篇文章才能执行方法.
(1)报错1:
没生成文件.
发现:序列化有问题
修改:VO这里15行
重测:重新写一个文章并审核.
成功:
(2)
拷贝这个(就是文章id):
直接输入如下:即直接动态显示!
这就是渲染出来的 静态页面。
看看生成文件的前端:
(3)错误3:无法跳转
页面左侧这里点击作家名字没跳转。
修改:修改生成的静态文件:384这里需要加 ../。
因为url发生了变化,所以跳转的时候这要改改.
当然,改生成文件没啥用,我们改生成方法:
348行,生成的时候就加上.
3 其他细节.
(1)页面是静态部分,但是【评论是动态的,我们没有静态化!】
(??这里第一次还是挺难接受的,怎么一部分静态一部分动态??)
还是可以发表评论
(2)
当然,文章两种发布形式:自动审核后发布 + 手动审核后发布。
本节处理:手动审核后发布
之前把 自动审核注释了,所以目前所有文章必须手动审核。下节课去改。
==>意思是“自动审核”部分这块内容自己写嘛???
文章阅读量单独获取并展示
1 问题分析
(1)什么问题?
页面左上这里有个“阅读量”,一直是0,这节课处理一下。
其实redis中是有数据的:
生成的文件中,阅读量这里应该要动态生成,而不是让freemarker生成静态的。
(2)怎么造成的?怎么解决
阅读数本来在detail接口动态获取,静态化以后不会被动态调用了,静态化以后这块数据就写死了。
评论区能动态是因为评论区部分没有静态化。
==> 247-248这两行代码要提取出来,做一个单独的接口!
2 代码编写
(1)创建controller接口:51
这里定义的时候不像之前定义grid了,返回integer即可
(2)实现类controller
就拿之前247/248几行复制过来即可.
3 修改前端页面
(1)现在已经生成的html接口改一下,测试接口方法是否正确
(一串前端的东西,不懂)
82行:
266增加一行:默认为0.(什么动态绑定啥的,都忘了)
写一个方法:349开始
299加上这个方法调用,别忘了写this
测试:阅读量有了.
(2)刚才的修改补充到 ftl 中去(6:50)
函数
生命周期的调用
默认的属性
插值表达式
重新生成并测试:….
静态化解耦
梳理生产端消费端与中间gridfs关系
一、静态化高度耦合(见老师笔记)
说白了就是 后端 前端 放在两个服务器上。
部署方式如下:
(1)后端生成HTML,上传到 GridFS文件系统.
(OSS这种也行吗,内部使用GridFS更好一些)(没懂,不知道这个“内部”是什么意思??)
(2)后端通知前端,应该去获取HTML
(3)前端接受到后端的通知.(前端服务器这里有一个迷你后端,专门接受后端的消息)
(4)前端根据请求,去GridFS下载HTML文件
(5)根据下载的路径,利用Ngix或者tomcat进行“路径虚拟化”,这样,HTML就可以在浏览器端访问到.
==>本节课完成(3)中,“前端服务器迷你后端”的构建
二、“前端服务器迷你后端”的构建(4:50,具体见视频)
1 新建maven工程
html这个服务专门生成HTML.
(1) 补充依赖
(2) yml文件复制过来,微调
port:8002
数据库数据源都不要了mapper这些都不要了.
2 搭建后端框架
(1)构建application启动类
包名如下.
类复制其他服务的即可,基本一样.
(2)构建测试controller
(3)测试(8:00)
测试前关闭数据库的自动类型装配。因为这个工程中数据库的依赖还在,但是我们把数据库的配置都删掉了,所以为了避免sb自动配置时报错,我们把这块禁用。
虚拟机里面mongodb也要启动,不然会报错!
这里给项目改名,增加辨识度.
运行成功:
(这里怎么体现接受后端的消息??还没编写,只是搭了个架子是吗???)
生产端存储html到gridfs并关联文章表
零、
① mongoFileId 就是文件对应的 主键 id。 (本节课,article模块)
② GridFS中的数据要和数据库中的文件关联. (本节课,article模块)
③ 这里下载的路径就是我们tomcat的路径. (下节课,article-html模块)
(前端=消费端【article-html模块】 后端=生产端【article模块】)
(后端生产html,前端消费html)
一、【上传】生成html并上传,拿到mongoFileId
复制文章生成HTML的方法,小改一波,让他变成上传html到GridFS的方法。
(1)修改文件名,然后把生成html的代码都去掉,我们直接上传0,无需生成。
(2)使用freemarker自带的工具类和方法,把 html 转成 string
211行.
(198这里,后面要改成string返回值)
(2.5)调用方法
159注释了,160调用方法进行测试.
(此时还没有返回值,暂时用void)
(3)测试1:打印(2)中得到的string(4:50)
输出的就是我们“静态化后的html”.
(4)上传到GridFS
用这个 apache 的 io 包.
如下:217。写完这个我们先去处理GridFS
(5)GridFS配置类
我们曾在files模块中写过:
拷贝到article中:
article-html也拷贝:
(6)注入GridFS,并调用上传方法,得到对应的mongoFileId
(sout代码测试完了记得注释掉)
这个方法可以传入inputStream,正好和(4)调用IO工具包生成的流匹配上。如下这个方法:
其中String s这个形参是:取名。用当前文章id+后缀来命名。
上传完毕之后,得到ObjectId,属于MongoDB的包。这个我们后面就拿来做关联。把这个 id 返回。
(7)修改审核成功时的代码
164
调用我们刚才写的方法,拿到mongoFileId。
然后准备编写 文件关联保存 的代码。
二、【关联】本地 和 GridFS 的文件
以前讲数据库表设计时,这个mongo-file-id一直没用,现在用来做关联。
(1)service层接口
41
(2)service层实现
116
别忘了加事务。
(3)回到controller,发起调用
166
(???12:30这里提到两个service什么事务,什么关联啥的,没听懂??什么调整到同一service中?==>问答区好像 有讨论这个的,后面看看)
(4)测试(12:50)
mongodb中的:ID列的末尾9e7f
数据库中的:末尾9e7f
—————————————————-
至此,article服务的代码写完了.(生产端)
下节课写article-html的代码。(消费端)
消费端从gridfs下载HTML到tomcat
上节课article服务的代码写完了(生产端):上传 与 关联
本节课写article-html的代码。(消费端):从GridFS下载。
三、【下载】构建 下载 接口.
1 api 工程中,在article包下构建接口
(api这块,不区分article-html和article了)
编写controller接口
2 article-html 工程中实现 消费端接口
先把 gridFSBucket 注入进来.
(1)
选择第二个这个方法来下载啊:
(2)
输出流这里就是“存储下载文件的路径”。
最后要抛出异常(接口之间没抛出,去补一下)、
34 行 separator 左侧是路径,右侧是文件名加后缀。
(3)
其中articlePath通过配置 和 属性注解来获取。
(4)补充注释,补充返回值
返回值这里,返回状态码。
当然你用apache包下的也行,用springframworker的也行,两者的枚举类的名称不太一样,都代表 200。图中显示的是spring包的写法,这个比较推荐。
3 生产端 调用接口
去articleController中编写。
(1)编写调用方法
方法传入 mysql的文章id 和 Mongodb中的id 即可。
url需要重新配置域名,如下:
(??url的规则还要去复习下呀)
方法见177行:184 这里通过 url 调用了消费端的方法。
这里老师写错了,html 和 download 之间少了/
(2)调用:
170 171行
4 测试(12:30)
发表文章后,tomcat这有文件就说明对了!
撤回删除文章,删除gridfs文件以及html(作业)
1 业务介绍
html又声称,也应该有销毁:
如下图:已发布的文章可以“撤回/删除”
不仅要改数据在数据库中的状态,还要把文件从前端删掉!
2 流程简介
(1)点击“撤回/删除”时,拿到文章信息,包括mongodbId.
(2)消费端:根据mongodbId,从gridFS中删掉对应文章.
(emmm,是不是没提 修改 生成端文章状态)
小结:
本章主要完成了 服务器解耦。
接口还是用restTemplate去写的,这种方式的话,耦合度较高。前端多个节点时,就得修改。(没太懂)
如何保证详情页静态化后的高并发性能?(作业)
第十章 RabbitMQ异步解耦与延迟队列
一、MQ介绍与安装
接口解耦需求
==>为实现“接口解耦”,使用 RabbitMQ.
1 回顾上一章节
我们 生产端 通知 消费端 是使用的“Rest 请求调用”.
这样做耦合度较高。
2 从一个故事理解 消息队列
图中模式存在以下几个缺点:
(1)生产者得一个个批发商打电话,批发商多的话,效率很低.
(2)新增批发商的话,还得去记录新的批发商(即后端代码补充新的参数)
==>代表耦合度高
3 优化思路
如何优化?如何做到通知一次,让其他批发商看到,并自己来拿货?
==>微信群:生产者发通知,批发商 监听 通知。从而实现解耦。
4 接口解耦的过程:
RabbitMQ 概述 & MQ 模型
1 常见的MQ
RMQ和Kafka有什么区别呢??去了解一下?
2 什么是RabbitMQ?
AMQP是协议:应用之间通信,分布式中多见
3 应用场景:
4 RabbitMQ模型
channel 就是通道,用来建立连接。可以有很多个,可以发很多消息。
注意,消费者这里和MQ是“双向”的,因为消费者需要“监听”MQ。
Exchange是交换机,可以理解为 路由/映射。不同的Exchange可以把消息放入不同的队列。
集成MQ
MQ整合到项目中去。
一、引入相关依赖和配置
1 api 工程中的 pom 文件:
25行.
导入好了可以查看.
2 在需要使用mq的项目中,进行相关的配置.
(1)生产者 article 服务
打开yml文件,spring节点下配置:49-54
① host:代表mq的安装位置,填Linux的ip即可。(默认是localhost)
② port:5672
③ username 和 password:用可视化界面里的admin.
④ virtual-host:
上图可视化界面就有virtual host,打开如下图,默认有 /,代表根目录.
imooc这个是老师自己创建的,还可以自己创建,图片下面那个add的那块就可以。
测试添加了一个dev的,我们就用的这个!
(2)消费者 article-html 服务
刚才(1)的那几行复制过来即可:34-39
3 启动观察/测试(5:50)
交换机Exchange 和 消息队列Queue 没有创建,目前还看不出来啥.
二、
创建交换机和队列
紧接上节.
二、创建 交换机Exchange 和 队列Queue.
交换机Exchange 和 队列Queue 是独立的,你创建好了还要把它们绑定在一起。
把当前 降锁(说的啥,听不清)的操作写在 api 中。
1 配置文件
路径如下,创建一个配置类.
2 起名
final属性(也没解释为啥).
15和18
3 创建 交换机
放入 spring 容器。注入容器时,其名称也用刚才创建的名字。
① 注意,导入的包是:spring 的 amqp.core.
② 这里这几个代表“不同模式”。我们使用的就是 topic模式 。
③ 形参就是我们刚才命名的交换机的名字。
后期有可能会讲。
④ durable 就是 持久化。对于 消息队列 可以设置 true 或者 false。
⑤ build就是构建。
4 创建队列
5 介绍创建成功后,可视化界面的显示情况
交换机创建成功的话,这里会默认创建7个交换机。
下着这dev就是我们要创建(啥时候创建的?为啥已经有了?)。
队列成功创建时,这里会显示:
(暂未测试)
三、绑定 交换机Exchange 和 队列Queue.
这张MQ模型很重要,牢记。
1 绑定方法
如下:
(1) 绑定类型有很多,我们用amqp.core的这个作为返回值。
(2) bind为绑定方法。这里形参是“队列对象”,而非一个string。因此,为了能在bind中使用,我们通过当前方法的形参把 queue 传进来!交换机形参同理。
同时,加上注解 @Qualifier才 能正确传给bind方法,表示去容器中拿这两个bean。
(3)to就是 和什么绑定 的意思,这里选择形参为 交换机 的。
(4)通过with指定匹配规则
形参为 routingKey,当作是 路由/映射。这里暂时写 article.* 。
==>下节课具体讲这个 routingKey.
(5)noargs() 方法执行绑定,源码中,这个方法就是返回一个Binding对象
2 测试(12:20)
install 和 启动 都没问题.
其实现在没有执行方法,可视化界面没有什么 显示。
创建生产者,配置路由规则
四、创建生产者,设置符合要求的路由规则
生产者应该属于article这个项目。
1 RabbitMQ 路由规则 routing key 介绍
2 使用HelloController进行测试
(1)创建
这个过程主要是“生产者 发送消息到 交换机”,然后“交换机 可以通过 一定的路由规则,把信息存入相应的 队列 中”。
类外补充注解RequestMapping,性质为producer(干啥的忘了)
注入rabbit模板,在hellow方法中写一个发送方法,直接调用 rabbitTemplate 中的 convertAndSend 方法即可。
形参1:要发送到的交换机的名称。
形参2:路由规则,待会写这个。(这个规则,必须符合上节课中,“队列绑定交换机的过程中的 routingKey ”!)
形参3: 说明。object类,一般放一个字符串即可。
上图中30行的规则,必须符合43行的这个“article.*”。
最后测试前,别忘了给方法加上路与朴:
(2)测试(7:50)
调用生产者发送.
可以在可视化界面这里查看:
total 就是 1 了。
交换机:
进入queues板块,找到下面的get Messages,就可以看到了
….
(12:00)更改路由,多个发送请求,再测试。
(14:30)解绑之前的队列,再测试
消费者接收消息处理业务
五、创建消费者
在html模块中处理消费者。
1 消费者监听MQ
(1)创建一个新的类
(2)补充注解.
通过RabbitListener指定要监听的队列.
(3)
形参String payload,Message是amqp.core包下的.
因为消息作用于payload的载体
(4)测试打印payload(3:20)
13行打断点。
思考:这里我们得去在网页调用生产者url,这里才会打印?还是说,不调用生产者url,根据queue已有的就会打印了?
==>只要Queue有消息,就会监听!而不是非要再调用一次生产者的 url 才行。
(5)关键信息:receivedRoutingKey
这里这个Routing Key就是很关键的消息了,通过这个就可以识别是什么类型MQ,然后就可以编写对应的处理代码
2 根据监听到的 receivedRoutingKey 编写匹配的处理代码
关闭刚才编写的 消费者。取消断点,继续处理。
(1)获取receivedRoutingKey
(2)根据不同的receivedRoutingKey进行不同的处理
(3)测试
内容打印到了控制台!
——————————————————————-
至此,生产端口,消费端口,解耦模型完成!
三、
文章静态化HTML与删除
前面几节课实现了如下 RMQ的模型,现在我们要通过这个等模型真正去解决我们项目中静态HTML 上传 下载 删除 的问题!
本节先优化这块代码:
1 生产者
复制一份这个方法,我们重新写!
(1)编写生产者方法
注入mq的模板类.
之前object形参我们写了一个string,现在我们这里把文章id和mongodbId拼接到一起写上去,方便识别。 当然了,假如你要传递的对象多起来后,完全可以新建一个实体类,把信息都放进去,然后把这个实体类对象传进来!
(2)调用生产者方法
176
2 消费者
(1)
这里呢,我们这里新建一个类,把监听、下载、删除的这些操作写在新的Controller类中,将其作为一个组件,注入bean中。然后我们在上节课中rabbitMQconsumer中注入这个类!就可以通过不同的routingkey调用不同的方法了
毕竟这个controller的方法就是已经写好的下载、删除文件的方法。
(2)
rabbitMQconsumer中注入(1)中的controller。
回顾生产者的 routingkey :article.download.do;生产者的objext :文章id,对应mogodbId(对应消费者的paload)
因此,这里消费者这里匹配上这个规则。25行。
然后payload就是生产者的object,是含有 文章id,对应mogodbId 的字符串。这里直接分割,分别获取这两个id。27,28行。
这两个参数就是controller中下载方法所需的 id。32行。
3 测试(6:10)
发个文章,审核通过测试以下。结果是成功的。
文章也下载了,IDEA也接受信息并打印了。
4 更改前端
代码老师准备好了,你切换即可:74切成75。
这样从冬天查询文章,变成了直接打开静态文章。
5 删除功能自己写。
四、延迟队列
延时队列需求与安装配置
一、为什么项目中要应用 延时队列?
(1)
延时消费:之前是消费者监听到就可以处理,现在是监听到以后,等设置的时间到了才处理。
(2)之前业务中的弊端
项目中有一个“自动发布文章”,我们之前写过:
这个就是具体的实现,这是一个全表扫描,只要发布时间小于当前时间,代表可以发布,而不是定时的状态。(??懵了?)。既然是全表扫描,数据量一大必然对数据库造成冲击。同时还有时间精度不够,查询性能低等缺点。
因此,之间 定时任务发布 实际由很多问题。
==>我们使用 延时队列 KO 这个问题!
二、RabbitMQ 延时队列 功能 安装与配置(5:20)
实现延时队列
也需要“构建交换机、队列,并设置绑定关系”!
一、延时队列的配置
1 创建延时队列配置类,并修改交换机和对立的名字!
重新建个个列,交换机的名字和对立的名字都改掉!
创建方法中对应的变量名都改好!
2 调用delayed方法,增加延时队列功能!
25行.
3 队列绑定交换机
改下名字
然后改下routingKey
4 补充:方法名相同导致容器内的冲突
之前和这里绑定方法都是binding,而且都@Bean了,这样可不行!记得改方法名!
38
二、实现 生产者 的延时队列
1 生产者发送延时消息
还是在helloController中编写:
重写一个接口,基本和之前一样,如下:
2 选择重载方法,构建所需的处理器
MessagePostProcessor,这是个 消息发布的处理器,这里可以设置“发送模式”、“延时时间”等
回到controller类中,定义一下这个 MessagePostProcessor,重写一下它里面这个方法。里面这个DeliveryMode就是发送模式,我们选了 持久模式。
随后,再设置时间,单位ms。
3 补充形参
86
三、消费者 监听 延时队列
1 创建消费者
(这一块录制的音质不太好。为什么这里 消费者和生产者要放到一个项目中去????不是要解耦嘛?????)
这里直接复制过来了,还没有重命名
2 修改消费者代码
这里简单sout一下即可
为了方便后面测试,生产者这里也sout一下:90
这样就可以计算时间差了。
四、测试(9:10)
之前设置了5s,这里确实是5s.
上节课模拟了延时队列的演示,熟悉了延时队列的使用流程。
本节课实际运用这个功能,利用它完成“定时发布文章”。
1 业务分析
发文章的时候可以选择 定时发送:
我们需要用 “定时时间 - 当前时间 = 延时时间”
一、生产端
2
先找到article 模块的 ArticleController 的 createArticle方法。
这个方法内部调用过一个service:94
进入这个service。再insert文章以后,补充相应的判断。
进入if里的代码,我们把上节课延时队列演示的代码copy过来,进行修改。
主要包括MessagePostProcessor处理器的设置,convertAndSend。复制过来以后如下:
3 计算延时时间
通过BO得到计算所需的两个时间点,然后就可以计算了。
93-96计算。
98调用了一个API计算,便于我们待会看测试结果。
108这个延时时间已经设置好了。
4 重新约定routingKey
生产者那边重新声明:
消费者这边定义。
message就传文章id即可。
二、消费端
主要是修改状态为“即时发布”
之前定时任务是这么写的:全表查询来修改。
==>现在需要一个修改单条记录状态的service方法
1 service层
(1)接口
25行
(2)实现
181行开始:
2 controller层
注入 service,调用方法.
articleId 这么写,不仅可以方便后续拓展业务的调用,同业也更加清晰。
三、测试(10:20)
———————————————-
延时任务执行完后没有生成html,这块需要作为作业自己去完善。
实现文章的定时延时发布
上节课模拟了延时队列的演示,熟悉了延时队列的使用流程。
本节课实际运用这个功能,利用它完成“定时发布文章”。
1 业务分析
发文章的时候可以选择 定时发送:
我们需要用 “定时时间 - 当前时间 = 延时时间”
一、生产端
2
先找到article 模块的 ArticleController 的 createArticle方法。
这个方法内部调用过一个service:94
进入这个service。再insert文章以后,补充相应的判断。
进入if里的代码,我们把上节课延时队列演示的代码copy过来,进行修改。
主要包括MessagePostProcessor处理器的设置,convertAndSend。复制过来以后如下:
3 计算延时时间
通过BO得到计算所需的两个时间点,然后就可以计算了。
93-96计算。
98调用了一个API计算,便于我们待会看测试结果。
108这个延时时间已经设置好了。
4 重新约定routingKey
生产者那边重新声明:
消费者这边定义。
message就传文章id即可。
二、消费端
主要是修改状态为“即时发布”
之前定时任务是这么写的:全表查询来修改。
==>现在需要一个修改单条记录状态的service方法
1 service层
(1)接口
25行
(2)实现
181行开始:
2 controller层
注入 service,调用方法.
articleId 这么写,不仅可以方便后续拓展业务的调用,同业也更加清晰。
三、测试(10:20)
———————————————-
延时任务执行完后没有生成html,这块需要作为作业自己去完善。