FreeMarker


一. FreeMarker

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

模板编写为FreeMarker Template Language (FTL)。它是简单的,专用的语言。 要准备数据在真实编程语言中来显示,比如数据库查询和业务运算, 之后模板显示已经准备好的数据。在模板中,可以专注于如何展现数据, 而在模板之外可以专注于要展示什么数据。

1

这种方式通常被称为 MVC (模型 视图 控制器) 模式,对于动态网页来说,是一种特别流行的模式。

它帮助从开发人员(Java 程序员)中分离出网页设计师(HTML设计师)。设计师无需面对模板中的复杂逻辑, 在没有程序员来修改或重新编译代码时,也可以修改页面的样式。

其它类似的java模板引擎还有Jsp、Thymeleaf 、Velocity 等。

二. 案例入门

freemarker作为springmvc一种视图格式,默认情况下SpringMVC支持freemarker视图格式。

此处创建Spring Boot+Freemarker工程用于测试模板。

代码demo:点击下载

环境搭建,运行

创建一个maven工程:

1)pom.xml内导入依赖

<?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>com.xsh</groupId>
    <artifactId>FreeMarker</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    </dependencies>

</project>

2)在resources目录下新建application.yml文件和templates目录。

freemarker默认会取templates目录下的文件,取其它的名字将会扫描不到。

application.yml:

server:
  port: 8088 #服务端口

spring:
  application:
    name: test-freemarker #指定服务名
  freemarker:
    cache: false  #关闭模板缓存,方便测试
    settings:
      template_update_delay: 0 #检查模板更新延迟时间,设置为0表示立即检查,如果时间大于0会有缓存不方便进行模板测试

3)创建测试实体类Student

package com.xsh.model;

import java.util.Date;
import java.util.List;

/**
 * @author : xsh
 * @create : 2020-06-23 - 22:26
 * @describe:
 */
public class Student {
    private String name;//姓名
    private int age;//年龄
    private Date birthday;//生日
    private Float mondy;//钱包
    private List<Student> friends;//朋友列表
    private Student bestFriend;//最好的朋友

   //此处已省略getter setter toString方法
}

在templates文件内新建test1.ftl文件,.ftl后缀名为freemarker模板文件,即FreeMarker Template Language

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hello World!</title>
</head>
<body>
	Hello ${name}!
</body>
</html>

4)创建controller

package com.xsh.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.Map;

/**
 * @author : xsh
 * @create : 2020-06-23 - 22:33
 * @describe:
 */
@Controller
public class FreeMarkerController {

    @RequestMapping("/test1")
    public String test1(Map<String,Object> map){
        //map作为形参,里面的数据最终会作为request域响应给用户;
        //freemarker会渲染map内的数据
        map.put("name","xsh");
        return "test1";
    }
}

5)创建springBoot启动类

@SpringBootApplication
public class FreemarkerTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(FreemarkerTestApplication.class,args);
    }
}

运行项目,访问http://localhost:8088/test1

三. 常用数据渲染

controller内返回数据准备:(返回增加了list和map类型)

package com.xsh.controller;

import com.xsh.model.Student;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.*;

/**
 * @author : xsh
 * @create : 2020-06-23 - 22:33
 * @describe:
 */
@Controller
public class FreeMarkerController {

    @RequestMapping("/test1")
    public String test1(Map<String,Object> map){
        //map作为形参,里面的数据最终会作为request域响应给用户;
        //freemarker会渲染map内的数据
        map.put("name","xsh");


        Student stu1 = new Student();
        stu1.setName("小明");
        stu1.setAge(18);
        stu1.setMondy(1000.86f);
        stu1.setBirthday(new Date());
        
        Student stu2 = new Student();
        stu2.setName("小红");
        stu2.setMondy(200.1f);
        stu2.setAge(19);
        
        List<Student> friends = new ArrayList<>();
        friends.add(stu1);
        stu2.setFriends(friends);
        stu2.setBestFriend(stu1);
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        //向数据模型放数据
        map.put("stus",stus);
        
        //准备map数据
        HashMap<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);
        
