李佳骏

技术改变生活

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

使用Freemarker宏进行可扩展式模块化编程

该文是转载而来,并非我本人所写,但是觉得真心不错,所以收藏一下

一、前言

今天的文章聊一下freemarker的一些特性:宏,我们将使用它写出一些模块化,可扩展的页面代码,这样的复用并且可扩展的代码风格正是我一直所追求的优雅。

二、需求案例

干巴巴的代码没意思,我们拿一个实际应用的例子。

先看一下我们具体的需求,以我的博客网站为例,比较首页 及markdown编辑器页 可以发现他们的公共点即头部导航栏。

再比对下首页文章全文页

可以发现公共点除了头部导航行,还包括博客大标题及右侧导航栏,用面向对象中的继承关系我们可以将它们表示如下:

正如同类可以通过基类定义通用功能实现复用,通过继承扩展一样,freemarker的页面是不是也可以定义基础模板,并经过类似继承的手段来实现复用和扩展呢,答案自然是有的,这个就是我们今天的所谈到的。

三、语法实现

首先是baseMarco.ftl 基本模板宏:

1.baseMarco.ftl

<#compress>//在基本宏里定义#compress 压缩页面指令, 扩展页就不需要定义了
<#macro base base_title base_keywords="" base_js=[] base_css=[]>
//base: 模板名 base_title base_keywords 可由扩展页传入的标题和关键字 
//base_js css 由扩展页传入其自己的css js 我这里定义的是一个数据,方便传入多个
<html lang="zh-CN">
<head>
<title>初的博客-${base_title}</title>
//标题 后缀为扩展页所传入
//公共css
<link rel="stylesheet"
    href="//cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css">
</head>
//遍历扩展页css
<#list base_css as c>
<link rel="stylesheet" href="${staticsPath}${c}">
</#list>
<body id="main-body" >
    <div class="container">
       <ul class="nav nav-pills">
         <li ><a href="/">首页</a></li>
         <li ><a href="/articles.html">文章</a></li>
         ...
       </ul>
    </div>
    //以上是公共导航栏
    //#nested 指令表示扩展页内容将嵌套在此处
    <#nested>
    //以下是公共页脚
    <footer class="blog-footer">
       <p>? 2015-2016 初</p>
    </footer>
</body>
//公共js
<script src="http://apps.bdimg.com/libs/jquery/1.11.3/jquery.min.js"></script>
//遍历公共js
<#list base_js as j>
<script src="${staticsPath}${j}"></script>
</#list>
</html>
</#macro> 
</#compress>

ok,然后是扩展的markdown页。 有了基本宏之后,扩展页就只需要填写自己的内容了,代码非常干净。

2.markdown.ftl:

//引入基本宏
<#include "WEB-INF/views/baseMacro.ftl">     
//@base 基本宏的名字 base_title 本页标题,与base中的前缀拼接就成为了该页完整标题 Chu Lung's Blog-markdown编辑器
//base_js css 本页自有的js和css
<@base base_title="markdown编辑器" base_js=["/markdown/editormd.js","/markdown/main.js"] base_css=["/markdown/css/editormd.css"] base_keywords="在线markdown编辑器,editormd">
//@base 中间的内容将嵌套至 base 宏中的#nested处
    <div id="layout"> 
       <div id="editor-div"></div>
    </div>

</@base> 

以上就完成了markdown页面的扩展。

freemarker的宏嵌套不仅可以嵌套内容,同样也可以嵌套宏,就如同子类继承父类,"孙"类还可以继承子类一样。

前面说到了,首页文章全文页的公共点除了导航栏,还有大标题和侧边栏。因此我们需要扩展宏,让它包含这两页面的公共内容。

3.pageMarco.ftl

//宏名字 page
<#macro page title js=[] css=[] keywords="">
//引入base宏
<#include "WEB-INF/views/baseMacro.ftl">
//标题 js css等让下一级扩展页传入 keywords本页赋值
<@base base_title=title base_js=js base_css=css base_keywords="个人博客,java,初">
//以下内容将被嵌套至base宏中#nested指令处, 注意内容中又包含一个#nested指令
<div class="container">
    //公共大标题
    <div class="blog-header">
       <h1 class="blog-title">初的博客</h1>
       <p class="lead blog-description">唯爱、技术和美食三者不可辜负.</p>
    </div>
    <div class="row">
       <div class="col-sm-8 blog-main">
       //该指令表明下一级扩展页内容将被嵌套至此
       <#nested>
    </div>
    //公共侧边栏
       <div class="col-sm-3 col-sm-offset-1 blog-sidebar">
         <div class="sidebar-module sidebar-module-inset">
          <h4>Hi</h4>
          <p>欢迎来到我的博客</p>
         </div>
         <#-- <div class="sidebar-module">
          <h4>标签</h4>
          <ol class="list-unstyled">
              <li><a href="#">March 2014</a></li>
          </ol>
         </div>
         -->
         <div class="sidebar-module">
          <h4>档案</h4>
          <ol id="articleFilings" class="list-unstyled">
          </ol>
         </div>
       </div>
    </div>
</div>
</@base>
</#macro>

然后首页就可以嵌套至page中了,文章页也一样,这里就不再累述了。

4.index.ftl

<#include "WEB-INF/views/pageMacro.ftl">     
<@page title="首页" js=["/blog/js/common.js"]>
<div>
...
</div>
</@page> 
posted on 2016-11-17 14:06  李佳骏  阅读(305)  评论(0编辑  收藏  举报