主要内容:
- mysql中数据发生变化的时候会触发页面静态化,并将数据放到redis中
- fastdfs上需要提前上传一个zip文件,里面包含html、css、js等
- 触发页面静态化之后,从fstdfs下载这个zip,将更新后的数据(在redis中)与模板重新生成html,将这个html上传到fastdfs,用rabbitMQ向nginx所在节点发送消息
- nginx所在节点接收消息,拿到其中html在fastdfs上的路径,下载下来,然后将文件放到nginx的指定站点目录,至此页面静态化完成
时序图:
一.页面静态化的触发
需要页面静态化的网页往往是那些并发访问量高但是又不经常改变的页面,当我们在后端改变这些页面的数据时,触发页面静态化,页面会自动在nginx所在节点指定位置生成,整个过程自动化。
/**
* 课程分类的页面静态化方法
*/
private void pageStatic() {
//1.拿到pageName
//String pageName = pagerMapper.selectPageName(PageConstant.PAGE_ALIAS_COURSE);
String pageName = "home";
//2.往redis中存课程类型的数据,并拿到redisKey
HashMap<String, Object> model = new HashMap<>();
model.put("courseTypes", this.treeData());
AjaxResult ajaxResult = redisFeignClient.set(RedisKeyConstant.CPURSE_TYPE_PAGE_STATIC, JSON.toJSONString(model));
if (!ajaxResult.isSuccess()) {
throw new RuntimeException("redis存数据失败!");
}
//3.往页面静态化服务模块发送消息,消息携带redisKey与pageName
AjaxResult pageAjaxResult = pageFeignClient.pageStatic(pageName, RedisKeyConstant.CPURSE_TYPE_PAGE_STATIC);
if (!pageAjaxResult.isSuccess()) {
throw new RuntimeException("往页面静态化服务发送消息失败!");
}
}
二.页面静态化
页面静态化单独有一个模块,其他模块会去用feign调用这个模块来实现页面静态化
@Override
public void pageStatic(String pageName, String redisKey) throws Exception {
//1.拿到pageName,并根据其查到在fastdfs中的地址
Pager pager = pagerMapper.selectByPageName(pageName);
String templateUrl = pager.getTemplateUrl();
//2.拿到地址后就下载
byte[] templateByte = fastdfsFeignClient.download(templateUrl);
//3.在c盘临时目录创建C:\Users\LXY\AppData\Local\Temp\pageName.zip用于接收先前来的templateByte
String filePath = getTempDir() + pageName + ".zip";
File file = MyFileUtils.createFile(filePath);
FileCopyUtils.copy(templateByte, file);
//4.下载完成后解压到执行目录
String unzipPath = getTempDir() + "pagepath/";
ZipUtils.unZip(filePath, unzipPath);
//5.从redis上获取数据并转换成map格式
AjaxResult result = redisFeignClient.get(redisKey);
if (!result.isSuccess() || result.getResultObj() == null) {
throw new RuntimeException("数据获取失败");
}
String stringResult = result.getResultObj().toString();
Map model = JSON.parseObject(stringResult, Map.class);
model.put("staticRoot", unzipPath);
//6.数据与模板合并生成html,注意模板与html这两个文件都要放在unzipPath下面
String vmPath = unzipPath + pageName + ".vm";
String htmlPath = unzipPath + pageName + ".html";
VelocityUtils.staticByTemplate(model, vmPath, htmlPath);
//7.合并完成后把html上传到Fastdfs , 拿到上传路径
File htmlFile = new File(htmlPath);
byte[] htmlBytes = FileCopyUtils.copyToByteArray(htmlFile);
AjaxResult ajaxResult = fastdfsFeignClient.uploadHtml(htmlBytes);
if (!ajaxResult.isSuccess()) {
throw new RuntimeException("html上传失败");
}
//8.集成MQ,往MQ发送消息
//内容:1.html的fastdfs的下载路径, 2.html需要拷贝到Nginx的物理路径
String htmlDownloadPath = ajaxResult.getResultObj().toString();
String nginxPhysicalPath = pager.getPhysicalPath();
HashMap<String, Object> msgMap = new HashMap<>();
msgMap.put("htmlDownloadPath", htmlDownloadPath);
msgMap.put("nginxPhysicalPath", nginxPhysicalPath);
String routingkey = pagerMapper.selectSiteNameBySiteId(pager.getSiteId());
rabbitTemplate.convertAndSend(RabbitConstant.EXCHANGE_STATIC_PAGE, routingkey, JSON.toJSONString(msgMap));
}
注意rabbitMQ中要先有这个交换机。
三.更新后的页面存放到指定位置
rabbitMQ接收后将消息取出进行处理
//监听页面静态化的队列
@RabbitListener(queues = {RabbitConstant.QUEUE_STATIC_PAGE})
public void receiveEmail(String msg, Message message, Channel channel) throws IOException {
//1.将字符串转换成map
Map map = JSON.parseObject(msg, Map.class);
//html在fastdfs下载路径
String htmlDownloadPath = (String) map.get("htmlDownloadPath");
//nginx物理路径
String nginxPhysicalPath = (String) map.get("nginxPhysicalPath");
//2.从fastdfs下载html
byte[] htmlBytes = fastdfsFeignClient.download(htmlDownloadPath);
if (htmlBytes != null && htmlBytes.length > 0) {
//3.把html拷贝到nginx物理路径
File file = MyFileUtils.createFile(nginxPhysicalPath);
FileCopyUtils.copy(htmlBytes, file);
//触发手动签收
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
}
}