        map.put("stu1",stu1);
        map.put("stuMap",stuMap);

        //返回freemarket模板的位置,基于resources/templates路径内
        return "test1";
    }
}

2.1 渲染list

<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stus as stu>
        <tr>
            <td>${stu_index + 1}</td>
            <td >${stu.name}</td>
            <td>${stu.age}</td>
            <td >${stu.mondy}</td>
        </tr>
    </#list>
</table>
  • 使用#list指令渲染list集合数据
  • 插值表达式${...}渲染具体的值
  • __index:得到循环的下标,使用方法是在stu后边加"_index",它的值是从0开始

2.2 渲染map

-----渲染map数据方式一:在中括号中填写map的key--------<br/>
输出stu1的学生信息:<br/>
姓名:${stuMap['stu1'].name}<br/>
年龄:${stuMap['stu1'].age}<br/>
-----渲染map数据方式二: 在map后面直接.key--------<br/>
输出stu1的学生信息:<br/>
姓名:${stuMap.stu1.name}<br/>
年龄:${stuMap.stu1.age}<br/>
-----渲染map数据方式三--------<br/>
输出stu1的学生信息:<br/>
姓名:${stu1.name}<br/>
年龄:${stu1.age}<br/>
<hr>

遍历map

<table>
    <tr>
        <td>序号</td>
        <td>姓名</td>
        <td>年龄</td>
        <td>钱包</td>
    </tr>
    <#list stuMap?keys as k>
        <tr>
            <td>${k_index + 1}</td>
            <td>${stuMap[k].name}</td>
            <td>${stuMap[k].age}</td>
            <td>${stuMap[k].mondy}</td>
        </tr>
    </#list>
</table>
  • stuMap指定要遍历的map元素名字
  • ?keys表示遍历stuMap中的每一个key,并通过as k将key值赋予给k
  • k_index获取索引,从0开始

2.3 if指令与运算符

if 指令即判断指令,是常用的FTL指令,freemarker在解析时遇到if会进行判断,条件为真则输出if中间的内容,否则跳过内容不再输出。

    <#list stus as stu>
        <tr>
            <td>${stu_index + 1}</td>
            <td <#if stu.name =='小明'>style="background:red;"</#if>>${stu.name}</td>
            <td>${stu.age}</td>
            <td <#if stu.mondy gt 300>style="background:green;"</#if>>${stu.mondy}</td>
        </tr>
    </#list>

因为 FreeMarker会把>解释成FTL标签的结束字符,所以可以使用括号来避免这种情况,如:<#if (x>y)>,也可以使用比较运算符gt

  • 算数运算符

FreeMarker表达式中完全支持算术运算,FreeMarker支持的算术运算符包括:+, - , * , / , %

  • 逻辑运算符

逻辑运算符有如下几个: 逻辑与:&& ,逻辑或:|| ,逻辑非:! ,逻辑运算符只能作用于布尔值,否则将产生错误

  • 比较运算符

表达式中支持的比较运算符有如下几个:

1)=或者== : 判断两个值是否相等.

2)!= : 判断两个值是否不等.

3)> 或者gt : 判断左边值是否大于右边值

4)>=或者gte : 判断左边值是否大于等于右边值

5)<或者lt : 判断左边值是否小于右边值

6) <=或者lte : 判断左边值是否小于等于右边值

2.4 空值处理

因为freemarker模板内,当一个模板内一个渲染的数据为空时,将会报错。

所以可以判断某变量是否存在使用, “??” 用法为:variable??,如果该变量存在,返回true,否则返回false。

例:为防止stus为空报错可以加上判断如下:

<#if stus??> 
    <#list stus as stu>
    ......

    </#list>
</#if>

使用 “!” 可以为变量指定为空时的默认值,当变量为空时则显示默认值。

例: ${name!' '}表示如果name为空显示空字符串。

如果是嵌套对象则建议使用()括起来。

例: ${(stu.bestFriend.name)!' '}表示,如果stu或bestFriend或name为空默认显示空字符串。

