Velocity模板语法

接了一个网站开发的项目,网站系统用的是gpower cms,中文名叫通元内容管理系统, 该系统是Java开发,已经提供了内容管理后台,所以只需要开发前端模板即可。

因为后台数据是直接渲染到前端的,所以使用了基础的html+css进行开发。随着移动化的发展,现在看PC端网页越来越少,好在现在的网页设计脱离了原本花里胡哨的风格,通过给div加背景色、边框和阴影,交互上使用动画效果,页面看起来不仅简洁大方,也省了很多设计的苦恼。顺便学会了flex布局,相比以前用的float浮动,写起来确实很畅快。

在一台Windows 7系统的电脑下部署时,看到了历史悠久的IE浏览器,版本为IE8,考虑到还有部分人在使用旧系统,准备做一下兼容性测试,发现IE浏览器已经打不开网页,而不是像以前显示样式错乱,页面惨不忍睹,省了兼容性的麻烦,更不需要在页面中加入升级浏览器提示。不知道是不是IE自己拒绝访问,还是网页中head标签写的那句<meta http-equiv="X-UA-Compatible" content="IE=edge" />起了效果,只能说现在的前端真是赶上好时候了。

对比千篇一律的移动端UI设计和小屏展示,不管是从获取内容还是艺术审美的角度,PC端的网页明显更具多样性也更精美,我只能说互联网不能没有网页。据说淘宝开始逐步下线pc端购物功能,这样真的没有必要。

前端模板做好了,但是出现一个问题,怎么绑定后台数据呢?研究了一下,模板引擎是Apache Velocity,但是系统自己定义了很多方法和变量,在没有开发文档的情况下,只好学习该网站的旧模板代码,复用了一部分,自己摸索出了一部分,现在整理了一下,当作记录,如果是以内容展示为主的网站,以下语法基本够用了。

常用变量和方法

$site.fullName   #站点标题(后台-站点设置)
$pathUtil.getSiteUrl($site)  #站点url,静态资源前添加绝对路径避免引用失效
$cms.getUrl("新闻动态") #根据栏目名获取地址
${curChannel.title}  #当前栏目标题
$curArticle.name  #当前文章标题

#parse("header.vm") #包含引用模板

站点字段

