自己模拟的ftl 用法:

 基类

public class Ftl_object_data_model  {
     //三种基本属性
     private boolean canRead=true;//是否能读取
     private int length=2;//长度
     private String content;//内容
     //内部小vo对象属性
     private Ftl_object_data_model_inner fi = new Ftl_object_data_model_inner();
 
     //非属性内部方法1
     public boolean isCanWrite() {
         return true;
     }
     //非属性内部方法2
     public boolean canSend() {
         return true;
     }
 
 
     public boolean isCanRead() {
         return canRead;
     }
 
     public void setCanRead(boolean canRead) {
         this.canRead = canRead;
     }
 
     public int getLength() {
         return length;
     }
 
     public void setLength(int length) {
         this.length = length;
     }
 
     public String getContent() {
         return content;
     }
 
     public void setContent(String content) {
         this.content = content;
     }
 
     public Ftl_object_data_model_inner getFi() {
         return fi;
     }
 
     public void setFi(Ftl_object_data_model_inner fi) {
         this.fi = fi;
     }
 
 //    @Override
 //    public Object exec(List arg0) throws TemplateModelException {
 //        return new SimpleNumber(((SimpleScalar)arg0.get(1)).getAsString().indexOf(((SimpleScalar)arg0.get(0)).getAsString()));
 //    }
 //    public TemplateModel exec(List arg0) throws TemplateModelException {
 //        return new SimpleNumber(((String)arg0.get(1)).indexOf((String)arg0.get(0)));
 //    }
 }
 
 基类中小vo 的类

public class Ftl_object_data_model_inner {
     private boolean canRead=true;//是否能读取
     private int length;//长度
     private String content;//内容
 
     public boolean isCanRead() {
         return canRead;
     }
 
     public void setCanRead(boolean canRead) {
         this.canRead = canRead;
     }
 
     public int getLength() {
         return length;
     }
 
     public void setLength(int length) {
         this.length = length;
     }
 
     public String getContent() {
         return content;
     }
 
     public void setContent(String content) {
         this.content = content;
     }
 }
 
 main启动测试类

public class FtlTest {
     public static void main(String[] args) throws IOException {
         Configuration cfg = new Configuration();
         cfg.setDirectoryForTemplateLoading(new File("F:\king\proj\TKCard\TKCard_cn_cn_Server\src\test\java\general\ftl_test"));
 //        cfg.setObjectWrapper(ObjectWrapper.DEFAULT_WRAPPER);
         cfg.setObjectWrapper(new DefaultObjectWrapper());
         cfg.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
 
         //生成数据模型
         //用map封装的数据模型
 //        Object root = testMapDataModel();
         //直接用对象封装的数据模型
         Object root = testObjectDataModel();
         // 通过freemarker解释模板,首先需要获得Template对象
         //用map封装的数据模型对应的模板
 //        Template template = cfg.getTemplate(testMapDataModelTemplate());
         //直接用对象封装的数据模型对应的模板
         Template template = cfg.getTemplate(testObjectDataModelTemplate());
 
         // 定义模板解释完成之后的输出
         //PrintWriter out = new PrintWriter(new BufferedWriter( new FileWriter(dir+"/out.txt")));
         //直接控制台打印
         OutputStreamWriter out = new OutputStreamWriter(System.out);
         try {
             // 解释模板
             template.process(root, out);
         } catch (TemplateException e) {
             e.printStackTrace();
         }
     }
 
     /**
      * 测试用map封装的数据模型
      * @return
      */
     public static Object testMapDataModel(){
         Map root = new HashMap();
         root.put("name1", "世界,你好");//模板里需要几个值,这边数据模型里就必须要塞几个值,缺一个就会报错(多塞不会报错),因为freeworker 不支持null,所以少塞会报错
         root.put("name2", "我is大开发建设领导看风景");
         root.put("name3", new Ftl_object_data_model());//如果传的是方法则上边map类型的数据模型的map只能去掉泛型了,不能用key为value皆为string的泛型了
         return root;
     }
     /**
      * 测试用map封装的数据模型对应的数据模板
      * @return
      */
     public static String testMapDataModelTemplate(){
         return "ftl_map_data_model.ftl";
     }
 
     /**
      * 测试用vo对象封装的数据模型
      * @return
      */
     public static Object testObjectDataModel() {
         Ftl_object_data_model fm = new Ftl_object_data_model();
         return fm;
     }
     /**
      * 测试用vo对象封装的数据模型对应的数据模板
      * @return
      */
     public static String testObjectDataModelTemplate(){
         return "ftl_object_data_model.ftl";
     }
 }
 
 数据模板

