项目背景

公司开发新的项目,选择了分布式系统架构,同时项目中有大量图文展示的需求,考虑到开发效率和性能问题,需要集成cms的功能,程序实现后台录入数据静态化。

技术架构

java开发、jdk1.8,项目整体的技术架构大致是这样的:


前端采用的bootstrap、extJs,权限采用shiro框架,搜索采用solr或者lucene(这个暂时没有实现)。

过往问题

在这个项目之前,公司有另一套cms系统,做为公司主要经营业务的基础,它有很多优点,最主要的优点是定制性强,能适应各种前端版式的页面。另一个优点是开发速度特别快,基于模版标签开发,屏蔽了代码级的复杂度和开发人员水平的差距。
弱点有三个
一、在于标签库的实现,完全是基于正则替换,然后处理标签表述的逻辑进行查库、处理。标签没有实现语法树,也没有上下文,导致了多个标签函数嵌套的时候,某些时候无法正确实现替换逻辑。
二、没有应用更多的缓存技术(只实现了jvm内的HashMap缓存),数据量大的任务,生成速度在查库上,有明显的瓶颈。
三、生成失败的模版,没有给出足够明确的错误提示,辅助使用者调试错误。

基本思路

整个大体流程

整个生成是基于freemarker模版引擎,项目初期,曾经对比过velocity与freemarker,因为freemarker最后一次更新时间比较近,最终选择了freemarker,其实两者应该差不多。

关键点

先晒一下目前的类结构

一、自定义标签与自定义函数

freemarker支持实现TemplateMethodModelEx接口的自定义函数,及实现TemplateDirectiveModel的自定义标签。上面代码,fun包下面的就是自定义函数,tags包下面的是自定义标签。
两者的区别,
1、从调用方法来看,

arts(10, 10, ”, ”)

这种是自定义函数
<@arts menu="15" pagesize="15" sort="" sql="";arts, page></@arts>
这种是自定义标签
2、自定义函数有返回值,可以再套入别的函数进行计算或者迭代。自定义标签没有返回值,它会返回几个变量,作用域只在标签体内部。
3、自定义标签传入的参数有Environment、TemplateDirectiveBody等等,即可以获取其他位置定义的模版变量,又可以追加变量,还可以输出字符串文本到最终生成的页面上。自定义函数,只能仅仅返回处理后的返回值。

二、freemarker生成静态页到指定路径的方法

这个问题,基本上查api或者别的博客就能找到具体的方法,但是有些资料可能不准确,这里我直接把我实现了的核心代码贴出来。我使用的freemarker版本是2.3.23。

