使用Java进行FreeMarker的web模板开发的基础教程

一、概述

FreeMarker 是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯 Java 编写,FreeMarker 被设计用来生成 HTML Web 页面,特别是基于 MVC 模式的应用程序,虽然 FreeMarker 具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由FreeMarker 生成页面,通过模板显示准备的数据(如下图)

FreeMarker 不是一个 Web 应用框架,而适合作为 Web 应用框架一个组件。FreeMarker 与容器无关,因为它并不知道 HTTP 或 Servlet;FreeMarker 同样可以应用于非Web应用程序环境,FreeMarker 更适合作为 Model2 框架(如 Struts)的视图组件,你也可以在模板中使用 JSP标记库。另外,FreeMarker是免费的。

二、Freemarker的准备条件

freemarker.2.3.16.jar,下载地址这里就不贴了..(这个jar包其实在struts2里面)

三、Freemarker生成静态页面的原理

Freemarker 生成静态页面,首先需要使用自己定义的模板页面,这个模板页面可以是最最普通的html,也可以是嵌套freemarker中的 取值表达式, 标签或者自定义标签等等,然后后台读取这个模板页面,解析其中的标签完成相对应的操作, 然后采用键值对的方式传递参数替换模板中的的取值表达式,做完之后 根据配置的路径生成一个新的html页面, 以达到静态化访问的目的。

四、Freemarker提供的标签

Freemarker提供了很多有用 常用的标签,Freemarker标签都是<#标签名称>这样子命名的,${value} 表示输出变量名的内容 ,具体如下:

1、list:该标签主要是进行迭代服务器端传递过来的List集合,比如:

  <#list nameList as names>
   ${names}
  </#list>

name是list循环的时候取的一个循环变量,freemarker在解析list标签的时候,等价于:

  for (String names : nameList) {
    System.out.println(names);
  }

2、if:该标签主要是做if判断用的,比如:

  <#if (names=="陈靖仇")>
   他的武器是: 十五~~
  </#if>

这个是条件判断标签,要注意的是条件等式必须用括号括起来, 等价于:

  if(names.equals("陈靖仇")){
    System.out.println("他的武器是: 十五~~");
  }

3、include:该标签用于导入文件用的。

  <#include "include.html"/>

这个导入标签非常好用,特别是页面的重用。

另外在静态文件中可以使用${} 获取值,取值方式和el表达式一样,非常方便。

下面举个例子(static.html):

  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Insert title here</title>
  </head>
  <body> 

  描述:${description}
  <br/>
  集合大小:${nameList?size}
  <br/>
  迭代list集合:
  <br/>
  <#list nameList as names>
  这是第${names_index+1}个人,叫做:<label style="color:red">${names}</label>
  if判断:
  <br/>
  <#if (names=="陈靖仇")>
   他的武器是: 十五~~
  <#elseif (names=="宇文拓")>    <#--注意这里没有返回而是在最后面-->
   他的武器是: 轩辕剑~·
  <#else>
  她的绝招是:蛊毒~~
  </#if>
  <br/>
  </#list>
  迭代map集合:
  <br/>
  <#list weaponMap?keys as key>
  key--->${key}<br/>
  value----->${weaponMap[key]!("null")}
  <#--
  fremarker 不支持null, 可以用! 来代替为空的值。
  其实也可以给一个默认值
  value-----${weaponMap[key]?default("null")}
  还可以 在输出前判断是否为null
  <#if weaponMap[key]??></#if>都可以
  --> 

  <br/>
  </#list>
  include导入文件:
  <br/>
  <#include "include.html"/> 

  </body>
  </html>