2.5 内建函数

内建函数语法格式: 变量+?+函数名称

  • 获取某个集合的大小

    ${集合名?size}
    
  • 日期格式化

    显示年月日: ${today?date} 
    显示时分秒:${today?time}
    显示日期+时间:${today?datetime} <br>
    自定义格式化: ${today?string("yyyy年MM月")}
    
    
  • 函数 c

    可以在后端使用map.put("point", 102920122);存放一个数值。

    point是数字型,使用${point}会显示这个数字的值,并每三位使用逗号分隔。

    如果不想显示为每三位分隔的数字,可以使用c函数将数字型转成字符串输出,${point?c}

  • 将json字符串转成对象

    其中用到了 assign标签,assign的作用是定义一个变量。

    <br/>
    <#assign text="{'bank':'工商银行','account':'10101920201920212'}" />
    <#assign data=text?eval />
    开户行:${data.bank} 账号:${data.account}
    <hr>
    
    • 通过#assign text定义一个json字符串
    • #assign data=text?eval获取字符串的值并赋予给data
    • ${data.bank} 渲染json字符串的值定元素

四. 页面静态化

Freemarker提供了3种加载模板目录的方法。 它使用Configuration类加载模板。

三种方法分别是:

public void setClassForTemplateLoading(Class clazz, String pathPrefix);

public void setDirectoryForTemplateLoading(File dir) throws IOException;

public void setServletContextForTemplateLoading(Object servletContext, String path);

第一种:基于类路径,HttpWeb包下的framemaker.ftl文件

configuration.setClassForTemplateLoading(this.getClass(), "/HttpWeb");

configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板 

第二种:基于文件系统

configuration.setDirectoryForTemplateLoading(new File("/template"))

configuration.getTemplate("framemaker.ftl"); //framemaker.ftl为要装载的模板

第三种:基于Servlet Context,指的是基于WebRoot下的template下的framemaker.ftl文件

HttpServletRequest request = ServletActionContext.getRequest();

configuration.setServletContextForTemplateLoading(request.getSession().getServletContext(), "/template");

configuration.getTemplate("framemaker.ftl"); 

在访问新闻、活动、商品、详情页面的时候,路径可以是xx【id】.html,服务器端根据请求id,动态生成html网页,下次访问数据时,无需再查下数据,直接将html静态页面返回。可以减少对数据库的交互,提高访问的性能。

//将数据模型抽取成一个方法,实际使用中为数据库查询出来的值
private Map getMap() {
    Map<String, Object> map = new HashMap<>();
    //向数据模型放数据
    map.put("name", "xsh");
    Student stu1 = new Student();
    stu1.setName("小明");
    stu1.setAge(18);
    stu1.setMondy(1000.86f);
    stu1.setBirthday(new Date());
    Student stu2 = new Student();
    stu2.setName("小红");
    stu2.setMondy(200.1f);
    stu2.setAge(19);

    List<Student> friends = new ArrayList<>();
    friends.add(stu1);
    stu2.setFriends(friends);
    stu2.setBestFriend(stu1);
    List<Student> stus = new ArrayList<>();
    stus.add(stu1);
    stus.add(stu2);
    //向数据模型放数据
    map.put("stus", stus);
    //准备map数据
    HashMap<String, Student> stuMap = new HashMap<>();
    stuMap.put("stu1", stu1);
    stuMap.put("stu2", stu2);
    //向数据模型放数据
    map.put("stu1", stu1);
    //向数据模型放数据
    map.put("stuMap", stuMap);
    return map;
}

4.1 基于模板文件静态化

    @Test
    public void testGenerateHtml() throws Exception {
        //定义配置类
        Configuration configuration=new Configuration(Configuration.getVersion());
       //得到classpath路径,即模板存放路径
        String classpath = this.getClass().getResource("/").getPath();
        //定义模板路径
        configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));
        //获取模板文件内容
        Template template = configuration.getTemplate("test1.ftl");
        //定义数据模型
        Map map = getMap();
        //静态化
        String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
        System.out.println(content);

        InputStream inputStream = IOUtils.toInputStream(content);
        FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/test1.html"));//静态文件输出目录
        //输出文件
        IOUtils.copy(inputStream,fileOutputStream);
    }