com.gpower.cms.site.entity.SiteSite@62f219ef[name=我的网站,fullName=<null>,shortName=demo,sortID=46,rootChannelID=1356,rootChannel=<null>,pubUrl=http://www.example.com/demo,path=demo,encoding=<null>,logo=<null>,indexFile=index,indexExt=htm,itemExt=htm,dirType=0,smartGet=0,status=1,ifUse=1,defaultChannelID=<null>,defaultContentType=1,secondaryDomain=0,online_=false,synchronizeResource=0,isMobile=0,articleCount=0,publishArticleCount=0,id=45,name=<null>]

文章字段

com.gpower.cms.content.entity.Conten@4d32fffa[title=在中国买车,越来越便宜了?,titleColor=#333333,parentID=1379,siteID=45,viceTitle=<null>,keyword=<null>,author=财经汽车,source=虎嗅,summary=<null>,status=7,type=1,viewCount=0,viewCountToday=0,sortID=1634863758690,owner=jzy,creationDate=Fri Oct 22 08:49:19 CST 2021,modifiedDate=Fri Oct 22 08:52:23 CST 2021,publishDate=Thu Oct 21 08:40:00 CST 2021,url=<null>,version=<null>,versions=<null>,properties=<null>,isTop=4998,beginDay=<null>,topTime=<null>,topDays=0,lock_=false,lockUser=<null>,srcContentID=<null>,srcContent=<null>,channelName=<null>,allowExtranet=false,name=在中国买车,越来越便宜了?,seoData=<null>,id=c9aff8fcd1f443cd94ae2a45a738e321,name=<null>]

栏目字段

com.gpower.cms.channel.entity.Channel@1abe38ad[name=关于我们,sortID=10,title=关于我们,path=gywm,type=0,status=1,orderBy=sortID DESC,query=<null>,code=,publishType=1,dirType=0,logo=,isTop=1,isSuggest=0,archiveDays=0,pageCount=20,pageType=0,inheritRight=1,siteID=45,parentID=1356,site=<null>,parent=<null>,children=[],indexTemplateID=3dd040f6d346444697034e45de336cdd,itemTemplateID=4ebe52ed699f413bbbdb41688dddc920,indexFile=,indexExt=,itemExt=,extendFields=<null>,defaultContentType=1,dispatchChannels=<null>,workflow=0,srcChannelID=0,maxIndex=0,viewCount=0,viewCountToday=0,isApp=0,creationDate=Mon Apr 24 00:00:00 CST 2017,modifiedDate=Sun Mar 03 21:56:03 CST 2024,permit=1,childrenCount=0,orderByValue=0,owner=xscjzy,compressImg=0,mobileShow=0,indexMobileTemplateID=<null>,itemMobileTemplateID=<null>,topic=false,topicStatus=0,orderByValues={sortID DESC,sortID ASC,publishDate DESC,publishDate ASC},url=<null>,networkType=0,articleCount=0,publishArticleCount=0,id=1386,name=<null>]

获取内容

获取某一栏目的文章列表

<ul>
#foreach($article in $cms.getContentsByChannelName("工作动态",8))
    <li><a href="$cms.getUrl($article)">$article.name</a>                           <span>$cms.format($article.publishDate,"yyyy-MM-dd")</span>
    </li>
#end
</ul>

获取文章封面图

  • 因为编辑不会给每篇文章添加封面图片,从最近100篇文章中取出5张带封面图的文章,常用于用户幻灯片展示
#set($expNum = 6)
#set($count = 0)
#set($i = 0)
#foreach($article in $cms.getContentsByChannelName("工作动态",100))
    #if($cms.getPictureUrl($article)!="")
        #set($i=$i+1)
        #if($count<$expNum)
        <div class="swiper-slide">
        <a href="$cms.getUrl($article)" target="_blank">
            <img src="$cms.getPictureUrl($article)" alt="$article.name">
            <div class="news-swiper-title">
            <p>$article.name</p>
            </div>
        </a>
        </div>
        #set($count = $count+1)
        #end
    #end
#end

获取文章摘要

<h3>$article.name</h3>
                                            #if($stringUtil.nullFilter($article.summary)!="")
    <p>$stringUtil.summary($article.summary,120)</p>
#else
    #set($fullArticle=$cmsService.getArticle($article.id))
<p>$stringUtil.summary($cms.clearHtml($stringUtil.nullFilter($fullArticle.content)),120)</p>
#end

获取导航

<ul class="menu">
#if($curChannel.title == "首页")
    <li class="active"><a href="$cms.getUrl("首页")">网站首页</a></li>
#else
    <li><a href="$cms.getUrl("首页")">网站首页</a></li>
#end

#foreach($channel in $cms.getTopChildren($rootChannel))
    #set($count=$cms.getChannelCountByChannelID($channel.id))
    #if ($count == 0)
        #if($channel.title==$curChannel.title)
            <li class="active">
        #else
            <li>
        #end
        <a href="$cms.getUrl($channel)">$channel.title</a></li>
    #else
        #foreach($cChannel in $cms.getChildren($channel,0,1))
            <li>
            <a href="$cms.getUrl($channel)">$channel.title</a>
            <ul class="dropdown">
             #foreach($cChannel in $cms.getChildren($channel))
                <li><a href="$cms.getUrl($cChannel)">$cChannel.title</a></li>
             #end
             </ul>
            </li>
        #end
     #end
#end
</ul>

获取栏目内文章列表

<ul class="post-list">
#foreach($article in $cms.getPageContents($curChannel,$curPage))
    <li><a href="$cms.getUrl($article)">$article.name</a>
        <span class="date-label">$cms.format($article.publishDate,"yyyy-MM-dd")</span>
    </li>
#end
</ul>

获取附件

#if ($cms.getArticleAttachmentCount($curArticle.id, 3)>0)
    <div class="post-file">
    <h3>附件下载</h3>
    <ol>
    #foreach($doc in $cms.getAttachments($curArticle))
     <li><a href="$cms.getUrl($doc)" target="_blank">$doc.name</a></li>
    #end
     </ol>
     </div>
#end

上下篇文章

<div class="post-jump">
#foreach($article in $cmsService.getPageDatas("select * from  cms_content where parentID='$curChannel.id' and status=7 and publishDate>'$cms.format($curArticle.publishDate,'yyyy-MM-dd HH:mm')'  order by publishDate asc",1,1))
    <div class="post-prev">
        <a href="$cms.getUrl($article)">上一篇:  $article.title </a>
    </div>
#end

#foreach($article in $cmsService.getPageDatas("select * from  cms_content where parentID='$curChannel.id' and status=7 and publishDate<'$cms.format($curArticle.publishDate,'yyyy-MM-dd HH:mm')'  order by publishDate desc",1,1))
    <div class="ppost-next">
         <a href="$cms.getUrl($article)">下一篇: $article.title</a>
    </div>
#end
</div>

前端获取文章封面图和摘要

  • 通过在页面中输出全文,再通过js提取图片和截取文字作为摘要
<ul class="post-list">
#foreach($article in $cms.getPageContents($curChannel,$curPage))
<li class="item">
<div class="item-img" style="display:none;"></div>
<div class="item-content">
    <h2 class="item-title"><a href="$cms.getUrl($article)" rel="bookmark">$article.name</a></h2>
    <div class="item-excerpt"></div>
    <div class="item-summary" style="display: none;">
        #set ($fullArticle=$cmsService.getArticle($article.id))
        #if($stringUtil.nullFilter($!{fullArticle.content})!= "")
            $!{fullArticle.content}
        #end
    </div>

</div>
</li>
#end
</ul>

<!-- 需引入jQuery -->
<script src="$pathUtil.getSiteUrl($site)/static/js/jquery.slim.min.js"></script>
<script>
    $(document).ready(function () {
        $(".post-list-pro .item").each(function () {
            var summary = $(this).find(".item-summary").html();
            var img = imgUrlFun(summary);
            var des = filterHTMLTag(summary).substr(1, 150);

            if (img !== '') {
                $(this).find(".item-img ").show().html("<img src='" + img + "'/>");
            }

            if (des != "") {
                $(this).find(".item-excerpt").html(des + "...");
            }

            $(this).find(".item-summary").remove();
        });

    });

    //Get Frist Image
    function imgUrlFun(str) {
        var data = '';
        str.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/, function (match, capture) {
            data = capture;
        });
        return data;
    }

    //Remove HTML tags
    function filterHTMLTag(str) {
        str = str.replace(/<\/?[^>]*>/g, ''); //去除HTML tag
        str = str.replace(/[ | ]*\n/g, '\n'); //去除行尾空白
        str = str.replace(/ /ig, '');//去掉
        return str;
    }
</script>

按浏览量获取当前栏目热门文章

#foreach($article in $cmsService.getPageDatas("select * from cms_content where parentID='$curChannel.id' and status=7 order by viewCount desc",1,6))
    <li><a href="$cms.getUrl($article)" title="$article.title">
        $stringUtil.summary($article.title,30)</a>
    </li>
#end

从上面代码可以看出提供了一个可以直接在前端查询SQL语句的方法

$cmsService.getPageDatas([SQL语句],[从第几条开始],[条数])

获取子栏目

  • 常用于侧边栏,用来展示栏目
  • 如果有兄弟菜单或子菜单,展示子菜单,否则展示推荐的栏目,isSuggest==1 为推荐
 #set($count=$cms.getChannelCountByChannelID($curChannel.id))
            #if($count!=0)
                #set($c=$curChannel)
            #else
                #set($c=$cms.getChannel($curChannel.parentID))
            #end
            <ul class="channel-list">
                #if($c.id==1356)
                    #foreach($channel in $cms.getChildren($c))
                        #if($channel.isSuggest==1)
                            #if($channel.title==$curChannel.title)
                                <li class="current">
                                    <a href="$cms.getUrl($channel)">$channel.title </a>
                                </li>
                            #else
                                <li><a href="$cms.getUrl($channel)">$channel.title</a> </li>
                            #end
                        #end
                    #end
                #else
                    #foreach($channel in $cms.getChildren($c))
                        #if($channel.title==$curChannel.title)
                            <li class="current"> <a href="$cms.getUrl($channel)">$channel.title</a> </li>
                        #else
                            <li><a href="$cms.getUrl($channel)">$channel.title</a> </li>
                        #end
                    #end
                #end
 </ul>

以上代码可以优化,比如判断是否为当前栏目,可以将class单独设置为变量,不需要写两个li标签导致代码冗余

 #if($channel.title==$curChannel.title) 
    #set($current = "current")
 #else
    #set($current = "")
 #end
 <li class=“$current”><a href="$cms.getUrl($channel)">$channel.title </a></li>

获取栏目的图片

  • 如果后台没有设置栏目封面,则显示默认栏目图
#if($stringUtil.nullFilter($curChannel.logo)=="")
   <div style='background-image: url($pathUtil.getSiteUrl($site)/static/images/cover.webp)'>
#else
   <div  style='background-image: url($pathUtil.getSiteUrl($site)/${curChannel.path}/$curChannel.logo)'>
#end

工具

搜索

  • POST方式提交
  • 内含两个字段,query 和 siteID
<form id="search-form" method="post" action="/cms/web/search/index.jsp" target="_blank">
<label>
    <input type="text" name="query" type="text" placeholder="" autocomplete="off"></label>
    <input name="siteID" value="45" type="hidden">
    <button type="submit">搜索</button>
</form>

文章访问统计

<span>阅读量:
    <script src="/cms/web/writeLog.jsp?siteID=$curChannel.siteID&channelID=$curChannel.id&contentID=$curArticle.id"></script></span>

分页(展示页码)

<div class="pager">
#set($prePage = $curPage - 1)
#set($leftm=$prePage/5)
#set($left=$leftm*5 + 1)
#set($right=$leftm*5 + 5)

#if($right>$totalPage)
    #set($right=$totalPage)
#end

#set($nextPage=$curPage+1)
#set($newPage1 = $left + 5)
#set($newPage2 = $left - 1)

#if($curPage>1)
    <a class="prev" href="$cms.getIndexFileName($curChannel,$prePage)">上一页</a>
#else
    <a class="prev">上一页</a>
#end
    <span class="pager-num">
    #foreach($index in [$left..$right])
        #if ($index == $curPage)
            <a class="active">$index</a>
        #else
            <a href="$cms.getIndexFileName($curChannel, $index)">$index</a>
        #end
    #end
    </span>
    #if($curPage<$totalPage)
        <a class="next" href="$cms.getIndexFileName($curChannel, $nextPage)">下一页</a>
    #else
        <a class="next">下一页</a>
    #end
</div>

发表回复

登录后才能评论