---------------------------------------- 一、-------------------------------------
 
 <#-- 一、整个vo对象直接作为数据模型数据的基类Ftl_object_data_model 对象中的属性拿取方式-->
 <#--基础属性直接拿取,无需带上对象变量(由于这边无需变量名,所以此基类变量名既不是root又不是fm)-->
 <#--${root.length}  错误的写法,无需带root-->
 <#--${fm.length}  错误的写法,无需带fm-->
 <#--基类属性读取直接拿即可,其他属性一样,包括方法,直接拿取-->
 ${length}
 <#--由于ftl一般都以字符串形式打印,所以Boolean类型的读取要特殊处理-->
 <#--${canRead} 内部Boolean类型属性错误读取-->
 <#--${canread} 内部Boolean类型属性错误读取-->
 <#--${isCanRead()} 内部Boolean类型属性错误读取-->
 <#--Boolean类型正确读写 固定格式 var?c -->
 <#--boolean第一种读取,结果打印true or false-->
 ${canRead?c}
 <#--Boolean第二种读取,结果打印yes or no  当canRead为真则取第一个参数值即yes,否则取第二个参数no-->
 ${canRead?string('yes','no')}
 <#--非属性 的 Boolean类型get方法读取,即这个get方法拿的不是对象的属性,而仅仅是类中一个返回值为Boolean类型的方法-->
 方法1:<#--${CanWrite()?c} 拿对象中非属性内部方法1错误拿法-->
 方法1:<#--${canWrite()?c} 拿对象中非属性内部方法1错误拿法-->
 方法1:<#--${canwrite()?c} 拿对象中非属性内部方法1错误拿法-->
 方法1:<#--<#if CanWrite >true</#if> 拿对象中非属性内部方法1错误拿法-->
 方法1:<#--<#if canwrite >true</#if> 拿对象中非属性内部方法1错误拿法-->
 
 方法1:${isCanWrite()?c} <#-- 拿对象中非属性内部方法1正确拿法1-->
 方法1:<#if isCanWrite() >true</#if> <#--拿对象中非属性内部方法1正确拿法-->
 方法1:<#if canWrite >true</#if> <#--拿对象中非属性内部方法1正确拿法,这种方法是一种特殊的拿取方式,必须是在严格的is打头的get方法时才有用-->
 
 方法2:<#--${cansend()?c} 拿对象中非属性内部方法2错误拿法-->
 方法2:<#--<#if canSend >true</#if> 拿对象中非属性内部方法2错误拿法-->
 方法2:<#--<#if cansend >true</#if> 拿对象中非属性内部方法2错误拿法-->
 
 方法2:${canSend()?c} <#-- 拿对象中非属性内部方法2正确拿法1-->
 方法2:<#if canSend() >true</#if> <#--拿对象中非属性内部方法2正确拿法-->
 
 ---------------------------------------- 二、-------------------------------------
 
 <#-- 二、整个vo对象直接作为数据模型数据的基类Ftl_object_data_model 对象中的子类属性 小vo对象中的属性拿取方式-->
 <#--直接用小vo 被new 时的变量名.属性  或 .方法即可 拿取  方式和直接拿基类中的属性一样的-->
 ${fi.length}
 ${fi.isCanRead()?c}
 <#if fi.isCanRead() >true</#if>
 <#if fi.canRead >true</#if>
 
 
 <#--
 
 注:几个重要的语法规则:
 
 1、FreeMarker的插值有如下两种类型:1,通用插值${expr};2,数字格式化插值:#{expr}或#{expr;format}
 2、??:判断某个变量是否存在,返回boolean值 类似  var?if_exists
 3var!xxx:指定缺失变量的默认值 类似 var?default(xxx) 而 ${!var?c}表明非var,即当var为真时结果求假,!此表非含义
 4、使用lt、lte、gt和gte来替代<、<=、>和>= 也可以使用括号<#if (x>y)>
 5、内置函数: 调用区别于属性的访问,属性访问用.访问,而内置函数用?访问如var?if_exists
 6、注意${}为变量的渲染显示,而<>为定义等操作符的定义
 7、对于库中的变量修改,使用in关键字 <#assign mail="jsmith@other.com" in my>
 8、stringA[M .. N] 取子字符串,类似substring(stringA, M, N)
 9、List片段可以采用: products[10..19] or products[5..] 的格式进行定义,当只局限于数字
     <#assign c= [1,2,3,4,5,6,6,7]>
     <#list c[1..3] as v>
         ${v}
     </#list>
 10、freemarker可用"["代替"<".在模板的文件开头加上[#ftl].
 11、注释语法   <#-- 注释部分 -->
                                                                       <#--  由于杀念11注释语法破坏了整体的注释,所以这边由加了个注释头标签
 12、 数字输出的另外一种方式  #{c.a;m0} 区别于${x},这个例子是用于输出数字的格式化,保留小数的位数,详细如下
         数字格式化插值可采用#{expr;m1M2}形式来格式化数字,其中: m1:小数部分最小1位 M2:小数部分最大2位 即大小m代表不同含义
 13、在定义字符串的时候,可以使用''或者"",对特殊字符,需要使用进行转义
 14、如果存在大量特殊字符,可以使用${r"..."}进行过滤 如  ${r"${foo}"}     ${r"C:fooar"}
 15、Map对象的key和value都是表达式,但是key必须是字符串 可以混合使用.和[""]访问 book.author["name"] //混合使用点语法和方括号语法
 16、为了处理缺失变量,FreeMarker提供了两个运算符: 用于防止对象不存在而导致的异常 !:指定缺失变量的默认值 ??:判断某个变量是否存在,返回boolean值
 17、noparse指令指定FreeMarker不处理该指定里包含的内容,该指令的语法格式如下: <#noparse>...</#noparse>
 18、?html 用于将字符串中可能包含的html字符,进行过滤.
     ${firstName?html} 使用?html对html字符进行过滤、格式化处理 escape , noescape指令,对body内的内容实用统一的表达式
         看如下的代码:
         <#escape x as x?html>
                 First name:${firstName}
                 Last name:${lastName}
                 Maiden name:${maidenName}
         </#escape>
         上面的代码等同于:
         First name:${firstName?html}
         Last name:${lastName?html}
         Maiden name:${maidenName?html}
 19、<#assign name1=value1 name2=value2 / > 可以同时定义多个变量
     也可以使用循环来给变量赋值
     <#assign x>
         <#list ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期天"] as n>
             n:${n}
         </#list>
     </#assign>
     x:${x}
 
     执行结果:
     x:
     n:星期一
     n:星期二
     n:星期三
     n:星期四
     n:星期五
     n:星期六
     n:星期天
     说明:不是先打印n:${n}的循环值,而是先打印 x:${x}的值。含义就是先定义一个x,x的内容为 循环list,每次循环渲染显示的内容
         n:${n} 的值 为x中的一个元素,全部循环完,x的值也组装完了,结果打印显示x:${x}。记住不是说list为x中的list,即不是为x注入一个list(这
         就是为啥最后打印x时前边都有n:而不是和原list内容一样的原因,表明此list不是x中的属性,即此list和x没什么关系,此仅借用一下list机制而已),
         而是通过list机制 进行循环得出临时值作为x的元素。
 20、setting指令,用于动态设置freeMarker的运行环境:
     该指令用于设置FreeMarker的运行环境,该指令的语法格式如下:<#setting name=value>,在这个格式中,name的取值范围包含如下几个:
     locale:该选项指定该模板所用的国家/语言选项
     number_format:指定格式化输出数字的格式
     boolean_format:指定两个布尔值的语法格式,默认值是true,false
     date_format,time_format,datetime_format:指定格式化输出日期的格式
     time_zone:设置格式化输出日期时所使用的时区
 21、<#return> 用于退出宏的运行
 22、调用Java方法:
     如:
     public class A implements TemplateMethodModelEx{
         @Override
         public Object exec(List arg0) throws TemplateModelException {
             return new SimpleNumber(((SimpleScalar)arg0.get(1)).getAsString().indexOf(((SimpleScalar)arg0.get(0)).getAsString()));
         }
         或
         public TemplateModel exec(List arg0) throws TemplateModelException {
             return new SimpleNumber(((String)arg0.get(1)).indexOf((String)arg0.get(0)));
         }
     }
     封装数据模型时用map模型(如果用vo对象模型的话可能需要vo中有个map,此map的效果等同于直接用map模型),直接 map.put("method",new A()); method可以任意变量名
     由于此要put一个对象,所以此map模型用到的map就不能用Map<String,String>了,即不用带泛型,用 Map root = new HashMap();
     下边就是到模板了,模板里表达式格式为:<#assign x = "something">  ${method("met",x)} 即先定义一个变量x,然后调用表达式method("met",x),此表达式传2个
     参数,当解析模板执行到此表达式时会将此表达式的2个参数直接传到A类中的exec方法中的参数,exec方法参数为list,那模板中传几个参数都是以String类型或
     SimpleScalar(ftl包装string用的对象,可以调用getAsString()得到string内容)类型直接传到exec的参数list中的,传几个过来就都封装到这个list中,exec执行
     结果返回给模板 ${结果} 渲染显示出来。
 
     说明:调用Java方法时需要java类实现TemplateMethodModel 或 TemplateMethodModelEx接口,但是好像会覆盖掉属性的访问,即这个类中的其他属性可能就没法访问了(这个是否能访问没测过)
     即要调用的java方法所在类 必须实现TemplateMethodModel接口,即实现 exec方法 即 public TemplateModel exec(List arg0) throws TemplateModelException
     或 public Object exec(List list) throws TemplateModelException 方法。
     在模板解析时模板中调用表达式时会立即调用到java类中的上边实现的exec方法,exec方法返回值  返回给 模板中表达式处 渲染显示出来。
 
 -->
原文地址:https://www.cnblogs.com/wzhanke/p/4776240.html