4.2 基于模板字符串静态化

//基于模板文件的内容(字符串)生成html文件
@Test
public void testGenerateHtmlByString() throws Exception{
    //创建配置类
    Configuration configuration=new Configuration(Configuration.getVersion());
    //获取模板内容
    //模板内容,这里测试时使用简单的字符串作为模板
    String templateString="" +
            "<html>\n" +
            "    <head></head>\n" +
            "    <body>\n" +
            "    名称:${name}\n" +
            "    </body>\n" +
            "</html>";

    //加载模板
    //模板加载器
    StringTemplateLoader stringTemplateLoader = new StringTemplateLoader();
    stringTemplateLoader.putTemplate("template",templateString);
    configuration.setTemplateLoader(stringTemplateLoader);
    Template template = configuration.getTemplate("template","utf-8");

    //数据模型
    Map map = getMap();
    //静态化
    String content = FreeMarkerTemplateUtils.processTemplateIntoString(template, map);
    //静态化内容
    System.out.println(content);
    InputStream inputStream = IOUtils.toInputStream(content);
    //输出文件
    FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/test1.html"));
    IOUtils.copy(inputStream, fileOutputStream);
}

五. 代码生成器

实现获取数据库内所有表和字段名,并自动生成实体类文件

模板文件javabean.ftl,用于生成java实体类文件

package ${packageName};
import java.util.Date;
public class ${className}{

<#-- 循环类型及属性 -->
<#list attrs as attr>
     private ${attr.type} ${attr.name}; //${attr.remarks}
</#list>

<#-- 循环生成set get方法 -->
<#list attrs as attr>
     public void set${attr.name}(${attr.type} ${attr.name}) {
      this.${attr.name} = ${attr.name};
     }
     public ${attr.type} get${attr.name}() {
      return ${attr.name};
     }
</#list>
}

5.1 Freemarker加载类

package com.xsh.util;

import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.File;

/**
 * @author : xsh
 * @create : 2020-06-25 - 14:57
 * @describe: Freemarker加载类
 *  项目不要存放在带有中文目录的文件夹下
 *  否则获取classpath路径时会因为有中文名而乱码,获取不到文件,抛出java.io.FileNotFoundException异常
 */
public class FreeMarkerInit {

    private static FreeMarkerInit single= new FreeMarkerInit();
    private FreeMarkerInit() {}
    //静态工厂方法
    public static FreeMarkerInit getInstance() {
        return single;
    }

    public Template getDefinedTemplate(String templateName) throws Exception{
        //配置类
        Configuration configuration = new Configuration(Configuration.getVersion());
        //得到classpath路径,即模板存放路径
        String classpath = this.getClass().getResource("/").getPath();
        //定义模板路径
        configuration.setDirectoryForTemplateLoading(new File(classpath+"/templates/"));
        configuration.setDefaultEncoding("UTF-8");
        configuration.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        return configuration.getTemplate(templateName);
    }
}

5.2 获取字段信息

package com.xsh.util;

import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : xsh
 * @create : 2020-06-25 - 15:00
 * @describe: 连接数据库获取元信息,得到表名,列信息。
 */
public class MetadataUtil {
    private static Connection conn;
    private static DatabaseMetaData meta;

