Velocity模板开发常见问题分享
在twitter上看到 @Fenng 提到“国内分享velocity的不多”,忽然想起自己在支付宝用velocity开发了两年,和服务端开发同学也常为这个模板层的归属问题纠结不休。这也是我在淘宝上买这件velocity主题T恤的原因,上次去红京鱼吃饭,工友们对它表示了很大的兴趣^_^
直入话题,把自己这两年的velocity开发经验的精华部分分享出来吧,相信足以应对前端模板开发的日常工作。这里我准备了一个VM版的,有运行环境的同学可以放上去跑起来看看。
问:遇到vm模板开发的问题一般怎么解决?
首先官方手册PDF还是要收藏一份,英文的看不了,就去google上搜份中文手册看。手册上没有提及的只有去google.com(google.cn基本搜不到)上搜索了,用上一些英文关键字一般可以找到,实在找不到只有问周围的专业人士了。
问:如何通过URL传递整型变量到VM里?
#set($n = $!request.getParameter('n')) #set($intNum = 0) #set($m = $intNum.parseInt($n) + 1)
问:#parse和$tile.setTemplate()(或$control.setTemplate())区别是啥?
- #parse是先插入后解析,$tile是先解析后插入。
- #parse和被#parse的页面变量相互共享,$tile变量需要传入。
- #parse是代码块无须controller,$tile是通用组件需要controller。
- #parse需要配置系统的默认path,推荐能用#parse就不要用$tile
问:VM模板里能取到哪些业务的值?
VM是模板解析层,一般可以通过$request取到很多业务数据。比如从当前request对象中取cookie:
#foreach($cookie in $request.getCookies())
$cookie.name : $cookie.value
#end
问:${catge}、$!catge、$catge这些写法有啥区别?
这三种写法语义上是等价的。${catge}比$catge的好处是,可以用{}符号隔开变量和其他文字。$catge和$!catge区别在于当页面中不存在$catge时,$!catge将会不会再页面中显示。
问:VM里的循环、取对象什么的咋搞?
循环啥的,学会怎么用#foreach语句就好了,想知道更多去Google下velocity的参考文档。循环能做的事情很多,比如上面的遍历出request里的cookie。
这里举个绑定一系列元素的JS表单校验的例子:
"attach3": { desc: "附件3", depends : true, required: true }, "attach4": { desc: "附件4", depends : true, required: true }, "attach5": { desc: "附件5", depends : true, required: true },
千万别copy大段相通的VM代码,用这句:
#foreach ( $count in [3..5] ) "attach${count}": { desc: "附件${count}", depends : true, required: true }, #end
如果attch5是最后一个绑定元素呢?那最后一个逗号“,”就不要打出来,这里就引申出一个问题:怎样判断是否为循环的最后一次?
这里要用到一个叫$velocityCount的变量,任何循环语句中都默认有这么一个标识当前循环次数的变量,而数组的长度都可以通过size()方法获取到。
源码:
#set($array = [3,4,5]) #foreach ( $count in $array ) "attach${count}": { desc: "附件${count}", depends : true, required: true }#if($velocityCount !=$array.size()), #end #end
问:听说VM里有宏定义,这个啥东东?
宏定义#macro就是把一些操作封装成类似function的方式来统一处理同类问题,具体你自己去google吧。有兴趣的话建议搜索系统当中叫macros-default.vm(或macros.vm)的文件,一般的宏定义都会写在这个文件里。
需要说明的是,宏定义一般是放在某car的根目录上,在页面上也可以直接定义。宏定义修改之后需要deploy当前系统,否则方法会被缓存,看不到改动后的效果。
问:VM里怎样生成随机数
VM强大之处其实在于它的工具类,例如一般的VM都默认有$stringUtil这个字符串比较的类。
有时我们需要给URL后加个随机数清清缓存。在webx系统你可以用$randomUtils.nextDouble(),在sofa MVC试试$math.getRandom(),如果不起作用,检查下是否配置了相应的工具类。
问:如何通过VM来获取当前页面URL?
貌似前面已经提到VM可以随意调用$request对象里的方法,获取到需要的值。
//webx下获取当前页: $rundata.getRequest().getServerName()$rundata.getRequest().getServletPath() //sofa MVC下获取当前页: #set($pageAbsUrl = "$!request.getServerName()"+"$!request.getContextPath()"+"$!request.getServletPath()") //获取引用页: $rundata.getRequest().getHeader("referer")
问:VM该前端开发来做还是服务端开发来做?有啥意义?
@catge认为服务端提供数据、接口,前端进行VM、CSS、JS开发。因为VM是DOM结构层,样式和脚本都要基于结构开发。
比如有一个需求是为某些浏览器的用户增加一个全站的XBOX弹窗,提醒用户升级到股沟浏览器。你有两种选择方案,一种是用JS判断UA信息为该浏览器,然后将已经生成好的XBOX的DOM弹出来。第二种方案是在VM里取request里的http头信息里的UA信息,判断符合条件则生成这段DOM。
咋一看,这两种方法差不多,而且通过VM来实现更复杂,因为VM里取浏览器类型和版本号十分困难,$stringUtil折腾来折腾去都没有JS来得快。
但是如果需求方说的浏览器是指IE6.0以下版本的浏览器呢?为了几千个用户给几亿用户的前端代码里加上这段JS判断?那只能说你很2。
@catge认为VM层的模板优化至关重要,VM不应该只包含业务逻辑,同时应该使用大量的展现逻辑,针对不同用户、不同来源、不同浏览器展现最优体验。