实际代码:

  package com.chenghui.test; 

  import java.io.File;
  import java.io.FileOutputStream;
  import java.io.IOException;
  import java.io.OutputStreamWriter;
  import java.io.Writer;
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  import java.util.Map; 

  import freemarker.template.Configuration;
  import freemarker.template.DefaultObjectWrapper;
  import freemarker.template.Template;
  import freemarker.template.TemplateException; 

  public class CreateHtml {
    public static void main(String[] args) {
      try {
        //创建一个合适的Configration对象
        Configuration configuration = new Configuration();
        configuration.setDirectoryForTemplateLoading(new File("D:\\project\\webProject\\WebContent\\WEB-INF\\template"));
        configuration.setObjectWrapper(new DefaultObjectWrapper());
        configuration.setDefaultEncoding("UTF-8");  //这个一定要设置,不然在生成的页面中 会乱码
        //获取或创建一个模版。
        Template template = configuration.getTemplate("static.html");
        Map<String, Object> paramMap = new HashMap<String, Object>();
        paramMap.put("description", "我正在学习使用Freemarker生成静态文件!"); 

        List<String> nameList = new ArrayList<String>();
        nameList.add("陈靖仇");
        nameList.add("玉儿");
        nameList.add("宇文拓");
        paramMap.put("nameList", nameList); 

        Map<String, Object> weaponMap = new HashMap<String, Object>();
        weaponMap.put("first", "轩辕剑");
        weaponMap.put("second", "崆峒印");
        weaponMap.put("third", "女娲石");
        weaponMap.put("fourth", "神农鼎");
        weaponMap.put("fifth", "伏羲琴");
        weaponMap.put("sixth", "昆仑镜");
        weaponMap.put("seventh", null);
        paramMap.put("weaponMap", weaponMap); 

        Writer writer = new OutputStreamWriter(new FileOutputStream("success.html"),"UTF-8");
        template.process(paramMap, writer); 

        System.out.println("恭喜,生成成功~~");
      } catch (IOException e) {
        e.printStackTrace();
      } catch (TemplateException e) {
        e.printStackTrace();
      } 

    }
  }

这样子基本上可以算的上可以简单的去做一点简单的生成了,但是要在实际中去运用,还是差的很远的,因为freemarker给的标签完全满足不了我们的需要,这时候就需要自定义标签来完成我们的需求了。。
五、Freemarker自定义标签

Freemarker自定义标签就是自己写标签,然后自己解析,完全由自己来控制标签的输入输出,极大的为程序员提供了很大的发挥空间。

基于步骤:

以前写标签需要在<后加# ,但是freemarker要识别自定义标签需要在后面加上@,然后后面可以定义一些参数,当程序执行template.process(paramMap, out);,就会去解析整个页面的所有的freemarker标签。

自定义标签 需要自定义一个类,然后实现TemplateDirectiveModel,重写execute方法,完成获取参数,根据参数do something等等。。

将自定义标签与解析类绑定在一起需要在paramMap中放入该解析类的实例,存放的key与自定义标签一致即可。。

注意:在自定义标签中,如果标签内什么也没有,开始标签和结束标签绝对不能再同一行,不然会报错

freemarker.log.JDK14LoggerFactory$JDK14Logger error

我曾经上当过,这是freemarker 存在的bug。

下面是static.html的例子:

  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
  <html>
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  <title>Insert title here</title>
  </head>
  <body>
  <#--自定义变量-->
  <#assign num='hehe'/>
  ${num}
  <br/>
  自定义标签
   <@content name="chenghui" age="120">
    ${output}
    ${append}
   </@content> 

  </body>
  </html>