    static {
        try {
            Class.forName("com.mysql.jdbc.Driver");
        }catch (ClassNotFoundException e){
            e.printStackTrace();
            System.out.println("数据库连接失败!,请检查数据库服务是否开启与依赖是否导入");
        }
    }
    public static void openConnection(){
        try {
            if (conn==null||conn.isClosed()){
                conn= DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/test",
                        "root","123456");
                meta=conn.getMetaData();
            }
        }catch (SQLException e){
            e.printStackTrace();
        }
    }
    //获取注解
    public static  String getCommentByTableName(String tableName) throws Exception{
        openConnection();
        Statement stmt=conn.createStatement();
        ResultSet rs=stmt.executeQuery("SHOW CREATE TABLE "+tableName);
        String comment=null;
        if (rs!=null&&rs.next()){
            comment=rs.getString(2);
        }
        rs.close();
        stmt.close();
        conn.close();
        return comment;
    }

    //获取所有表名称
    public static List<String> getTableNames(){
        openConnection();
        ResultSet rs=null;
        List<String> nameList=new ArrayList<>();
        try {
            rs=meta.getTables(null,null,null,new String[]{"TABLE"});
            while (rs.next()){
                String tName=rs.getString("TABLE_NAME");
                nameList.add(tName);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return  nameList;
    }

    /**
     * 列信息数组的集合。List中每个元素是一个数组,代表一个列的信息;
     * 每个数组的元素1是列名,元素2是注释,元素3是类型
     * @return
     */
    public static List<String[]> getTableColumnsInfo(String tableName) throws  Exception{
        openConnection();
        ResultSet rs=meta.getColumns(null,"%",tableName,"%");
        List<String[]> columnInfoList=new ArrayList<>();
        while (rs.next()){
            String[] colInfo=new  String[3];
            colInfo[0] =rs.getString("COLUMN_NAME");
            colInfo[1] =rs.getString("REMARKS");
            colInfo[2] =rs.getString("TYPE_NAME");
            columnInfoList.add(colInfo);
        }
        return columnInfoList;
    }


    public static DatabaseMetaData getMeta() {
        return meta;
    }

    public static void setMeta(DatabaseMetaData meta) {
        MetadataUtil.meta = meta;
    }

    public static Connection getConn() {
        return conn;
    }

    public static void setConn(Connection conn) {
        MetadataUtil.conn = conn;
    }
}

5.3 命名修改

从数据库直接获取的表名,列信息不符合java的命名规范,如驼峰命名法,所以需要对获取的表名和字段名进行名字转换

package com.xsh.util;

/**
 * @author : xsh
 * @create : 2020-06-25 - 15:01
 * @describe:
 * 驼峰命名:第一个单词以小写字母开始;第二个单词的首字母大写或每一个单词的首字母都采用大写字母
 * 帕斯卡命名法:每个单词都大写,常用于类名,函数名,属性,命名空间。
 */
public class JavaNameUtil {

    public static void main(String[] args) {
        String str="imagines_age_name";
        String javaname1 = JavaNameUtil.toPascal(str);
        String javaname2 = JavaNameUtil.toCamel(str);
        System.out.println("帕斯卡命名:"+javaname1);
        System.out.println("驼峰命名转换:"+javaname2);
    }


    /**
     * 将数据库(表、字段)转换以java命名方式帕斯卡或者驼峰
     * @param unberscoreName
     * @param isPascal     是否将首字母转化大写,true则转化为驼峰命名,false则转换为帕斯卡命名
     * @return 驼峰或帕斯卡命名字符串
     */
    public static String translate(String unberscoreName, boolean isPascal) {
        StringBuilder result = new StringBuilder();
        //从第一个字母
        if (unberscoreName != null && unberscoreName.length() !=0) {
            boolean flag = false;
            char firstChar = unberscoreName.charAt(0);  //得到首字母
            if (isPascal) {
                result.append(Character.toUpperCase(firstChar));
            } else {
                result.append(firstChar);
            }
            //从第二个字母以后开始
            for (int i = 1, length = unberscoreName.length(); i < length; i++) {
                char ch = unberscoreName.charAt(i);
                if ('_' == ch) {
                    flag = true;
                } else {
                    if (flag) { //标记上一个是下划线,就转化为大写。
                        result.append(Character.toUpperCase(ch));
                        flag = false;
                    } else {
                        result.append(ch);
                    }
                }
            }
        }
        return result.toString();
    }

    /**
     * 调用translate() 转换为帕斯卡命名
     * @param unberscoreName 数据库(表名、字段名)
     * @return
     */
    public static String toPascal(String unberscoreName) {
        return translate(unberscoreName, true);
    }

    /**
     * 调用translate() 转换为驼峰命名
     * @param unberscoreName 数据库(表名、字段名)
     * @return
     */
    public static String toCamel(String unberscoreName) {
        return translate(unberscoreName, false);
    }

    /**
     *
     * 将获取数据库类型转化为java类型
     * @param dbTypeName 实际的数据库类型
     * @return
     */
    public static String dbTypeChangeJavaType(String dbTypeName){
        String javaType=null;
        switch(dbTypeName){
            case "VARCHAR" :javaType="String";break;
            case "BIGINT" :javaType="Long";break;
            case "INT" :javaType="Integer";break;
            case "DATETIME" :javaType="Date";break;
            default:javaType="String";break;
        }
        return javaType;
    }
}

Attribute.java:用于存放从数据库获取的字段类型,字段名字,字段备注

package com.xsh.model;

/**
 * @author : xsh
 * @create : 2020-06-25 - 15:11
 * @describe: 
 */
public class Attribute {
    private String type;//类型
    private String name;//名字
    private String remarks;//备注

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getName() {
        return name;
    }

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

    public String getRemarks() {
        return remarks;
    }

    public void setRemarks(String remarks) {
        this.remarks = remarks;
    }

    public Attribute() {
    }

    public Attribute(String type, String name, String remarks) {
        this.type = type;
        this.name = name;
        this.remarks = remarks;
    }
}

5.4 测试类

package com.xsh;

import com.xsh.model.Attribute;
import com.xsh.util.FreeMarkerInit;
import com.xsh.util.JavaNameUtil;
import com.xsh.util.MetadataUtil;
import freemarker.template.Template;

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

/**
 * @author : xsh
 * @create : 2020-06-25 - 14:30
 * @describe: 根据数据库内字段名,自动生成java实体类
 */
public class CreateJavaTemplateTest {
    //生成java实体类
    public void createBean() throws Exception{
        //获取项目根目录
        String basicPath=System.getProperty("user.dir");
        //文件最终生成路径
        String savePath=basicPath+"\\FreeMarker\\src\\main\\java\\com\\xsh\\pojo";
        //判断文件夹是否存在,不存在则创建文件夹
        File file=new File(savePath);
        if(!file.exists()){
            throw new Exception("文件夹不存在,请检查路径是否存在:"+savePath);
        }

        //获取模板
        Template temp = FreeMarkerInit.getInstance().getDefinedTemplate("javabean.ftl");
        //获取表名集合
        List<String> strs= MetadataUtil.getTableNames();
        for (String str1: strs
        ) {
            //Attribute里面封装模板使用属性
            List<String[]> strList=MetadataUtil.getTableColumnsInfo(str1);
            List<Attribute> attr_list = new ArrayList<Attribute>();
            for (String[] c:strList
            ) {
                attr_list.add(new Attribute(JavaNameUtil.dbTypeChangeJavaType(c[2]), JavaNameUtil.toCamel(c[0]),c[1]));
            }

            //转换为帕斯卡命名
            String str=JavaNameUtil.toPascal(str1);

            Map<String, Object> root = new HashMap<String, Object>();
            root.put("packageName", "com.xsh.pojo");//包名
            root.put("className", str);//实体类文件名,即数据库表名
            root.put("attrs", attr_list);
            OutputStream fos = new FileOutputStream( new File(savePath, str+".java"));
            Writer out = new OutputStreamWriter(fos);
            temp.process(root, out);
            fos.flush();
            fos.close();
        }
    }

    public static void main(String[] args) {
        CreateJavaTemplateTest test = new CreateJavaTemplateTest();
        try {
            test.createBean();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

5.5 运行测试类

运行测试类,pojo文件夹下根据数据库内表名自动生成实体类

数据库test:

代码demo:点击下载

springBoot
Freemarker
  • 作者:管理员(联系作者)
  • 发表时间:2020-06-25 16:18
  • 版权声明:自由转载-非商用-非衍生-保持署名(null)
  • undefined
  • 评论