写点什么

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

  • 2022 年 9 月 13 日
    北京
  • 本文字数:3039 字

    阅读完需:约 10 分钟

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

系列文章:

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


一 前言

上一篇文章简单介绍了工程的初始化方法,本篇将探索代码生成技术。因为业务开发中使用 Java 语言较多,所以这里以 Java 作为背景语言。

大家熟知并且日常都在使用 Spring/SpringMVC/SpringBoot、Mybatis 框架,在开发中我们经常需要手写 Entity、Mapper、dao、service、controller 相关代码,这些重复性的工作会占用很多工作时间。如果有一个代码生成工具来做这些重复工作,显然可以提高我们的工作效率。这时,就需要了解模板引擎技术。

二 模板引擎工具:freemarker 与 velocity

最早接触的是 velocity,记得 14,15 年左右,当时在某家公司开发的前端页面,就是使用 velocity 作为模板引擎。创建前端页面的 vm/tpl 模板后,利用 velocity 提供的能力,编写脚本生成静态页面,然后再走上线更新。

除了 velocity 之外,freemarker 也是一款模板引擎,使用 FreeMarker Template Language(FTL)编写,它是一种简单的、专用的语言。

关于二者(有时也会包括 thymeleaf)的对比,已经有一些文章进行了分析,这里不再赘述,感兴趣的朋友可以搜索,或在评论中留言一起探讨。这里基于以前的一些调研工作,选择 freemarker 作为这里使用的模板引擎,用于示例。

三 freemarker 介绍

freemarker 的基础介绍,可以参考 freemarker 在线手册,中文版地址:http://freemarker.foofun.cn/

简单来说,FreeMarker 是一款 模板引擎: 即一种基于模板和要改变的数据, 并用来生成输出文本(HTML 网页,电子邮件,配置文件,源代码等)的通用工具。 它不是面向最终用户的,而是一个 Java 类库,是一款程序员可以嵌入他们所开发产品的组件。

freemarker 的几个关键概念:模板(template)、Java 对象(Java Object)、输出(Output),三者含义和关系可通过下图体现:



(1)其中,template 是我们要使用的模板,基于这个模板来生成文件。简单来说,就是一些固定模式(代码/标签/逻辑)+变量的组合,其中变量在后面根据需要,替换成所需的值;

(2)Java Object 是模型/对象,可以简单理解为一些 key-value 对,key 是变量名称,value 就是变量的值;

(3)Output 是输出结果,在把 template 中的变量替换成 object 中的 value 后,就得到了我们预期的文件。

而替换的动作,就是由 freemarker 来实现的。

四 示例

4.1 工程结构

这里采用 maven 工程,idea 创建,工程目录结构如下:

4.2 依赖包引入-pom

<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0"         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId> <artifactId>template-engine</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging>
<dependencies> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.23</version> </dependency> </dependencies>
<build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.0.2</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> <finalName>${project.artifactId}</finalName> </build></project>
复制代码

4.3 自定义 freemark 模板

这里预期是生成一个 Java 类,如下所示,是一个典型的 bean,包括几个属性和对应的 get/set 方法,几个变量: packageName-包名,className-类名,属性:id, userName, password

package ${packageName};
public class ${className} {
private Integer ${id};
private String ${userName};
private String ${password};
public Integer get${id?cap_first}(){ return ${id}; }
public void set${id?cap_first}(Integer ${id}){ this.${id}=${id}; }
public String get${userName?cap_first}(){ return ${userName}; }
public void set${userName?cap_first}(String ${userName}){ this.${userName}=${userName}; }
public String get${password?cap_first}(){ return ${password}; }
public void set${password?cap_first}(String ${password}){ this.${password}=${password}; }}
复制代码

4.4 定义生成代码方法

package com.freemark.demo.templates.util;
import freemarker.template.Configuration;import freemarker.template.Template;
import java.io.*;import java.util.HashMap;import java.util.Map;
public class FreemarkTest {
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"); dataMap.put("id", "id"); dataMap.put("userName", "userName"); dataMap.put("password","password");
// 加载模版文件 Template template = configuration.getTemplate("test.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(); } } }}
复制代码

我们运行 main 方法,可以看到控制台会打印出 Test.java 源码生成成功! 并在 src/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; }}
复制代码


发布于: 刚刚阅读数: 4
用户头像

磨炼中成长,痛苦中前行 2017.10.22 加入

微信公众号【程序员架构进阶】。多年项目实践,架构设计经验。曲折中向前,分享经验和教训

评论

发布
暂无评论
低代码探索:Java模板引擎技术_低代码_程序员架构进阶_InfoQ写作社区