基于freemarker构建专属代码生成器——代码生成器的底层原理

一、我们为什么要构建自己的代码生成器

通常来讲,在Java开发中最基本的也是占用我们最大量事件的就是CRUD,也就是频繁地构造“实体类”、“dao层代码”以及相关的service层和controller层的代码。其实,这一部分工作,可以使用代码生成器来完成,节约时间,免于加班

二、一般代码生成器的底层原理

其实,包括mybatis代码生成器在内的所有代码生成器,其底层原理都是大差不差的,基本都是:

  1. 首先,写一个代码模板
  2. 然后,在模板中插入变量
  3. 最后,将变量替换为我们想要插入的值

经过这样的三步走,最终就是我们的想要生成的目标代码
当然,我们可以使用循环,判断等逻辑表达生成更加复杂,通用性更好的模板。

三、简单的例子——freemarker

下面,我们以freemarker为例,生成一个简单的代码模板。

准备工作

首先构建了一个自己的spring boot的maven工程

然后再pom里面引入了freemarker的依赖

<!-- 引入模板引擎freemarker -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
        </dependency>
1. 写一个代码模板

我们下一个生成Java的模板最简单的模板(HelloWorld.java)

public class HelloWorld{
	public void sayHelloToWorld(){
		System.out.println("Hello, world");
	}
}
2. 在模板中需要替换的地方中插入变量

这里就要用到,我们的freemarker引擎了,我们需要将刚刚的代码复制到Hello.ftl文件中,然后将World和world提出按成变量(注意这里区分大小写)

public class Hello${Domain}{
	public void sayHelloTo${Domain}(){
		System.out.println("Hello, ${domain}");
	}
}

在上面我们用 D o m a i n 替换了 W o r l d , {Domain}替换了World, Domain替换了World{domain}替换了world
不同的地方使用不同的变量

3. 将变量替换,生成我们自己的代码

实现代码替换生成文件,需要做三步:

第一步:读模板

读模板这里,freemarker有规范的写法,如下:

/**
  * 读模板
  */
 public static Template readTemplate(String ftlName, String ftlPath) throws IOException { // 这里的ftlName就是模板的路径
     Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
     cfg.setDirectoryForTemplateLoading(new File(ftlPath)); // 
     cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_31));
     Template template = cfg.getTemplate(ftlName);
     return template;
 }
第二步和第三步:将变量填进去,并输出出来
/**
  * 根据模板,生成文件
  */
public static void generator(Template template, String fileName, Map<String, Object> map) throws IOException, TemplateException {
   FileWriter fw = new FileWriter(fileName); // 输出的文件地址
   BufferedWriter bw = new BufferedWriter(fw); // 构建一个输入流
   template.process(map, bw); // 将map中的数据输入到template中
   bw.flush(); // 关闭输入流
   fw.close(); // 关闭文件
}
完整的代码应该是:
package com.liangyi.train.generator.test;

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

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class ServerGeneratorTest {

    public static void main(String[] args) {
        String ftlName = "Hello.ftl";
        String ftlPath = "generator/src/main/java/com/liangyi/train/generator/test"; // 这里的地址是从项目的根目录下开始算的,比如我这里项目根目录下有个文件夹generator
        String fileName = "generator/src/main/java/com/liangyi/train/generator/test/HelloTeacher.java"; // 这里的地址是从项目的根目录下开始算的
        HashMap<String, Object> map = new HashMap<>();
        map.put("Domain", "Teacher");
        map.put("domain", "teacher");

        try{
            Template template = readTemplate(ftlName, ftlPath);
            generator(template, fileName, map);
        }catch (Exception e){
            System.out.println(e.getMessage());
        }


    }

    /**
     * 读模板
     * @param ftlName
     * @param ftlPath
     * @return
     * @throws IOException
     */
    public static Template readTemplate(String ftlName, String ftlPath) throws IOException { // 这里的ftlName就是模板的路径
        Configuration cfg = new Configuration(Configuration.VERSION_2_3_31);
        cfg.setDirectoryForTemplateLoading(new File(ftlPath)); // 设置模板文件的加载目录
        cfg.setObjectWrapper(new DefaultObjectWrapper(Configuration.VERSION_2_3_31));
        Template template = cfg.getTemplate(ftlName); // 从加载目录中加载文件名为ftlName指向的模板文件
        return template;
    }

    /**
     * 向文件中写入变量的值,并生长新文件
     * @param template
     * @param fileName
     * @param map
     * @throws IOException
     * @throws TemplateException
     * @throws TemplateException
     */
    public static void generator(Template template, String fileName, Map<String, Object> map) throws IOException, TemplateException, TemplateException {
        FileWriter fw = new FileWriter(fileName); // 输出的文件地址
        BufferedWriter bw = new BufferedWriter(fw); // 构建一个输入流
        template.process(map, bw); // 将map中的数据输入到template中
        bw.flush(); // 关闭输入流
        fw.close(); // 关闭文件
    }
}

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值