Spring针对velocity实现了默认的file的resourceLoader,每次读取的文件都是固定位置的,如果我们想实现随时改变文件随时页面生效这种效果就很难实现了。
但是现实的应用场景中这样的例子还不少,1营销页面,2产品化的配置管理等
实现方案,可以通过纯前端的方式实现
比如:
1.把页面模版写在数据库里,然后写死一个页面,通过ajax从后台取不同的模版,然后根据不同的数据做渲染展示
2.纯后端模式实现,改造springmvc的view的render这层,保证每次渲染的时候,原有从文件系统读模版改为从db中读模版。
本文主要采用第二种方案和大家做交流。
分析这个问题,首先要了解springMvc的DispatcherServlet处理链路
1. DispatcherServlet中获取到controller返回的ModelAndView之后会通过render方法来获取对应的view代码如下:
2. resolveViewName()方法中,通过所有配置的viewResolver来进行resolveViewName。这个链路一直看下去,会到具体的viewResolver然后build出来view,这里就不过多赘述,详情看代码。
3. 获取到view之后,view会通过render()方法来做渲染,在渲染的过程中会通过VelocityView.doRender()来做渲染,然后通过getTemplate()获取渲染需要的模版。
VelocityView.doRender() ----> getTemplate() ----> VelocityEngine.getTemplate() ---> RuntimeInstance.getTemplate() ---> ResourceManager.getResource()
重点看ResourceManager.getResource
该方法就是模版的具体获取过程,如果第一次访问,那么走else分支,有了缓存走if分支,走else分支的会,会通过loader去获取模版资源
可以看到最终判断文件是否需要更新是通过loader来实现的,VelocityResourceLoader来加载具体的模版
看到这里,我们可以明白了,控制velocity的模版获取是通过loader来实现的。那么如果我们想实现自己来从db里面读取模版,只需实现自己的loader即可(1.获取模版,2控制何时更新模版)
但是问题来了!!!这个loader是何时spring给注入进去做的初始化呢?
继续往下看
众所周知spring配置velocity做展现层是通过VelocityConfigurer来实现的,VelocityConfigurer继承自VelocityEngineFactory,通过各种参数实现了针对velocity的相关参数配置,主要的方法有:VelocityEngineFactory.initVelocityResourceLoader()
spring写死了默认的loader名称为file
看到这里大家应该比较清楚了,实现从db里面读取vm文件,我们只需要重写两个类即可
1.ResourceLoader(在loader中实现原有的从文件系统中读取改为从db中或者分布式文件系统中读取,并控制velocity的缓存管理,实现自己来管理这部分模版的缓存)
2.VelocityConfigurer(在初始化velocity的时候设置不同的classloader名称,并且将自己新写的ResourceLoader设置进去即可)
思路基本上就是上面的思路,由于公司代码不能漏出,所以暂时不贴出重写后的类了。
后续会在上几篇博客嵌入了jetty的springMvc空框架上进行实现。敬请期待。
这篇文章也是断断续续靠晚上挤出来的一点点时间完成的。感觉工作忙了越来越没写技术博客的动力了,无奈记性太差,怕下次忘掉,又要翻源码,所以就记录一下思路吧。