//成员变量
private static Configuration config = new  Configuration(Configuration.VERSION_2_3_25);
//config设置
config.setLocale(Locale.CHINA);  config.setDefaultEncoding("utf-8");  config.setEncoding(Locale.CHINA, "utf-8");  config.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_25));StringTemplateLoader stringLoader = new StringTemplateLoader();
//content是模版内容的字符串        stringLoader.putTemplate("siteTemplate",content);  config.setTemplateLoader(stringLoader);
try(FileWriter out = new FileWriter(filePath.toFile());) {Template template = config.getTemplate("siteTemplate","utf-8");  config.setCustomAttribute("customDataModel", dataModel);template.process(dataModel, out);out.flush();} catch (Exception e) {//异常处理}

三、列表页分页,如何根据一个模版,动态生成出一或多个分页面

这个问题包括很多细节,比如生成后的地址规则。假设目标地址是news_index.html,那么第二页就不能用这个地址,我的处理方式是news_index_x.html,x代表第几页,可以是2~n。但是第一页就是原地址。
最关键
如果你也需要基于freemarker实现这个功能,大概机会发现,最关键的问题,是如何在生成第一页的时候,知道还有第二页需要生成。因为产生多个分页面,一般是在自定义标签里面,比如有一个循环数据列表的标签,发现一页10条,无法显示完,怎样告知生成阶段的代码(就是上面那一段)。这是两个完全不同的代码区域和处理阶段。
参考了另一款开源cms,我采取了一种有点技巧性的做法。核心思想就是,上面说到自定义标签,可以在生成后的页面上,任意输出字符串。假设标签中判断还有下一页,需要生成,就在页面上输出一段注释,本页面生成完以后,重新读取生成的页面,发现有包含此种注释,则继续生成下一页。

下面贴一些代码

//输出还有下一页的标识
env.getOut().write(LBLCommon.getHasNextPage(totalRecord, totalPage, pageIndex));public static String getHasNextPage(int recordCount, int totalPage, int pageindex) {return hasNextPage+"_"+recordCount+"_"+totalPage+"_"+pageindex+"-->";}

//生成静态化页面 this.writeUseFreeMarker(name, content, url, dataModel);
//分页机制,查询是否需要分页————————————————————
this.morePageProcess(name, dataModel, url, rootPath, content, entry);

//处理分页
private void morePageProcess(String name, Map<String, Object> dataModel, String url, String rootPath, String content, Map.Entry<String, String> entry) throws Exception{String html = this.readFile(url);LBLPagerModel pager = checkHasNextPage(html);if (pager != null) {//重设置一个基础的总记录数dataModel.put("totalRecord", pager.getRecordCount());for (int i = 2; i<= pager.getTotalPage(); i ++) {//设置页码setPageIndex(dataModel, i);url = rootPath + LBLCommon.getPageUrl(entry.getValue(), i);this.writeUseFreeMarker(name, content, url, dataModel);}}
}

整个静态化的部分,还有很多别的细节和坑,比如标签参数的转型问题,生成静态页过程中模版exception的catch和反馈,查询生成队列情况的监控模块(基于mongo),标签设计,自动生成、定时生成、过滤生成…

总结

静态化的功能,与业务结合的很紧密,好的标签设计非常重要,这个可能得靠多踩坑才能提升一点躲开雷区的能力。另外,这次的开发过程,也让我更深刻的认识到,深思熟虑,先慢后快,不写一行垃圾代码,才是最节约时间的开发模式。

更多有趣的信息,包括一个新的周更python主题,都在我的公众号,请扫描下方二维码关注

一次分布式架构cms系统页面静态化模块开发经历相关推荐

  1. MySQL建表添加乐观锁字段_Java秒杀系统优化-Redis缓存-分布式session-RabbitMQ异步下单-页面静态化...

    Java秒杀系统优化-Redis缓存-分布式session-RabbitMQ异步下单-页面静态化 项目介绍 基于SpringBoot+Mybatis搭建的秒杀系统,并且针对高并发场景进行了优化,保证线 ...

  2. 软件架构-解密电商系统-页面静态化

    秒杀系统说了几次了,基本技术点都有所涉及.真正的要解决大流量分布式系统的时候,不是特别容易,就像CAP原则和BASE原则,没有最优的方案,只有最合适的. 页面静态化(一) ① 技术方案 通过程序将动态 ...

  3. 电商详情页系统实战(2) -小型电商网站商品详情页的页面静态化架构及缺陷

    商品详情页的系统架构 => 缓存架构 => 高并发 => 高可用 电商网站里,大概可以说分成两种 小型电商 简单的一种架构方案,页面静态化的方案 大型电商 复杂的一套架构,大电商,国 ...

  4. 亿级流量电商详情页系统实战-1.小型电商网站的商品详情页的页面静态化架构以及其缺陷

    1.电商网站按规模分类 电商网站里,大概可以说分成两种: 小型电商 简单的一种架构方案,页面静态化的方案 大型电商 复杂的一套架构,大电商,国内排名前几的电商,大型的详情页架构页面静态化,全量的页面静 ...

  5. 学成在线 第4天 讲义-页面静态化 页面预览

    1页面静态化需求 1.为什么要进行页面管理? 本项目cms系统的功能就是根据运营需要,对门户等子系统的部分页面进行管理,从而实现快速根据用户需求修改 页面内容并上线的需求. 2.如何修改页面的内容? ...

  6. 如何通过页面静态化提升论坛性能

    为什么80%的码农都做不了架构师?>>>    页面静态化可以提升网站性能,但是如何才能提升论坛性能...浏览还可以,但是数据提交静态化似乎很难提升性能. 转载于:https://m ...

  7. ASP.NET 权限管理 页面静态化 OA系统培训 三层架构

    白菜价, 想要的联系QQ:867635458,非诚勿扰! ASP.NET MVC Linq 技术  企业级通用OA系统  全程开发 大型企业级别OA项目实战全新上线啦!本项目由小孔子讲师全程录制.小孔 ...

  8. CMS系统的页面静态化流程

    一.CMS系统的功能 CMS系统就是内容管理系统(Content Management System).就是管理网站展示内容的系统. 在传统的门户网站或电商网站开发中,我们需要频繁的修改前端展示的内容 ...

  9. 大型网站架构提速关键技术(页面静态化、memcached、Mysql优化)

    大型网站关键技术介绍 1. pv值(page views),访问量大 带来问题 a. 流量大 10000000*2m ->解决方案 买带宽 ,优化程序(处理图片) b. 并发量,同时访问网站的人 ...

  10. web 页面静态化设计

    写在前头 静态化是解决减轻网站压力,提高网站访问速度的常用方案,但在强调交互的We2.0 时代,对静态化提出了更高的要求,静态不仅要能静,还要能动,下面我通过一个项目,谈谈网站静态化后的架构设计方案, ...

最新文章

  1. 用户切换命令:su 与 sudo
  2. java代码输出伞_在伞中集成测试Web应用程序的问题
  3. jzoj3512-游戏节目【树状数组,双向dfs】
  4. Qt工作笔记-双击TreeWidget列进行数据修改
  5. Q-learning家族【强化学习】
  6. MediaPipe: Google Research 开源的跨平台多媒体机器学习模型应用框架
  7. HashMap深度分析
  8. linux终端自动输入,linux shell自动输入实现
  9. java pdf转为png_java-使用icepdf实现pdf转换成png
  10. Oracle包和包体
  11. 在IIS6 配置使用php5.4的fastcgi模式
  12. 腾讯元老、上市公司CTO辞职后,每天对着200亩地发呆!
  13. 2020 dns排名_2020年中国最快的dns_动漫台
  14. Gradle剔除依赖
  15. java lang ClassCastException java lang Integer cannot be ca
  16. 《阿里巴巴Java开发手册(正式版)》--MySQL规约
  17. ubuntu 安裝 jdk 6 遇到的問題
  18. Latex术语表加边框
  19. 倒车轨迹线的实现方法(基于前人基础改进和验证)
  20. Android-仿QQ/微信-全局新消息提示 仿微信悬浮通知栏/横幅通知

热门文章

  1. Protected Process Light(PPL)微软系统进程保护机制
  2. [转帖]房博士教你购房(二)
  3. ProcessOn画斜箭头、写公式方法记录
  4. Chrome 插件配置
  5. Bzoj4484 [Jsoi2015]最小表示
  6. Java中守护线程和本地线程区别,这特么太重要了!
  7. 英语学习口诀大全be 的用法口诀
  8. 如何接触的最新的前端动态、最前沿的前端技术
  9. 为什么使用阿里普惠体没效果
  10. MATLAB混度系统仿真其二:蔡氏电路系统和三阶RC梯形移相振荡器仿真