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

一、概述

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进行集成使用,每次都需要在解析的时候把解析类的实例放进去。。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
, web
, freemarker
模板
javaweb freemarker、javaweb前台页面模板、java web网站模板、javaweb模板、java web网站模板下载,以便于您获取更多的相关知识。

时间: 2025-01-26 22:46:54

使用Java进行FreeMarker的web模板开发的基础教程_java的相关文章

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

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

Windows下Java+MyBatis框架+MySQL的开发环境搭建教程_java

MyBatis是一个Java持久化框架,它通过XML描述符或注解把对象与存储过程或SQL语句关联起来. MyBatis是在Apache许可证 2.0下分发的自由软件,是iBATIS 3.0的分支版本.其维护团队也包含iBATIS的初创成员. 与其他的对象关系映射框架不同,MyBatis并没有将Java对象与数据库表关联起来,而是将Java方法与SQL语句关联.MyBatis允许用户充分利用数据库的各种功能,例如存储过程.视图.各种复杂的查询以及某数据库的专有特性.如果要对遗留数据库.不规范的数据

Java的Hibernate框架结合MySQL的入门学习教程_java

零.关于HibernateHibernate是冬眠的意思,它是指动物的冬眠,但是本文讨论的Hibernate却与冬眠毫无关系,而是接下来要讨论的SSH2框架中的一员.Hibernate是一个开源的项目,它是一个对象关系模型的框架,并且对JDBC进行了非常轻量级的封装,程序员在开发时可以使用对象编程思维进行开发. 下载地址:http://hibernate.org/orm/downloads/ Note:轻量级和重量级的区别,轻量级的框架包较小,并且使用较简单,而且测试容易,开发效率高:重量级框架

Java的Hibernate框架中的继承映射学习教程_java

一.继承映射继承是面向对象很重要的特性,它实现了代码的服用,在关系模型中同样也有继承关系,这种继承关系其实可以看做是一种枚举关系,一种类型中可以枚举出很多子类型,这些子类型和父对象形成了继承关系,能够对其进行枚举的大部分都可以看做是一种继承映射,所以这种枚举关系可以看做是继承映射,例如动物就是一种抽象类,它是其它动物猪.猫等的父类,它们之间就是一种继承关系,如下图: 这种继承映射在转化为关系模型后会生成一张表,那么这张表是如何区分这两种类型的呢?用的是关系字段,需要在表中添加类型字段,使用关键字

java程序打包成exe与jar的图文教程_java

Java程序打包 1.java工程源码打包成jar包 选中工程,右键选择export... 选择Runnable JAR file (1)launch configuration 启动配置,java程序的启动类,如果工程没有生成类,先执行"选中工程--run as---Java Application " (2)Export Destination 输出文件名称,要生成的jar文件 2.jar包转换成.exe 使用exe4j4.0将jar生成exe执行文件 破解的exe4j4.0可在下

Java的Hibernate框架中的组合映射学习教程_java

一.组合映射组合是关联关系的一种特殊情况,是关联关系耦合度最高的一种关系,组合的主对象和子对象拥有相同的生命周期,主对像消亡的话子对象也会消亡.这里使用雇主和用户作为示例,用户和雇主都拥有联系方式属性,如果这里站在对象角度思考的话,常常会把对象模型绘制成为组合的方式,抽象出来一个共同的联系方式类,然后两种人分别包含相应的联系方式对象即可,向应的对象模型时它的对象示例如下图所示: 组合对象模型在生成相应的关系模型后会把对应的子类包含到主表中,所以对应的表结构会将相应的属性生成到对应的表中,相应的表

GSON实现Java对象的JSON序列化与反序列化的实例教程_java

从GitHub下载GSON:https://github.com/google/gson Gson的应用主要为toJson与fromJson两个转换函数,而在使用这种对象转换之前需先创建好对象的类别以及其成员才能成功的将JSON字符串成功转换成相对应的对象. class Examples { private int answer1 = 100; private String answer2 = "Hello world!"; Examples(){ } // default const

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

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

Velocity 为 Java Web 应用开发“增速”

web 一.模板引擎有什么用? 简单地说,模板引擎的作用就是取得数据并加以处理,最后显示出数据.例如,假设有一个企业职工的清单,我们可以用模板引擎将它以HTML页面的形式显示在企业的Intranet上,或简化后显示在管理员的手机上.使用模板引擎的好处就在于开发者和设计者能够以最合适的方式操作和利用数据,Velocity就是一个模板引擎的绝佳范例.Velocity的英文含义是"速度.流通速度.速率:迅速,快速",也许它的作者希望Velocity能够提高人们开发Web应用的速度吧. Vel