《跟我一起做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,前者是首页的模板,后者是定义了很多模板宏,供首页和其他页面调用,代码如下:
<#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&amp;uin=${themeConfig.social_qq}&amp;site=qq&amp;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">&rarr;</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,这就是我想做的。

posted on 2012-04-01 15:56  newflypig  阅读(726)  评论(0编辑  收藏  举报

导航