1. 程式人生 > >利用FreeMarker生成java原始碼

利用FreeMarker生成java原始碼

一 FreeMarker簡介

Apache FreeMarker is a template engine: a Java library to generate
text output (HTML web pages, e-mails, configuration files, source
code, etc.) based on templates and changing data. Templates are
written in the FreeMarker Template Language (FTL), which is a simple,
specialized language (not a full-blown programming language like PHP).
You meant to prepare the data to display in a real programming
language, like issue database queries and do business calculations,
and then the template displays that already prepared data. In the
template you are focusing on how to present the data, and outside the
template you are focusing on what data to present.

這裡寫圖片描述

This approach is often referred to as the MVC (Model View Controller)
pattern, and is particularly popular for dynamic Web pages. It helps
in separating the Web page designers (HTML authors) from the
developers (Java programmers usually). Designers won’t face
complicated logic in templates, and can change the appearance of a
page without programmers having to change or recompile code.

While FreeMarker was originally created for generating HTML pages in
MVC web application frameworks, it isn’t bound to servlets or HTML or
anything Web-related. It’s used in non-web application environments as
well.

模板就是把共性(固定不變的)的東西提取出來反覆使用,節約時間 提高開發效率。現在主流的模板技術包括:FreeMarker和Velocity,模板技術推崇一種模式:輸出=模板+資料。
FreeMarker最開始被MVC Web框架用來生成HTML頁面,但它的用途不僅限於HTML或者Web領域,比如本文所要介紹的生成JavaBean原始碼。

二 生成JavaBean原始碼

本文中將使用Freemarker 生成Person.java類程式碼,如下:

package com.ricky.java;

import java.util.List;

/**
 *  @author Ricky Fung
 */
public class Person {
    private Long id;
    private String name;
    private Integer age;
    private List<String> hobby;

    public void setId(Long id){
        this.id = id;
    }
    public Long getId(){
        return this.id;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return this.name;
    }

    public void setAge(Integer age){
        this.age = age;
    }
    public Integer getAge(){
        return this.age;
    }

    public void setHobby(List<String> hobby){
        this.hobby = hobby;
    }
    public List<String> getHobby(){
        return this.hobby;
    }

}

2.1 引入Freemarker 依賴

<dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>

2.2 Freemarker 模板檔案 person.ftl

package ${packageName};

import java.util.List;

/**
 *  @author ${author}
 */
public class ${className} {
    <#list attrs as attr> 
    private ${attr.type} ${attr.name};
    </#list>

    <#list attrs as attr>
    public void set${attr.name?cap_first}(${attr.type} ${attr.name}){
        this.${attr.name} = ${attr.name};
    }
    public ${attr.type} get${attr.name?cap_first}(){
        return this.${attr.name};
    }

    </#list>
}

2.3 Create a configuration instance

Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        cfg.setDirectoryForTemplateLoading(templateDir);    
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

2.4 Create a data-model
1)In simple cases you can build data-models using java.lang and java.util classes and custom JavaBeans:

  • Use java.lang.String for strings.
  • Use java.lang.Number descents for numbers.
  • Use java.lang.Boolean for boolean values.
  • Use java.util.List or Java arrays for sequences.
  • Use java.util.Map for hashes.
  • Use your custom bean class for hashes where the items correspond to
    the bean properties. For example the price property (getProperty())
    of product can be get as product.price. (The actions of the beans can
    be exposed as well; see much later here)

2)程式碼構建資料模型

Map<String, Object> root = new HashMap<String, Object>();

        root.put("packageName", "com.ricky.java");
        root.put("className", "Person");
        root.put("author", "Ricky Fung");

        List<Attribute> attr_list = new ArrayList<Attribute>();
        attr_list.add(new Attribute("id", "Long"));
        attr_list.add(new Attribute("name", "String"));
        attr_list.add(new Attribute("age", "Integer"));
        attr_list.add(new Attribute("hobby", "List<String>"));

        root.put("attrs", attr_list);

2.5 獲取指定模板

Template temp = cfg.getTemplate("person.ftl");

此時,會在E:/Work/Freemarker/templates目錄下查詢person.ftl。

2.6 用資料渲染模板

Writer out = new OutputStreamWriter(System.out);
temp.process(root, out);

如果需要將結果序列化到硬碟上,可以使用下面程式碼:

File dir = new File("E:/Work/Freemarker/src/");
        if(!dir.exists()){
            dir.mkdirs();
        }
        OutputStream fos = new  FileOutputStream( new File(dir, "Person.java")); //java檔案的生成目錄   
        Writer out = new OutputStreamWriter(fos);
        temp.process(root, out);

        fos.flush();  
        fos.close();

最後,貼上CodeGenerator.java完整的程式碼

package com.ricky.spring.springdemo.freemarker;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
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.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

public class CodeGenerator {

    public static void main(String[] args) {

        try {
            new CodeGenerator().gen();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (TemplateException e) {
            e.printStackTrace();
        }
    }

    public void gen() throws IOException, TemplateException{

        Configuration cfg = new Configuration(Configuration.VERSION_2_3_22);
        cfg.setDirectoryForTemplateLoading(new File("E:/Work/Freemarker/templates"));   
        cfg.setDefaultEncoding("UTF-8");
        cfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);

        Template temp = cfg.getTemplate("person.ftl");  // load E:/Work/Freemarker/templates/person.ftl

        // Create the root hash
        Map<String, Object> root = new HashMap<String, Object>();

        root.put("packageName", "com.ricky.java");
        root.put("className", "Person");
        root.put("author", "Ricky Fung");

        List<Attribute> attr_list = new ArrayList<Attribute>();
        attr_list.add(new Attribute("id", "Long"));
        attr_list.add(new Attribute("name", "String"));
        attr_list.add(new Attribute("age", "Integer"));
        attr_list.add(new Attribute("hobby", "List<String>"));

        root.put("attrs", attr_list);

//      Writer out = new OutputStreamWriter(System.out);
//      Writer out = new OutputStreamWriter(System.out);
        File dir = new File("E:/Work/Freemarker/src/");
        if(!dir.exists()){
            dir.mkdirs();
        }
        OutputStream fos = new  FileOutputStream( new File(dir, "Person.java")); //java檔案的生成目錄   
        Writer out = new OutputStreamWriter(fos);
        temp.process(root, out);

        fos.flush();  
        fos.close();

        System.out.println("gen code success!");
    }
}