前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >低代码探索:freemarker的模板和表达式

低代码探索:freemarker的模板和表达式

作者头像
程序员架构进阶
发布2022-12-01 15:46:40
1.3K0
发布2022-12-01 15:46:40
举报
文章被收录于专栏:架构进阶架构进阶

系列文章:

Mavan:自定义骨架及工程初始化

低代码探索:Java 模板引擎技术

一 概述

在低代码探索:Java 模板引擎技术 中,我们介绍了freemarker的概念和简单使用示例。本篇会详细介绍一下freemarker中的表达式,这在使用时很重要。我们通过模板定义要生成的页面框架,通过表达式来实现参数占位/替换,输入变量的首字母大/小写转换,以及for循环遍历等等。通过模板与表达式的配合,生成所需的页面/代码文件。

二 模板

关于模板的介绍,可以先看看freemarker在线手册的内容。FTL (即FreeMarker template language),就是freemarker为编写模板设计的非常简单的编程语言。

2.1 FTL介绍

模板(FTL编程)是由如下部分混合而成的:

  • 文本:文本会照着原样来输出。
  • 插值:这部分的输出会被计算的值来替换,相当于模板中的“变量”。插值由 ${ and } 所分隔(或者 #{ and },这种风格已经不建议再使用了,使用 number_format 设置项 和 the string 内建函数 来代替。对于计算机使用 (也就非本地的格式化)的格式化,使用 c 内建函数 (比如 number?c)。)。例如,我们有两个变量x和y,x=2.582y=4,那么常用的插值表达式和对应的取值如下面所示:
代码语言:javascript
复制
#{x}       <#-- 2.582 -->
#{y}       <#-- 4 -->
#{x; M2}   <#-- 2.58 -->
#{y; M2}   <#-- 4    -->
#{x; m1}   <#-- 2.6 -->
#{y; m1}   <#-- 4.0 -->
#{x; m1M2} <#-- 2.58 -->
#{y; m1M2} <#-- 4.0  -->
  • FTL 标签:FTL标签和HTML标签很相似,但是它们却是给FreeMarker的指示, 而且不会打印在输出内容中。
  • 注释:注释和HTML的注释也很相似,但它们是由 <#---->来分隔的。注释会被FreeMarker直接忽略, 更不会在输出内容中显示。

2.2 模板示例

下面是手册中提供的一个HTML页面的模板示例:其中,蓝色代表文本,橘黄色代表插值(${user}),黄色代表FTL标签(<#list animals ...),而绿色是注释, [BR]是为了在页面上显式可见的换行:

FTL有几点注意事项需要特别指出:

1、FTL区分大小写,例如 list 是指令的名称,而List不是(切记!),{name} 和 {Name} 或

2、插值 仅仅可以在 文本(或字符串表达式)中使用。

3、FTL 标签 不可以在其他 FTL 标签 和 插值中使用。比如, 这样做是 错误 的: <#if <#include 'foo'>='bar'>...</#if>

4、注释 可以放在 FTL 标签 和 插值中。示例:

代码语言:javascript
复制
<h1>Welcome ${user <#-- The name of user -->}!</h1>[BR]
<p>We have these animals:[BR]
<ul>[BR]
<#list <#-- some comment... --> animals as <#-- again... --> animal>[BR]
...

2.3 指令

FTL的指令是通过标签来调用,例如上面用到的<#list animals as animal>,使用到了list这个指令,代表遍历list中的每个变量。除了list之外,常用的还有<#if>

FTL的指令有两种类型: 预定义指令 和 用户自定义指令。详细说明可以参见链接,这里不再赘述,有疑问可以共同探讨。

2.4 表达式

FTL的表达式主要包括 直接确定值(字符串、数字、布尔值、序列、值域、哈希表)、检索变量、字符串操作、序列操作、哈希表操作等等。在定义模板时,使用最多的是直接确定值(字符串、数字),其次是检索变量和字符串操作。

检索变量示例:我们在外层定义好一个user对象,包含name, age等属性,那么在模板中应用时,可以通过 ${user.name}, ${user.age}来获取对应的值并替换到模板中对应的位置;

字符串操作示例:字符串连接:"Hello ${user}!" ;获取一个字符:name[0];字符串切分: 包含结尾: name[0..4],不包含结尾: name[0..<5],基于长度(宽容处理): name[0..*5],去除开头: name[5..]

2.5 插值

插值是用来给 表达式 插入具体值然后转换为文本(字符串)。用我们更熟悉的表述,就是模板中的占位符,用来标记某个位置是一个变量,在生成代码时,可以通过传入我们定义好的值,模板进行识别并完成替换,从而生成我们最终想要的文件。

插值的使用格式: {expression},这里的 expression 可以是所有种类的表达式(比如 {100 + x})。

完整的示例和说明还是推荐查看手册:插值。

三 模板使用和生成示例

接下来,我们还是通过demo来阐述freemarker模板定义到生成文件的整个过程,jar包的引入方式在低代码探索:Java 模板引擎技术中已经有过说明,这里只列举模板和代码部分。

3.1 模板定义

test.java.ftl:

代码语言:javascript
复制
package ${packageName};

public class ${className} {

<#if colList??>
<#list colList as col>
    private ${col.type} ${col.name};

</#list>

<#list colList as col>
    public ${col.type} get${col.name?cap_first}(){
        return ${col.name};
    }

    public void set${col.name?cap_first}(${col.type} ${col.name}){
        this.${col.name}=${col.name};
    }
</#list>
</#if>
}

这个模板定义了一个典型的实体类,也就是POJO。属性列表我们通过colList参数传入,并在外层加了if 的判断,避免参数为空的情况;对于list中的每个变量,都是一个col对象,里面有type 和 name两个属性,上述模板先逐个生成 private Integer id; xxx 这些字段,然后再依次生成对应的getId setId。。。 方法。

因为get set方法需要的是变量名的首字母大写,所以这里还使用了 get${col.name?cap_first}来对首字母进行大写处理。

3.2 column实体类定义

代码语言:javascript
复制
package com.freemark.demo.entity;

import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class Column {
  private String type;
  private String name;
}

Column用于封装参数,有type和name两个属性。 这里为了简化代码 引入了lombok,在pom.xml中增加相关依赖引入即可:

代码语言:javascript
复制
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.22</version>
</dependency>

3.3 生成代码方法

主要就是完成参数封装,模板加载和生成方法与上一篇内容相似。

代码语言:javascript
复制
package com.freemark.demo.templates.util;

import com.freemark.demo.entity.Column;
import freemarker.template.Configuration;
import freemarker.template.Template;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class FreemarkerTest {

  private static final String TEMPLATE_PATH = "src/main/java/com/freemark/demo/templates";

  private static final String CLASS_PATH = "src/main/java/com/freemark/demo";

  public static void main(String[] args) {
    // 创建freeMarker配置实例
    Configuration configuration = new Configuration();
    Writer out = null;
    try {

      // 设置模版路径
      configuration.setDirectoryForTemplateLoading(new File(TEMPLATE_PATH));
      // 创建数据模型
      Map<String, Object> dataMap = new HashMap<>();
      dataMap.put("packageName", "com.freemark.demo");
      dataMap.put("className", "Test");

      List<Column> columnList = new ArrayList<>();
      Column idCol = Column.builder().type("Integer").name("id").build();
      Column userNameCol = Column.builder().type("String").name("userName").build();
      Column passwordCol = Column.builder().type("String").name("password").build();
      columnList.add(idCol);
      columnList.add(userNameCol);
      columnList.add(passwordCol);
      dataMap.put("colList", columnList);

      // 加载模版文件
      Template template = configuration.getTemplate("test.java.ftl");

      // 生成文件流
      File docFile = new File(CLASS_PATH + "/" + "Test.java");
      out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(docFile)));

      // 输出到文件
      template.process(dataMap, out);
      System.out.println("Test.java 源码生成成功!");
    } catch (Exception e) {
      e.printStackTrace();
    } finally {
      try {
        if (null != out) {
          out.flush();
        }
      } catch (Exception e2) {
        e2.printStackTrace();
      }
    }
  }
}
我们执行FreemarkerTest的main方法,生成Test.java文件如下:
package com.freemark.demo;

public class Test {

    private Integer id;

    private String userName;

    private String password;


    public Integer getId(){
        return id;
    }

    public void setId(Integer id){
        this.id=id;
    }
    public String getUserName(){
        return userName;
    }

    public void setUserName(String userName){
        this.userName=userName;
    }
    public String getPassword(){
        return password;
    }

    public void setPassword(String password){
        this.password=password;
    }
}

四 总结

本篇对freemarker进行了深入一些的描述,并对上一篇的示例做了部分调整,使用了list、if等表达式、指令、插值这些freemarker的概念。

完整工程代码,可关注公众号回复freemarker引擎获取。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员架构进阶 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一 概述
  • 二 模板
    • 2.1 FTL介绍
      • 2.2 模板示例
        • 2.3 指令
          • 2.4 表达式
            • 2.5 插值
            • 三 模板使用和生成示例
              • 3.1 模板定义
                • 3.2 column实体类定义
                  • 3.3 生成代码方法
                  • 四 总结
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档