《跟我一起做J2EE版Blog–jPress》8(神器Freemaker的妙用)
这几天在给去年遗留下来的东汽财务系统做修正,所以手上的jPress进度稍微有些慢,没事,慢工出细活。这一讲我们来聊聊Freemarker,又是一个神器级的小玩意儿。Freemarker本身可以独立使用,生成任何结构的文档(我经常用它来生成XML和JSON,比jdom之流好用多了),当他配合上Struts以后,完全能够取代JSP成为WEBROOT目录下的主角。
![]()
先来讲讲用Freemarker的好处和jsp的坏处,Freemarker是一个模板引擎框架,众所周知的MVC真理:结构+数据=文档(又译作template+data=output),Freemarker可以将数据填入结构中,生成最终的文档,并且在结构处理的过程中,它提供了强大了宏控制,无论是判断还是循环,亦或宏定义甚至递归,都可以实现;而数据这一块就需要我们自己通过DAO来实现了,当模板和数据都准备就绪后,Freemarker的一个process方法就帮我们将模板和数据融合成最终文档了。而在用JSP时,结构和数据是混杂在一起的(即使用了Struts,引入了struts标签,其臃肿程度一样很高),怎一个混乱了得。使用Freemarker时,我们需要准备一个后缀为ftl的模板,这个模板中定义好文档结构,然后使用设计好DAO层及其实现类,完成数据操作(我们这里使用Hibernate,至于原生态的JDBC或者myBatis那就是看各个项目的需求了)。对于我们的jPress来说,ftl就是我们上一章设计的html,去掉所有的文本和数据就变成ftl了,然后在原来有文本的地方用${}来引用数据即可。当然实际开发过程中会碰到各种基于数据的判断和循环,甚至更高级的递归调用,还有不同类型的数据访问,比如数组,MAP类型的访问等等,这些问题在freemarker文档中都有描述,可以边开发,边用,边学。
在pom.xml中加了struts2的依赖以后,freemarker被默认添加进环境了,所以无需手工引入。下面我把上一讲中设计的HTML做成ftl贴出来给大家参考,为了最大限度的复用,我设计了两个文件,一个是index.ftl,另一个是blog.ftl,前者是首页的模板,后者是定义了很多模板宏,供首页和其他页面调用,代码如下:

先来讲讲用Freemarker的好处和jsp的坏处,Freemarker是一个模板引擎框架,众所周知的MVC真理:结构+数据=文档(又译作template+data=output),Freemarker可以将数据填入结构中,生成最终的文档,并且在结构处理的过程中,它提供了强大了宏控制,无论是判断还是循环,亦或宏定义甚至递归,都可以实现;而数据这一块就需要我们自己通过DAO来实现了,当模板和数据都准备就绪后,Freemarker的一个process方法就帮我们将模板和数据融合成最终文档了。而在用JSP时,结构和数据是混杂在一起的(即使用了Struts,引入了struts标签,其臃肿程度一样很高),怎一个混乱了得。使用Freemarker时,我们需要准备一个后缀为ftl的模板,这个模板中定义好文档结构,然后使用设计好DAO层及其实现类,完成数据操作(我们这里使用Hibernate,至于原生态的JDBC或者myBatis那就是看各个项目的需求了)。对于我们的jPress来说,ftl就是我们上一章设计的html,去掉所有的文本和数据就变成ftl了,然后在原来有文本的地方用${}来引用数据即可。当然实际开发过程中会碰到各种基于数据的判断和循环,甚至更高级的递归调用,还有不同类型的数据访问,比如数组,MAP类型的访问等等,这些问题在freemarker文档中都有描述,可以边开发,边用,边学。
在pom.xml中加了struts2的依赖以后,freemarker被默认添加进环境了,所以无需手工引入。下面我把上一讲中设计的HTML做成ftl贴出来给大家参考,为了最大限度的复用,我设计了两个文件,一个是index.ftl,另一个是blog.ftl,前者是首页的模板,后者是定义了很多模板宏,供首页和其他页面调用,代码如下:
<#assign s=JspTaglibs["/WEB-INF/views/common/struts-tags.tld"] />
<#import "blog.ftl" as blog/>
<@blog.blogHeader/>
<!--主面板-->
<div class="grid_9">
<#list entryPage.items as entry>
<@blog.blogEntry entry />
</#list>
</div>
<!--侧边栏-->
<div class="grid_3">
<@blog.blogSiderbar/>
</div>
<@blog.blogPagination entryPage.pages[0] , entryPage.pages[entryPage.pages?size-1] , entryPage.currentPage , entryPage.totalPage />
</div>
<@blog.blogFooter />
</body>
<script type="text/javascript">
document.getElementById("searchInput").value="<@s.text name="button.search"/>";
document.getElementById("searchInput").onfocus=function(){if(this.value=="<@s.text name="button.search"/>")this.value="";};
document.getElementById("searchInput").onblur=function(){if(this.value=="")this.value="<@s.text name="button.search"/>";};
</script>
</html>
<#assign s=JspTaglibs["/WEB-INF/views/common/struts-tags.tld"] />
<#--The blog's header-->
<#macro blogHeader>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="description" content="${siteConfig.siteAbout}"/>
<meta name="keywords" content="${siteConfig.siteKeyWords}"/>
<title>${siteConfig.siteTitle}</title>
<link href="themes/admired/css/960_12_col.css" rel="stylesheet" type="text/css" />
<link href="themes/admired/css/reset.css" rel="stylesheet" type="text/css" />
<link href="themes/admired/css/common.css" rel="stylesheet" type="text/css" />
<style>
</style>
</head>
<body>
<div id="header">
<div class="textShadow" id="header_top">
<!--标题-->
<h1 id="site-title"><a href="#">${siteConfig.siteTitle}</a></h1>
<!--副标题-->
<h2 id="site-description">${siteConfig.subTitle}</h2>
</div>
</div>
<div class="container_12" id="main">
<!--社交功能区-->
<ul id="admired-social">
<#if themeConfig.social_qq??><li id="admired-qq"><a href="http://wpa.qq.com/msgrd?v=3&uin=${themeConfig.social_qq}&site=qq&menu=yes" title="给我发消息"></a></li></#if>
<#if themeConfig.social_renren??><li id="admired-renren"><a target="_blank" href="http://www.renren.com/${themeConfig.social_renren}" title="人人"></a></li></#if>
</ul><div class="clear"></div>
<!--导航-->
<ul id="nav-bar">
<li class="now-page" id="nav-homePage"><a href="#"><@s.text name="label.home"/></a></li>
<li><a href="#">About</a></li>
<form id="searchForm" action="search" method="get">
<label for="s"><@s.text name="button.search"/></label>
<input id="searchInput" type="text" name="s" value="<@s.text name="button.search"/>"/>
<input id="searchSubmit" type="submit"/>
</form>
</ul>
</#macro>
<#--The blog's footer-->
<#macro blogFooter>
<div id="footer">
<div class="container_12">
<a id="scrollTop" href="#header"></a>
<div id="site-info" class="textShadow">${siteConfig.copyRight}</div>
</div>
</div>
</#macro>
<#--The pagination-->
<#macro blogPagination beginPage endPage currentPage totalPage>
<div id="pagination" class="grid_12">
<span>Page ${currentPage} of ${totalPage}</span>
<#list beginPage..endPage as p>
<#if p=currentPage>
<span class="current-page">${p}</span>
<#else>
<a href="#">${p}</a>
</#if>
</#list>
</div>
</#macro>
<#--The Entry-->
<#macro blogEntry entry>
<!--文章-->
<div class="entry boxShadow">
<!--文章标题栏-->
<div class="entry-header">
<!--日历-->
<div class="entry-calendar textShadow">
<p>${entry.createDt?string("MMM")}</p>
<p>${entry.createDt?string("dd")}</p>
</div>
<!--标题-->
<h1 class="entry-title"><a href="#">${entry.title}</a></h1>
<!--标题栏其他信息-->
<div class="entry-meta">
<p>Posted on <a href="#">${entry.createDt}</a></p>
<p class="entry-author">By <a href="#">${entry.author.nickname}</a></p>
</div>
</div>
<!--内容-->
<div class="entry-content">
${entry.content}<a href="#" class="more-link">Continue reading <span class="meta-nav">→</span></a></p>
</div>
<!--文章底部-->
<div class="entry-footer">
<!--底部信息-->
<div class="entry-meta">
<#if entry.categories?has_content><p>Posted in
<#list entry.categories as category>
<a href="#" title="View all posts in ${category.name}">${category.name}</a>
</#list> | </p></#if>
<#if entry.tags?has_content><p>Tagged with
<#list entry.tags as tag>
<a href="#" title="View all posts tagged with ${tag.name}">${tag.name}</a>
</#list> | </p></#if>
<a href="#" title="Comment on THIS TITLE">Leave a replay </a><p>${entry.views} views</p>
</div>
<!--编辑,如果有的话-->
<a class="entry-edit" href="#">Edit</a>
<div class="clear"></div>
</div>
</div>
</#macro>
<#--SiderBar-->
<#macro blogSiderbar>
<div class="widget" id="tags-widget">
<h3 class="widget-title">Tags</h3>
<div class="boxShadow tags">
<#list tags as tag>
<a href="#" style="font-size:${tag.fontSize}px;">${tag.name}</a>
</#list>
</div>
</div>
<div class="widget" id="category-widget">
<h3 class="widget-title">Category</h3>
<div class="boxShadow">
<@showCate cates/>
</div>
</div>
</#macro>
<#macro showCate icates>
<#if icates?has_content>
<ul>
<#list icates as cate>
<li><a href="#" title="${cate.description}">${cate.name}</a>(${cate.count})
<@showCate cate.subCategories/>
</li>
</#list>
</ul>
</#if>
</#macro>
设计好模板后,就可以让struts来用模板建立返回页面了,方法是在struts配置文件中,为action配上freemarker的返回类型,配置示例如下:<action name="index" class="com.flyding.jpress.actions.IndexAction">
<result type="freemarker">/WEB-INF/views/admired/index.ftl</result>
</action>
这一章主要介绍了freemarker及其在struts中的使用,本博的目的是带领大家认知J2EE领域广泛使用的一些技术,并带领大家一步一步熟悉J2EE一个项目开发的流程,真正深入研究某项技术的话还需要感兴趣的朋友花点时间阅读DOC和DEMO,今后jPress还将陆续用到Spring Security和Lucence,不管这些技术在jPress这一牛刀小试的项目中作用有多微弱,毕竟能够给新人带来参考和入门DEMO,这就是我想做的。
浙公网安备 33010602011771号