下面是上面的static.html模板的解析类:

  package com.chenghui.test; 

  import static freemarker.template.ObjectWrapper.DEFAULT_WRAPPER; 

  import java.io.IOException;
  import java.io.Writer;
  import java.util.Map; 

  import freemarker.core.Environment;
  import freemarker.template.TemplateDirectiveBody;
  import freemarker.template.TemplateDirectiveModel;
  import freemarker.template.TemplateException;
  import freemarker.template.TemplateModel;
  import freemarker.template.TemplateModelException;
  import freemarker.template.TemplateNumberModel;
  import freemarker.template.TemplateScalarModel; 

  /**
   * 自定义标签解析类
   * @author Administrator
   *
   */
  public class ContentDirective implements TemplateDirectiveModel{ 

    private static final String PARAM_NAME = "name";
    private static final String PARAM_AGE = "age"; 

    @Override
    public void execute(Environment env, Map params,TemplateModel[] loopVars,
        TemplateDirectiveBody body) throws TemplateException, IOException {
      if(body==null){
        throw new TemplateModelException("null body");
      }else{
        String name = getString(PARAM_NAME, params);
        Integer age = getInt(PARAM_AGE, params);
        //接收到参数之后可以根据做具体的操作,然后将数据再在页面中显示出来。
        if(name!=null){
          env.setVariable("output", DEFAULT_WRAPPER.wrap("从ContentDirective解析类中获得的参数是:"+name+", "));
        }
        if(age!=null){
          env.setVariable("append", DEFAULT_WRAPPER.wrap("年龄:"+age));
        }
        Writer out = env.getOut();
        out.write("从这里输出可以再页面看到具体的内容,就像document.writer写入操作一样。<br/>");
        body.render(out); 

        /*
        如果细心的话,会发现页面上是显示out.write()输出的语句,然后再输出output的内容,
        可见 在body在解析的时候会先把参数放入env中,在页面遇到对应的而来表单时的才会去取值
        但是,如果该表单时不存在,就会报错, 我觉得这里freemarker没有做好,解析的时候更加会把错误暴露在页面上。
        可以这样子弥补${output!"null"},始终感觉没有el表达式那样好。
        */
      }
    } 

    /**
     * 获取String类型的参数的值
     * @param paramName
     * @param paramMap
     * @return
     * @throws TemplateModelException
     */
    public static String getString(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{
      TemplateModel model = paramMap.get(paramName);
      if(model == null){
        return null;
      }
      if(model instanceof TemplateScalarModel){
        return ((TemplateScalarModel)model).getAsString();
      }else if (model instanceof TemplateNumberModel) {
        return ((TemplateNumberModel)model).getAsNumber().toString();
      }else{
        throw new TemplateModelException(paramName);
      }
    } 

    /**
     *
     * 获得int类型的参数
     * @param paramName
     * @param paramMap
     * @return
     * @throws TemplateModelException
     */
    public static Integer getInt(String paramName, Map<String, TemplateModel> paramMap) throws TemplateModelException{
      TemplateModel model = paramMap.get(paramName);
      if(model==null){
        return null;
      }
      if(model instanceof TemplateScalarModel){
        String str = ((TemplateScalarModel)model).getAsString();
        try {
          return Integer.valueOf(str);
        } catch (NumberFormatException e) {
          throw new TemplateModelException(paramName);
        }
      }else if(model instanceof TemplateNumberModel){
        return ((TemplateNumberModel)model).getAsNumber().intValue();
      }else{
        throw new TemplateModelException(paramName);
      }
    }
  }

然后再前面的实际代码中加上:

  //自定义标签解析
  paramMap.put("content", new ContentDirective());

这样子基本上可以使用,freemarker完成自定义标签了,解决一写简单的业务逻辑, 但是在实际的项目中不可能这样子去做,因为还没有和spring进行集成使用,每次都需要在解析的时候把解析类的实例放进去。。

(0)

相关推荐

  • java Freemarker页面静态化实例详解

    Freemarker FreeMarker 是一个用 Java 语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与 Web 容器无关,即在 Web 运行时,它并不知道 Servlet 或 HTTP.它不仅可以用作表现层的实现技术,而且还可以用于生成 XML,JSP 或 Java 等. 目前企业中:主要用 Freemarker 做静态页面或是页面展示 总结:freemarker 模版引擎,可以使用 Freemarker 模版生成 html 页面. Freemarker 语法 /*

  • Java操作FreeMarker模板引擎的基本用法示例小结

    FreeMarker 是一个采用 Java 开发的模版引擎,是一个基于模版生成文本的通用工具. 它被设计用来生成 HTML Web 页面,特别是基于 MVC 模式的应用程序.虽然使用FreeMarker需要具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由 FreeMarker 生成页面,并通过模板显示准备的数据. http://freemarker.org/ public void process(String template, Map<String, ?> data) th

  • Java用freemarker导出word实用示例

    最近一个项目要导出word文档,折腾老半天,发现还是用freemarker的模板来搞比较方便省事,现总结一下关键步骤,供大家参考,这里是一个简单的试卷生成例子. 一.模板的制作 先用Word做一个模板,如下图: (注意,上面是有表格的,我设置了边框不可见)然后另存为XML文件,之后用工具打开这个xml文件,有人用firstobject XML Editor感觉还不如notepad++,我这里用notepad++,主要是有高亮显示,和元素自动配对,效果如下: 上面黑色的地方基本是我们之后要替换的地

  • 基于Java的Spring框架来操作FreeMarker模板的示例

    1.通过String来创建模版对象,并执行插值处理 import freemarker.template.Template; import java.io.OutputStreamWriter; import java.io.StringReader; import java.util.HashMap; import java.util.Map; /** * Freemarker最简单的例子 * * @author leizhimin 11-11-17 上午10:32 */ public cla

  • java Spring整合Freemarker的详细步骤

    我的開發環境框架:springmvc開發工具:springsource-tool-suite-2.9.0版本:1.6.0_29tomcat版本:apache-tomcat-7.0.26前言:FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出.FreeMarker与Web容器无关,即在Web运行时,它并不知道Servlet或HTTP.它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java 等.簡而言之,Freemarker就是在Jave Web開發

  • java、freemarker保留两位小数

     一.Java保留2位小数 double acc = 22.4322; String accX = String.format("%.2f", acc); 二.freemarker保留两位小数 <#if centerFreeSize??> ${centerFreeSize?string("#.##")} <#else> 0.00 </#if> 补充:freemarker保留小数 freemarker保留两位小数 方法一 #{num

  • Java模版引擎Freemarker

    FreeMarker是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯Java编写 FreeMarker被设计用来生成HTML Web页面,特别是基于MVC模式的应用程序 虽然FreeMarker具有一些编程的能力,但通常由Java程序准备要显示的数据,由FreeMarker生成页面,通过模板显示准备的数据(如下图) FreeMarker不是一个Web应用框架,而适合作为Web应用框架一个组件 FreeMarker与容器无关,因为它并不知道HTTP或Servlet:FreeMarker同

  • 使用Java进行FreeMarker的web模板开发的基础教程

    一.概述 FreeMarker 是一个模板引擎,一个基于模板生成文本输出的通用工具,使用纯 Java 编写,FreeMarker 被设计用来生成 HTML Web 页面,特别是基于 MVC 模式的应用程序,虽然 FreeMarker 具有一些编程的能力,但通常由 Java 程序准备要显示的数据,由FreeMarker 生成页面,通过模板显示准备的数据(如下图) FreeMarker 不是一个 Web 应用框架,而适合作为 Web 应用框架一个组件.FreeMarker 与容器无关,因为它并不知道

  • 微信小程序开发入门基础教程

    微信小程序开发入门基础教程 本文档将带你一步步创建完成一个微信小程序,并可以在手机上体验该小程序的实际效果. 开发准备工作获取微信小程序的 AppID 登录 https://mp.weixin.qq.com ,就可以在网站的"设置"-"开发者设置"中,查看到微信小程序的 AppID 了,注意不可直接使用服务号或订阅号的 AppID . 下载开发工具 下载地址:https://mp.weixin.qq.com/debug/wxadoc/dev/devtools/dow

  • 使用代理模式来进行C#设计模式开发的基础教程

    一.概述 在软件开发中,有些对象由于创建成本高.访问时需要与其它进程交互等原因,直接访问会造成系统速度慢.复杂度增大等问题.这时可以使用代理模式,给系统增加一层间接层,通过间接层访问对象,从而达到隐藏系统复杂性.提高系统性能的目的. 二.代理模式的详细介绍 代理模式为其他对象提供一种代理以控制对这个对象的访问.其结构图如下: Subject定义了RealSubject和Proxy共用的接口,使得在任何使用RealSubject的地方都可以使用Proxy RealSubject定义了Proxy所代

  • Java Web十条开发实用小知识

     1.${ctx}与 ${pageContext.request.contextPath}这两个为一个意思,都是获取当前根目录. 不同的是${ctx}为${pageContext.request.contextPath}的简写版,经查证之后果真如此,发现在项目的一个文件内有这样一段话 的配置 复制代码 代码如下: <c:setvar="ctx"value="${pageContext.request.contextPath}"/> 注意在使用${ctx的

  • 在Java中FreeMarker 模板来定义字符串模板

    目录 问题描述 代码实现 问题总结 问题描述 一个业务需求,需要在后端通过代码渲染一个,列表如下图所示(下图只是一个示意): 这个表格的特点就是数据重复比较多,结构简单,我们可以通过 Java 代码直接拼字符串.但是这样的问题就会导致,代码非常的难看.在 Java 代码中混杂着很多样式代码,可读性和可维护性比较差.所以我就 pass 着这个方案. 于是我就想到,通过模板 + 参数的方式来实现,这样可以做到结构和参数的分离,经过比较我选择了通过 FreeMarker 模板来定义结构,最终完成字符串

  • Java通过Freemarker模板实现生成Word文件

    目录 1.  准备模板 2.  代码实现 3. PDF文件加水印 1.  准备模板 模板 + 数据 = 模型 1.将准备好的Word模板文件另存为.xml文件(PS:建议使用WPS来创建Word文件,不建议用Office) 2.将.xml文件重命名为.ftl文件 3.用文本编辑器打开.ftl文件,将内容复制出来,格式化一下,再覆盖原来的内容 (PS:格式化一下是为了方便查找并设置变量/占位符,当然设置好模板参数变量以后可以再压缩后再写会.ftl文件) 另外,强烈不建议在word文件中去编辑设置模

  • Java使用Freemarker页面静态化生成的实现

    目录 前言: 1. Freemarker介绍 2.创建模板文件 3.生成文件 4. Freemarker指令 4.1.assign指令 4.2.include指令 4.3.if指令 4.4.list指令 5.实际项目中使用Freemarker 5.1.在数据变更的业务逻辑层中定义模板消息 5.2.配置文件 5.3.生成静态页面 前言: 页面静态化其实就是将原来的动态网页(例如通过ajax请求动态获取数据库中的数据并展示的网页)改为通过静态化技术生成的静态网页,这样用户在访问网页时,服务器直接给用

  • SpringBoot中web模板渲染的实现

    目录 模板 Model Model中添加对象 日期格式化 模板 开发Web站点的本质,其实就是根据浏览器发起的请求(输入),生成HTML代码返回给浏览器(输出).在之前的学习中,我们已经通过文件的形式存储起来而不是直接在Java代码中生成HTML代码.另一方面,博客站点是动态的,即不同的请求返回的内容可能不同.但是对于同一类请求,例如访问id分别为1和2的两篇文章,对应的URL分别为/blogs/1和/blogs/2,他们返回的HTML代码片段的结构几乎是一样的: <!DOCTYPE html>

  • Web前端开发工具——bower依赖包管理工具

    Bower 是 twitter 推出的一款包管理工具,基于nodejs的模块化思想,把功能分散到各个模块中,让模块和模块之间存在联系,通过 Bower 来管理模块间的这种联系. 包管理工具一般有以下的功能: a)注册机制:每个包需要确定一个唯一的 ID 使得搜索和下载的时候能够正确匹配,所以包管理工具需要维护注册信息,可以依赖其他平台. b)文件存储:确定文件存放的位置,下载的时候可以找到,当然这个地址在网络上是可访问的. c)上传下载:这是工具的主要功能,能提高包使用的便利性.比如想用 jqu

随机推荐