首頁技術(shù)文章正文

Java培訓(xùn):自定義代碼生成器

更新時(shí)間:2022-11-14 來源:黑馬程序員 瀏覽量:

  1 概述

  1.1 介紹

   在項(xiàng)目開發(fā)過程中,有很多業(yè)務(wù)模塊的代碼是具有一定規(guī)律性的,例如controller控制器、service接口、service實(shí)現(xiàn)類、mapper接口、model實(shí)體類等等,這部分代碼可以使用代碼生成器生成,我們就可以將更多的時(shí)間放在業(yè)務(wù)邏輯上。

  傳統(tǒng)的開發(fā)步驟:

   創(chuàng)建數(shù)據(jù)庫(kù)和表

   根據(jù)表設(shè)計(jì)實(shí)體類

   編寫mapper接口

   編寫service接口和實(shí)現(xiàn)類

   編寫controller控制器

   編寫前端頁面

   前后端聯(lián)調(diào)

  基于代碼生成器開發(fā)步驟:

   創(chuàng)建數(shù)據(jù)庫(kù)和表

   使用代碼生成器生成實(shí)體類、mapper、service、controller、前端頁面

   將生成好的代碼拷貝到項(xiàng)目中并做調(diào)整

   前后端聯(lián)調(diào)

  我們只需要知道數(shù)據(jù)庫(kù)和表相關(guān)信息,就可以結(jié)合模版生成各個(gè)模塊的代碼,減少了很多重復(fù)工作,也減少出錯(cuò)概率,提高效率。

  1.2 實(shí)現(xiàn)思路

1668403951598_1.jpg

  (1)需要對(duì)數(shù)據(jù)庫(kù)表解析獲取到元數(shù)據(jù),包含表字段名稱、字段類型等等。

  (2)將通用的代碼編寫成模版文件,部分?jǐn)?shù)據(jù)需使用占位符替換。

  (3)將元數(shù)據(jù)和模版文件結(jié)合,使用一些模版引擎工具(例如freemarker)即可生成源代碼文件。

  2 Freemarker

  2.1 介紹

   FreeMarker 是一款 模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來生成輸出文本(HTML網(wǎng)頁,電子郵件,配置文件,源代碼等)的通用工具。 它不是面向最終用戶的,而是一個(gè)Java類庫(kù),是一款程序員可以嵌入他們所開發(fā)產(chǎn)品的組件。

   模板編寫為FreeMarker Template Language (FTL)。它是簡(jiǎn)單的,專用的語言, 在模板中,你可以專注于如何展現(xiàn)數(shù)據(jù), 而在模板之外可以專注于要展示什么數(shù)據(jù)。

1668403984945_2.jpg

  2.2 應(yīng)用場(chǎng)景

  (1)動(dòng)態(tài)頁面

  freemarker可以作為springmvc一種視圖格式,像jsp一樣被瀏覽器訪問。

  (2)頁面靜態(tài)化

  對(duì)于一些內(nèi)容比較多,更新頻率很小,訪問又很頻繁的頁面,可以使用freemarker靜態(tài)化,減少DB的壓力,提高頁面打開速度。

  (3)代碼生成器

  根據(jù)配置生成頁面和代碼,減少重復(fù)工作,提高開發(fā)效率。

  2.3 快速入門

  (1)創(chuàng)建freemarker-demo模塊,并導(dǎo)入相關(guān)依賴

<?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.itheima</groupId>
    <artifactId>freemarker-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
    </parent>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <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>
        <!-- freemarker -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <!-- lombok -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

  (2)application.yml相關(guān)配置

server:
  port: 8881 #服務(wù)端口
spring:
  application:
    name: freemarker-demo #指定服務(wù)名
  freemarker:
    cache: false #關(guān)閉模板緩存,方便測(cè)試
    settings:
      template_update_delay: 0 #檢查模板更新延遲時(shí)間,設(shè)置為0表示立即檢查,如果時(shí)間大于0會(huì)有緩存不方便進(jìn)行模板測(cè)試
    suffix: .ftl #指定Freemarker模板文件的后綴名

  (3)創(chuàng)建啟動(dòng)類

package com.heima.freemarker;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

  (4)創(chuàng)建Student模型類

package com.itheima.freemarker.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Student {
    private Integer id;
    private String name;//姓名
    private Integer age;//年齡
    private Date birthday;//生日
    private Float money;//錢包
}

  (5)創(chuàng)建StudentController

package com.itheima.freemarker.controller;

import com.itheima.freemarker.entity.Student;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.Date;

@Controller
@RequestMapping("student")
public class StudentController {

    @GetMapping("index")
    public String index(Model model){
        //1.純文本形式的參數(shù)
        model.addAttribute("name", "Freemarker");

        //2.實(shí)體類相關(guān)的參數(shù)
        Student student = new Student();
        student.setName("黑馬");
        student.setAge(18);
        model.addAttribute("stu", student);

        return "01-index";
    }
}

  (6)在resources/templates下創(chuàng)建01-index.ftl模版文件

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>首頁</title>
</head>
<body>
<b>普通文本 String 展示:</b><br/>
Hello ${name} <br>

<hr>
<b>對(duì)象Student中的數(shù)據(jù)展示:</b><br/>
姓名:${stu.name}<br/>
年齡:${stu.age}
<hr>
</body>
</html>

  (7)測(cè)試

  瀏覽器訪問 http://localhost:8881/student/index

  效果如下

1668404138819_3.jpg

  2.4 模版

  2.4.1 基礎(chǔ)語法種類

  (1)注釋,即<#-- -->,介于其之間的內(nèi)容會(huì)被freemarker忽略

<#--我是一個(gè)freemarker注釋-->

  (2)插值(Interpolation):即 **`${..}`** 部分,freemarker會(huì)用真實(shí)的值代替**`${..}`**

Hello ${name}

  (3)FTL指令:和HTML標(biāo)記類似,名字前加#予以區(qū)分,F(xiàn)reemarker會(huì)解析標(biāo)簽中的表達(dá)式或邏輯。

<# >FTL指令</#>

  (4)文本,僅文本信息,這些不是freemarker的注釋、插值、FTL指令的內(nèi)容會(huì)被freemarker忽略解析,直接輸出內(nèi)容。

<#--freemarker中的普通文本-->
我是一個(gè)普通的文本

  2.4.2 if指令

  if 指令即判斷指令,是常用的FTL指令,freemarker在解析時(shí)遇到if會(huì)進(jìn)行判斷,條件為真則輸出if中間的內(nèi)容,否則跳過內(nèi)容不再輸出。

  格式如下

<#if condition>
  ....
<#elseif condition2>
  ...
<#elseif condition3>   
  ...
<#else>
  ...
</#if>

  需求:根據(jù)年齡輸出所處的年齡段

  > 童年:0歲—6歲(周歲,下同)

  > 少年:7歲—17歲

  > 青年:18歲—40歲

  > 中年:41—65歲

  > 老年:66歲以后

  實(shí)例代碼:

  (1)在01-index.ftl添加如下代碼

<#if stu.age <= 6>
童年
<#elseif stu.age <= 17>
少年
<#elseif stu.age <= 40>   
青年
<#elseif stu.age <= 65>   
中年
<#else>
老年
</#if>

  (2)測(cè)試

  瀏覽器訪問http://localhost:8881/student/index

  效果如下

1668404286140_4.jpg

  2.4.3 list指令

  list指令時(shí)一個(gè)迭代輸出指令,用于迭代輸出數(shù)據(jù)模型中的集合

  格式如下

<#list items as item>
    ${item_index + 1}------${item}-----<#if item_has_next>,</#if>
</#list>

  
       迭代集合對(duì)象時(shí),包括兩個(gè)特殊的循環(huán)變量:

  (1)item_index:當(dāng)前變量的索引值。

  (2)item_has_next:是否存在下一個(gè)對(duì)象

  > item_index 和 item_has_nex 中的item為<#list items as item> 中as后面的臨時(shí)變量

  需求:遍歷學(xué)生集合,輸出序號(hào),學(xué)生id,姓名,所處的年齡段,是否最后一條數(shù)據(jù)

  (1)在StudentController中增加方法

@GetMapping("list")
public String list(Model model) throws ParseException {
    List<Student> list = new ArrayList<>();

    list.add(new Student(1001,"張飛",15, null, 1000.11F));
    list.add(new Student(1002,"劉備",28, null, 5000.3F));
    list.add(new Student(1003,"關(guān)羽",45, null, 9000.63F));
    list.add(new Student(1004,"諸葛亮",62, null, 10000.99F));
    list.add(new Student(1005,"成吉思汗",75, null, 16000.66F));
    model.addAttribute("stus",list);

    return "02-list";
}

  (2)在resources/templates目錄下創(chuàng)建02-list.ftl模版

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>列表頁面</title>
    <style>
        table{
            border-spacing: 0;/*把單元格間隙設(shè)置為0*/
            border-collapse: collapse;/*設(shè)置單元格的邊框合并為1*/
        }
        td{
            border:1px solid #ACBED1;
            text-align: center;
        }
    </style>
</head>
<body>

<table>
    <tr>
        <td>序號(hào)</td>
        <td>id</td>
        <td>姓名</td>
        <td>所處的年齡段</td>
        <td>生日</td>
        <td>錢包</td>
        <td>是否最后一條數(shù)據(jù)</td>
    </tr>
    <#list stus as stu >
        <tr>
            <td>${stu_index + 1}</td>
            <td>${stu.id}</td>
            <td>${stu.name}</td>
            <td>
                <#if stu.age <= 6>
                    童年
                <#elseif stu.age <= 17>
                    少年
                <#elseif stu.age <= 40>   
                    青年
                <#elseif stu.age <= 65>   
                    中年
                <#else>
                    老年
                </#if>
            </td>
            <td></td>
            <td>${stu.money}</td>
            <td>
                <#if stu_has_next>
                否
                <#else>
                是
                </#if>
            </td>
        </tr>
    </#list>
</table>

<hr>
</body>
</html>

  (2)測(cè)試

  瀏覽器訪問http://localhost:8881/student/list

  效果如下

1668404463221_5.jpg

  2.4.4 include指令

  include指令的作用類似于JSP的包含指令,用于包含指定頁,include指令的語法格式如下

<#include filename [options]></#include>

 
    (1)filename:該參數(shù)指定被包含的模板文件

  (2)options:該參數(shù)可以省略,指定包含時(shí)的選項(xiàng),包含encoding和parse兩個(gè)選項(xiàng),encoding

  指定包含頁面時(shí)所使用的解碼集,而parse指定被包含是否作為FTL文件來解析。如果省略了parse選項(xiàng)值,則該選項(xiàng)值默認(rèn)是true

  需求:"早上好,尊敬的 某某 用戶!" 這句話在很多頁面都有用到,請(qǐng)合理設(shè)計(jì)!

  (1)在resources/templates目錄下創(chuàng)建00-head.ftl模版,內(nèi)容如下

早上好,尊敬的 ${name} 用戶!

  (2)在resources/templates目錄下創(chuàng)建03-include.ftl模版,使用include引入00-head.ftl模版,內(nèi)容如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>詳情頁</title>
</head>
<body>

<#include "00-head.ftl" />
<br>
歡迎來到黑馬程序員。

</body>
</html>

  (3)在StudentController中增加方法

@GetMapping("include")
public String include(Model model) throws ParseException {
model.addAttribute("name", "黑馬");
return "03-include";
}

  (4)測(cè)試

  瀏覽器訪問http://localhost:8881/student/include

  效果如下

1668404643275_6.jpg

  2.4.5 assign指令

  它用于為該模板頁面創(chuàng)建或替換一個(gè)頂層變量

<#assign name = "zhangsan" />

  2.4.6 運(yùn)算符

  (1)算數(shù)運(yùn)算符

  FreeMarker表達(dá)式中完全支持算術(shù)運(yùn)算,FreeMarker支持的算術(shù)運(yùn)算符包括:

  - 加法: `+`

  - 減法: `-`

  - 乘法: `*`

  - 除法: `/`

  - 求模 (求余): `%`

  (2)比較運(yùn)算符

  - `=`或者`==`:判斷兩個(gè)值是否相等.

  - `!=`:判斷兩個(gè)值是否不等.

  - `>`或者`gt`:判斷左邊值是否大于右邊值

  - `>=`或者`gte`:判斷左邊值是否大于等于右邊值

  - `<`或者`lt`:判斷左邊值是否小于右邊值

  - `<=`或者`lte`:判斷左邊值是否小于等于右邊值

  比較運(yùn)算符注意

  - `=`和`!=`可以用于字符串、數(shù)值和日期來比較是否相等

  - `=`和`!=`兩邊必須是相同類型的值,否則會(huì)產(chǎn)生錯(cuò)誤

  - 字符串 `"x"` 、`"x "` 、`"X"`比較是不等的.因?yàn)镕reeMarker是精確比較

  - 其它的運(yùn)行符可以作用于數(shù)字和日期,但不能作用于字符串

  - 使用`gt`等字母運(yùn)算符代替`>`會(huì)有更好的效果,因?yàn)?FreeMarker會(huì)把`>`解釋成FTL標(biāo)簽的結(jié)束字符

  - 可以使用括號(hào)來避免這種情況,如:`<#if (x>y)>`

  (3)邏輯運(yùn)算符

  - 邏輯與:&&

  - 邏輯或:||

  - 邏輯非:!

  邏輯運(yùn)算符只能作用于布爾值,否則將產(chǎn)生錯(cuò)誤 。

  2.4.7 空值處理

  (1)缺失變量默認(rèn)值使用 “!”

  - 使用!要以指定一個(gè)默認(rèn)值,當(dāng)變量為空時(shí)顯示默認(rèn)值

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

  - 如果是嵌套對(duì)象則建議使用()括起來

  例: ${(stu.bestFriend.name)!''}表示,如果stu或bestFriend或name為空默認(rèn)顯示空字符串。

  (2)判斷某變量是否存在使用 “??”

  用法為:variable??,如果該變量存在,返回true,否則返回false

  例:為防止stus為空?qǐng)?bào)錯(cuò)可以加上判斷如下:

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

  2.4.8 內(nèi)建函數(shù)

  內(nèi)建函數(shù)語法格式: `變量+?+函數(shù)名稱`

  (1)求集合的大小

  `${集合名?size}`

  (2)日期格式化

  顯示年月日: `${today?date}`

  顯示時(shí)分秒:`${today?time}`

  顯示日期+時(shí)間:`${today?datetime}`

  自定義格式化: `${today?string("yyyy年MM月")}`

  (3)內(nèi)建函數(shù)`c`

  model.addAttribute("point", 102920122);

  point是數(shù)字型,使用${point}會(huì)顯示這個(gè)數(shù)字的值,每三位使用逗號(hào)分隔。

  如果不想顯示為每三位分隔的數(shù)字,可以使用c函數(shù)將數(shù)字型轉(zhuǎn)成字符串輸出

  `${point?c}`

  (4)將json字符串轉(zhuǎn)成對(duì)象

  一個(gè)例子:

  其中用到了 assign標(biāo)簽,assign的作用是定義一個(gè)變量。

<#assign text="{'bank':'工商銀行','account':'10101920201920212'}" />
<#assign data=text?eval />
開戶行:${data.bank}  賬號(hào):${data.account}

  ```

  (5)常見內(nèi)建函數(shù)匯總

?html:html字符轉(zhuǎn)義
?cap_first: 字符串的第一個(gè)字母變?yōu)榇髮懶问?
?lower_case :字符串的小寫形式
?upper_case :字符串的大寫形式
?trim:去掉字符串首尾的空格
?substring(from,to):截字符串  from是第一個(gè)字符的開始索引,to最后一個(gè)字符之后的位置索引,當(dāng)to為空時(shí),默認(rèn)的是字符串的長(zhǎng)度
?lenth: 取長(zhǎng)度
?size: 序列中元素的個(gè)數(shù)
?int: 數(shù)字的整數(shù)部分(比如 -1.9?int 就是 -1)
?replace(param1,param2):字符串替換  param1是匹配的字符串 param2是將匹配的字符替換成指定字符

  內(nèi)建函數(shù)測(cè)試demo1

  (1)在StudentController新增方法:

@GetMapping("innerFunc")
public String testInnerFunc(Model model) {
    //1.1 小強(qiáng)對(duì)象模型數(shù)據(jù)
    Student stu1 = new Student();
    stu1.setName("小強(qiáng)");
    stu1.setAge(18);
    stu1.setMoney(1000.86f);
    stu1.setBirthday(new Date());
    //1.2 小紅對(duì)象模型數(shù)據(jù)
    Student stu2 = new Student();
    stu2.setName("小紅");
    stu2.setMoney(200.1f);
    stu2.setAge(19);
    //1.3 將兩個(gè)對(duì)象模型數(shù)據(jù)存放到List集合中
    List<Student> stus = new ArrayList<>();
    stus.add(stu1);
    stus.add(stu2);
    model.addAttribute("stus", stus);
    // 2.1 添加日期
    Date date = new Date();
    model.addAttribute("today", date);
    // 3.1 添加數(shù)值
    model.addAttribute("point", 102920122);
    return "04-innerFunc";
}

  (2)在resources/templates目錄下創(chuàng)建04-innerFunc.ftl模版頁面:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>inner Function</title>
</head>
<body>

    <b>獲得集合大小</b><br>

    集合大小:${stus?size}
    <hr>


    <b>獲得日期</b><br>

    顯示年月日: ${today?date}       <br>

    顯示時(shí)分秒:${today?time}<br>

    顯示日期+時(shí)間:${today?datetime}<br>

    自定義格式化:  ${today?string("yyyy年MM月")}<br>

    <hr>

    <b>內(nèi)建函數(shù)C</b><br>
    沒有C函數(shù)顯示的數(shù)值:${point} <br>

    有C函數(shù)顯示的數(shù)值:${point?c}

    <hr>

    <b>聲明變量assign</b><br>
    <#assign text="{'bank':'工商銀行','account':'10101920201920212'}" />
    <#assign data=text?eval />
    開戶行:${data.bank}  賬號(hào):${data.account}

<hr>
</body>
</html>

  (3)測(cè)試

  瀏覽器訪問http://localhost:8881/student/innerFunc

  效果如下

1668404990552_7.jpg

  內(nèi)建函數(shù)測(cè)試demo2

  需求:遍歷學(xué)生集合,顯示集合總條數(shù),id不要逗號(hào)隔開,顯示學(xué)生的生日(只顯示年月日),錢包顯示整數(shù)并顯示單位`元`,用戶姓名做脫敏處理(如果是兩個(gè)字第二個(gè)字顯示為星號(hào),例如張三顯示為`張*`,如果大于兩個(gè)字,中間字顯示為星號(hào),例如成吉思汗顯示為`成*汗`,諸葛亮顯示為`諸*亮`)

  (1)修改StudentController中的list方法,

@GetMapping("list")
public String list(Model model) throws ParseException {
    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    List<Student> list = new ArrayList<>();

    list.add(new Student(1001,"張三",15, dateFormat.parse("2007-10-01 10:00:00"), 1000.11F));
    list.add(new Student(1002,"李四",28, dateFormat.parse("1994-10-01 10:00:00"), 5000.3F));
    list.add(new Student(1003,"王五",45, dateFormat.parse("1977-10-01 10:00:00"), 9000.63F));
    list.add(new Student(1004,"趙六",62, dateFormat.parse("1960-10-01 10:00:00"), 10000.99F));
    list.add(new Student(1005,"孫七",75, dateFormat.parse("1947-10-01 10:00:00"), 16000.66F));
    model.addAttribute("stus",list);

    return "02-list";
}

  (2)修改02-list.ftl模版

  共${stus?size}條數(shù)據(jù):輸出總條數(shù)

  `stu.id`后面加`?c `:id不需要逗號(hào)分割

  `stu.birthday`后面加`?date`:生日只輸出年月日

  `stu.money`后面加`?int`:金額取整

  姓名需要使用replace和substring函數(shù)處理

  完整內(nèi)容如下

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>列表頁面</title>
    <style>
        table{
            border-spacing: 0;/*把單元格間隙設(shè)置為0*/
            border-collapse: collapse;/*設(shè)置單元格的邊框合并為1*/
        }
        td{
            border:1px solid #ACBED1;
            text-align: center;
        }
    </style>
</head>
<body>
共${stus?size}條數(shù)據(jù)
<table>
    <tr>
        <td>序號(hào)</td>
        <td>id</td>
        <td>姓名</td>
        <td>所處的年齡段</td>
        <td>生日</td>
        <td>錢包</td>
        <td>是否最后一條數(shù)據(jù)</td>
    </tr>
    <#list stus as stu >
        <tr>
            <td>${stu_index + 1}</td>
            <td>${stu.id?c}</td>
            <td>
                <#if stu.name?length=2>
                    ${stu.name?replace(stu.name?substring(1), "*")}
                <#else>
                    ${stu.name?replace(stu.name?substring(1, stu.name?length-1), "*")}
                </#if>
            </td>
            <td>
                <#if stu.age <= 6>
                    童年
                <#elseif stu.age <= 17>
                    少年
                <#elseif stu.age <= 40>   
                    青年
                <#elseif stu.age <= 65>   
                    中年
                <#else>
                    老年
                </#if>
            </td>
            <td>${stu.birthday?date}</td>
            <td>${stu.money?int}元</td>
            <td>
                <#if stu_has_next>
                否
                <#else>
                是
                </#if>
            </td>
        </tr>
    </#list>
</table>

<hr>
</body>
</html>

  (3)測(cè)試

  瀏覽器訪問http://localhost:8881/student/list

  效果如下

1668405145477_8.jpg

  2.4.9 靜態(tài)化

  (1)springboot整合freemarker靜態(tài)化文件用法

  編寫springboot測(cè)試用例

package com.itheima.test;

import com.itheima.freemarker.FreemarkerDemoApplication;
import com.itheima.freemarker.entity.Student;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

@SpringBootTest(classes = FreemarkerDemoApplication.class)
@RunWith(SpringRunner.class)
public class FreemarkerTest {

    //注入freemarker配置類
    @Autowired
    private Configuration configuration;

    @Test
    public void test() throws IOException, TemplateException {
        Template template = configuration.getTemplate("04-innerFunc.ftl");
        /**
         * 靜態(tài)化并輸出到文件中   參數(shù)1:數(shù)據(jù)模型     參數(shù)2:文件輸出流
         */
        template.process(getData(), new FileWriter("d:/list.html"));
        /**
         * 靜態(tài)化并輸出到字節(jié)輸出流中
         */
        //StringWriter out = new StringWriter();
        //template.process(getData(), out);
        //System.out.println(out.toString());
    }


    private Map getData(){

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

        Student stu1 = new Student();
        stu1.setName("小強(qiáng)");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);
        stu1.setBirthday(new Date());

        //小紅對(duì)象模型數(shù)據(jù)
        Student stu2 = new Student();
        stu2.setName("小紅");
        stu2.setMoney(200.1f);
        stu2.setAge(19);

        //將兩個(gè)對(duì)象模型數(shù)據(jù)存放到List集合中
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);

        //向model中存放List集合數(shù)據(jù)
        map.put("stus",stus);


        //map數(shù)據(jù)
        Map<String,Student> stuMap = new HashMap<>();
        stuMap.put("stu1",stu1);
        stuMap.put("stu2",stu2);

        map.put("stuMap",stuMap);
        //日期
        map.put("today",new Date());

        //長(zhǎng)數(shù)值
        map.put("point",38473897438743L);

        return map;

    }
}

  (2)freemarker原生靜態(tài)化用法

package com.itheima.freemarker.test;

import com.itheima.freemarker.entity.Student;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import freemarker.template.TemplateExceptionHandler;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.*;

public class FreemarkerTest {

    public static void main(String[] args) throws IOException, TemplateException {
        //創(chuàng)建配置類
        Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
        //設(shè)置模版加載路徑

        //ClassTemplateLoader方式:需要將模版放在FreemarkerTest類所在的包,加載模版時(shí)會(huì)從該包下加載
        //CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreemarkerTest.class,""));

        String path = java.net.URLDecoder.decode(FreemarkerTest.class.getClassLoader().getResource("").getPath(),"utf-8");
        //FileTemplateLoader方式:需要將模版放置在classpath目錄下 目錄有中文也可以
        CONFIGURATION.setTemplateLoader(new FileTemplateLoader(new File(path)));

        //設(shè)置編碼
        CONFIGURATION.setDefaultEncoding("UTF-8");
        //設(shè)置異常處理器
        CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        //設(shè)置緩存方式
        CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
        //加載模版
        Template template = CONFIGURATION.getTemplate("templates/04-innerFunc.ftl");
        /**
         * 靜態(tài)化并輸出到文件中   參數(shù)1:數(shù)據(jù)模型     參數(shù)2:文件輸出流
         */
        template.process(getModel(), new FileWriter("d:/list.html"));
        /**
         * 靜態(tài)化并輸出到字節(jié)輸出流中
         */
        //StringWriter out = new StringWriter();
        //template.process(getData(), out);
        //System.out.println(out.toString());
    }


    public static Map getModel(){
        Map map = new HashMap();
        //1.1 小強(qiáng)對(duì)象模型數(shù)據(jù)
        Student stu1 = new Student();
        stu1.setName("小強(qiáng)");
        stu1.setAge(18);
        stu1.setMoney(1000.86f);
        stu1.setBirthday(new Date());
        //1.2 小紅對(duì)象模型數(shù)據(jù)
        Student stu2 = new Student();
        stu2.setName("小紅");
        stu2.setMoney(200.1f);
        stu2.setAge(19);
        //1.3 將兩個(gè)對(duì)象模型數(shù)據(jù)存放到List集合中
        List<Student> stus = new ArrayList<>();
        stus.add(stu1);
        stus.add(stu2);
        map.put("stus", stus);
        // 2.1 添加日期
        Date date = new Date();
        map.put("today", date);
        // 3.1 添加數(shù)值
        map.put("point", 102920122);
        return map;
    }
}

  3 數(shù)據(jù)庫(kù)元數(shù)據(jù)

  3.1 介紹

  元數(shù)據(jù)(Metadata)是描述數(shù)據(jù)的數(shù)據(jù)。

  數(shù)據(jù)庫(kù)元數(shù)據(jù)(DatabaseMetaData)就是指定義數(shù)據(jù)庫(kù)各類對(duì)象結(jié)構(gòu)的數(shù)據(jù)。

  在mysql中可以通過show關(guān)鍵字獲取相關(guān)的元數(shù)據(jù)

show status; 獲取數(shù)據(jù)庫(kù)的狀態(tài)
show databases; 列出所有數(shù)據(jù)庫(kù)
show tables; 列出所有表
show create database [數(shù)據(jù)庫(kù)名]; 獲取數(shù)據(jù)庫(kù)的定義
show create table [數(shù)據(jù)表名]; 獲取數(shù)據(jù)表的定義
show columns from <table_name>; 顯示表的結(jié)構(gòu)
show index from <table_name>; 顯示表中有關(guān)索引和索引列的信息
show character set; 顯示可用的字符集以及其默認(rèn)整理
show collation; 顯示每個(gè)字符集的整理
show variables; 列出數(shù)據(jù)庫(kù)中的參數(shù)定義值

  也可以從 information_schema庫(kù)中獲取元數(shù)據(jù),information_schema數(shù)據(jù)庫(kù)是MySQL自帶的信息數(shù)據(jù)庫(kù),它提供了訪問數(shù)據(jù)庫(kù)元數(shù)據(jù)的方式。存著其他數(shù)據(jù)庫(kù)的信息。

select schema_name from information_schema.schemata; 列出所有的庫(kù)
select table_name FROM information_schema.tables; 列出所有的表

  在代碼中可以由JDBC的Connection對(duì)象通過getMetaData方法獲取而來,主要封裝了是對(duì)數(shù)據(jù)庫(kù)本身的一些整體綜合信息,例如數(shù)據(jù)庫(kù)的產(chǎn)品名稱,數(shù)據(jù)庫(kù)的版本號(hào),數(shù)據(jù)庫(kù)的URL,是否支持事務(wù)等等。

  DatabaseMetaData的常用方法:

getDatabaseProductName:獲取數(shù)據(jù)庫(kù)的產(chǎn)品名稱
getDatabaseProductName:獲取數(shù)據(jù)庫(kù)的版本號(hào)
getUserName:獲取數(shù)據(jù)庫(kù)的用戶名
getURL:獲取數(shù)據(jù)庫(kù)連接的URL
getDriverName:獲取數(shù)據(jù)庫(kù)的驅(qū)動(dòng)名稱
driverVersion:獲取數(shù)據(jù)庫(kù)的驅(qū)動(dòng)版本號(hào)
isReadOnly:查看數(shù)據(jù)庫(kù)是否只允許讀操作
supportsTransactions:查看數(shù)據(jù)庫(kù)是否支持事務(wù)

  3.2 搭建環(huán)境

  (1)導(dǎo)入mysql依賴

<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>5.1.47</version>
</dependency>

  (2)創(chuàng)建測(cè)試用例

package com.itheima.test;

import org.junit.Before;
import org.junit.Test;

import java.sql.*;
import java.util.Properties;

public class DataBaseMetaDataTest {
    private Connection conn;

    @Before
    public void init() throws Exception {
        Properties pro = new Properties();
        pro.setProperty("user", "root");
        pro.setProperty("password", "123456");
        pro.put("useInformationSchema", "true");//獲取mysql表注釋
        //pro.setProperty("remarksReporting","true");//獲取oracle表注釋
        conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/?useUnicode=true&amp;characterEncoding=UTF8", pro);
    }  
}

  3.3 綜合信息元數(shù)據(jù)

  (1)獲取數(shù)據(jù)庫(kù)元信息綜合信息

@Test
public void testDatabaseMetaData() throws SQLException {
    //獲取數(shù)據(jù)庫(kù)元數(shù)據(jù)
    DatabaseMetaData dbMetaData = conn.getMetaData();
    //獲取數(shù)據(jù)庫(kù)產(chǎn)品名稱
    String productName = dbMetaData.getDatabaseProductName();
    System.out.println(productName);
    //獲取數(shù)據(jù)庫(kù)版本號(hào)
    String productVersion = dbMetaData.getDatabaseProductVersion();
    System.out.println(productVersion);
    //獲取數(shù)據(jù)庫(kù)用戶名
    String userName = dbMetaData.getUserName();
    System.out.println(userName);
    //獲取數(shù)據(jù)庫(kù)連接URL
    String userUrl = dbMetaData.getURL();
    System.out.println(userUrl);
    //獲取數(shù)據(jù)庫(kù)驅(qū)動(dòng)
    String driverName = dbMetaData.getDriverName();
    System.out.println(driverName);
    //獲取數(shù)據(jù)庫(kù)驅(qū)動(dòng)版本號(hào)
    String driverVersion = dbMetaData.getDriverVersion();
    System.out.println(driverVersion);
    //查看數(shù)據(jù)庫(kù)是否允許讀操作
    boolean isReadOnly = dbMetaData.isReadOnly();
    System.out.println(isReadOnly);
    //查看數(shù)據(jù)庫(kù)是否支持事務(wù)操作
    boolean supportsTransactions = dbMetaData.supportsTransactions();
    System.out.println(supportsTransactions);
}

  (2)獲取數(shù)據(jù)庫(kù)列表

@Test
public void testFindAllCatalogs() throws Exception {
    //獲取元數(shù)據(jù)
    DatabaseMetaData metaData = conn.getMetaData();
    //獲取數(shù)據(jù)庫(kù)列表
    ResultSet rs = metaData.getCatalogs();
    //遍歷獲取所有數(shù)據(jù)庫(kù)表
    while (rs.next()) {
        //打印數(shù)據(jù)庫(kù)名稱
        System.out.println(rs.getString(1));
    }
    //釋放資源
    rs.close();
    conn.close();
}

  (3)獲取某數(shù)據(jù)庫(kù)中的所有表信息

@Test
public void testFindAllTable() throws Exception {
    //獲取元數(shù)據(jù)
    DatabaseMetaData metaData = conn.getMetaData();
    //獲取所有的數(shù)據(jù)庫(kù)表信息
    ResultSet rs = metaData.getTables("庫(kù)名", "%", "%", new String[]{"TABLE"});
    //拼裝table
    while (rs.next()) {
        //所屬數(shù)據(jù)庫(kù)
        System.out.println(rs.getString(1));
        //所屬schema
        System.out.println(rs.getString(2));
        //表名
        System.out.println(rs.getString(3));
        //數(shù)據(jù)庫(kù)表類型
        System.out.println(rs.getString(4));
        //數(shù)據(jù)庫(kù)表備注
        System.out.println(rs.getString(5));
        System.out.println("--------------");
    }
}

  (4)獲取某張表所有的列信息

@Test
public void testFindAllColumns() throws Exception {
    //獲取元數(shù)據(jù)
    DatabaseMetaData metaData = conn.getMetaData();
    //獲取所有的數(shù)據(jù)庫(kù)某張表所有列信息
    ResultSet rs = metaData.getColumns("庫(kù)名", "%", "表名","%");

    while(rs.next()) {
        //表名
        System.out.println(rs.getString("TABLE_NAME"));
        //列名
        System.out.println(rs.getString("COLUMN_NAME"));
        //類型碼值
        System.out.println(rs.getString("DATA_TYPE"));
        //類型名稱
        System.out.println(rs.getString("TYPE_NAME"));
        //列的大小
        System.out.println(rs.getString("COLUMN_SIZE"));
        //小數(shù)部分位數(shù),不適用的類型會(huì)返回null
        System.out.println(rs.getString("DECIMAL_DIGITS"));
        //是否允許使用null
        System.out.println(rs.getString("NULLABLE"));
        //列的注釋信息
        System.out.println(rs.getString("REMARKS"));
        //默認(rèn)值
        System.out.println(rs.getString("COLUMN_DEF"));
        //是否自增
        System.out.println(rs.getString("IS_AUTOINCREMENT"));
        //表中的列的索引(從 1 開始
        System.out.println(rs.getString("ORDINAL_POSITION"));
        System.out.println("--------------");
    }
}

  3.4 參數(shù)元數(shù)據(jù)

  參數(shù)元數(shù)據(jù)(ParameterMetaData):是由PreparedStatement對(duì)象通過getParameterMetaData方法獲取而

  來,主要是針對(duì)PreparedStatement對(duì)象和其預(yù)編譯的SQL命令語句提供一些信息,ParameterMetaData能提供占位符參數(shù)的個(gè)數(shù),獲取指定位置占位符的SQL類型等等

  以下有一些關(guān)于ParameterMetaData的常用方法:

  ```

  getParameterCount:獲取預(yù)編譯SQL語句中占位符參數(shù)的個(gè)數(shù)

  ```

@Test
public void testParameterMetaData() throws Exception {
    String sql = "select * from health.t_checkgroup where id=? and code=?";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "7");
    pstmt.setString(2, "0003");
    //獲取ParameterMetaData對(duì)象
    ParameterMetaData paramMetaData = pstmt.getParameterMetaData();
    //獲取參數(shù)個(gè)數(shù)
    int paramCount = paramMetaData.getParameterCount();
    System.out.println(paramCount);
}

  3.5 結(jié)果集元數(shù)據(jù)

  結(jié)果集元數(shù)據(jù)(ResultSetMetaData):是由ResultSet對(duì)象通過getMetaData方法獲取而來,主要是針對(duì)由數(shù)據(jù)庫(kù)執(zhí)行的SQL腳本命令獲取的結(jié)果集對(duì)象ResultSet中提供的一些信息,比如結(jié)果集中的列數(shù)、指定列的名稱、指定列的SQL類型等等,可以說這個(gè)是對(duì)于框架來說非常重要的一個(gè)對(duì)象。

  以下有一些關(guān)于ResultSetMetaData的常用方法:

  ```

  getColumnCount:獲取結(jié)果集中列項(xiàng)目的個(gè)數(shù)

  getColumnType:獲取指定列的SQL類型對(duì)應(yīng)于Java中Types類的字段

  getColumnTypeName:獲取指定列的SQL類型

  getClassName:獲取指定列SQL類型對(duì)應(yīng)于Java中的類型(包名加類名

  ```

@Test
public void testResultSetMetaData() throws Exception {
    String sql = "select * from health.t_checkgroup where id=?";
    PreparedStatement pstmt = conn.prepareStatement(sql);
    pstmt.setString(1, "7");
    //執(zhí)行sql語句
    ResultSet rs = pstmt.executeQuery();
    //獲取ResultSetMetaData對(duì)象
    ResultSetMetaData metaData = rs.getMetaData();
    //獲取查詢字段數(shù)量
    int columnCount = metaData.getColumnCount();
    System.out.println("字段總數(shù)量:"+ columnCount);
    for (int i = 1; i <= columnCount; i++) {
        //獲取表名稱
        System.out.println(metaData.getColumnName(i));
        //獲取java類型
        System.out.println(metaData.getColumnClassName(i));
        //獲取sql類型
        System.out.println(metaData.getColumnTypeName(i));
        System.out.println("----------");
    }
}

  4 代碼生成器環(huán)境搭建

  4.1 創(chuàng)建maven工程

  創(chuàng)建maven工程并導(dǎo)入以下依賴

<properties>
    <java.version>11</java.version>
    <!-- 項(xiàng)目源碼及編譯輸出的編碼 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <!-- 項(xiàng)目編譯JDK版本 -->
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.freemarker</groupId>
        <artifactId>freemarker</artifactId>
        <version>2.3.23</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>5.1.47</version>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <version>1.18.8</version>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.10</version>
    </dependency>
</dependencies>

  目錄結(jié)構(gòu)如下

1668405538880_9.jpg

  4.2 編碼

  4.2.1 常量類

package freemarker.constant;

public class TemplateConstant {

    //實(shí)體類模板
    public static final String entityTemplate = "templates/Entity.ftl";
    //Mapper模板
    public static final String mapperTemplate = "templates/Mapper.ftl";
    //Mapper映射文件模版
    public static final String mapperXmlTemplate = "templates/MapperXml.ftl";
    //service模版
    public static final String serviceTemplate = "templates/Service.ftl";
    //service實(shí)現(xiàn)類模版
    public static final String serviceImplTemplate = "templates/ServiceImpl.ftl";
    //controller模版
    public static final String controllerTemplate = "templates/Controller.ftl";
    //vo模版
    public static final String entityVoTemplate = "templates/EntityVo.ftl";
    //dto模版
    public static final String entityDtoTemplate = "templates/EntityDto.ftl";
    //pom模版
    public static final String pomTemplate = "templates/pom.ftl";
    //application.yml模版
    public static final String applicationTemplate = "templates/application.ftl";
}

  4.2.2 工具類

  (1)DbUtil數(shù)據(jù)庫(kù)工具類

package freemarker.util;

import freemarker.param.ColumnClass;
import freemarker.param.TableClass;
import lombok.Getter;
import lombok.Setter;

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

/**
 * 數(shù)據(jù)庫(kù)工具類
 */
@Setter
@Getter
public class DbUtil {

    //數(shù)據(jù)庫(kù)連接地址
    private String url = "jdbc:mysql://localhost:3306/heima_leadnews_wemedia?useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=UTC";
    //數(shù)據(jù)庫(kù)用戶名
    private String username = "root";
    //數(shù)據(jù)庫(kù)密碼

    private String password = "123456";
    //數(shù)據(jù)庫(kù)驅(qū)動(dòng)
    private String driver = "com.mysql.jdbc.Driver";

    //數(shù)據(jù)庫(kù)名稱
    private String dbName = null;

    private Connection connection =null;

    /**
     * 獲取jdbc鏈接
     * @return
     * @throws Exception
     */
    public Connection getConnection() throws Exception{
        Properties pro = new Properties();
        pro.setProperty("user", username);
        pro.setProperty("password", password);
        pro.put("useInformationSchema", "true");//獲取mysql表注釋
        //pro.setProperty("remarksReporting","true");//獲取oracle表注釋
        Class.forName(driver);
        connection = DriverManager.getConnection(url, pro);
        return connection;
    }

    /**
     * 獲取當(dāng)前數(shù)據(jù)庫(kù)下的所有表名稱及注釋
     * @return
     * @throws Exception
     */
    public List<TableClass> getAllTables() throws Exception {
        List<TableClass> list = new ArrayList<>();
        //獲取鏈接
        Connection conn = getConnection();
        //獲取元數(shù)據(jù)
        DatabaseMetaData metaData = conn.getMetaData();
        //獲取所有的數(shù)據(jù)庫(kù)表信息
        ResultSet rs = metaData.getTables(dbName!=null?dbName:conn.getCatalog(), "%", "%", new String[]{"TABLE"});
        while (rs.next()) {
            TableClass tableClass = new TableClass();
            tableClass.setTableName(rs.getString(3));
            tableClass.setTableComment(rs.getString(5));
            list.add(tableClass);
        }
        return list;
    }

    /**
     *  獲取某張表的所有列
     * @param tableName
     * @return
     * @throws Exception
     */
    public List<ColumnClass> getAllColumns(String tableName) throws Exception {
        List<ColumnClass> list = new ArrayList<>();
        //獲取鏈接
        Connection conn = getConnection();
        //獲取元數(shù)據(jù)
        DatabaseMetaData metaData = conn.getMetaData();
        //獲取所有的數(shù)據(jù)庫(kù)某張表所有列信息
        ResultSet rs = metaData.getColumns(dbName!=null?dbName:conn.getCatalog(), "%", tableName,"%");

        while(rs.next()) {
            ColumnClass columnClass = new ColumnClass();
            columnClass.setColumnName(rs.getString("COLUMN_NAME"));
            columnClass.setColumnType(rs.getString("TYPE_NAME"));
            columnClass.setColumnComment(rs.getString("REMARKS"));
            columnClass.setChangeColumnName(StrUtil.changeColumnStr(rs.getString("COLUMN_NAME")));
            list.add(columnClass);
        }
        return list;
    }

    /**
     * 關(guān)閉鏈接
     */
    public void closeConnection(){
        try {
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    };

}

  (2)字符串處理工具類

package freemarker.util;

/**
 * 字符串處理工具類
 */
public class StrUtil {
    /**
     * 去掉下劃線轉(zhuǎn)駝峰  user_name  -> userName
     * @param str
     * @return
     */
    public static String changeColumnStr(String str) {
        String name = str;
        if (name.indexOf("_") > 0 && name.length() != name.indexOf("_") + 1) {
            int lengthPlace = name.indexOf("_");
            name = name.replaceFirst("_", "");
            String s = name.substring(lengthPlace, lengthPlace + 1);
            s = s.toUpperCase();
            str = name.substring(0, lengthPlace) + s + name.substring(lengthPlace + 1);
        } else {
            return str;
        }
        return changeColumnStr(str);
    }
    /**
     * 去掉下劃線轉(zhuǎn)駝峰  tb_user  -> TbUser
     * @param str
     * @return
     */
    public static String changeTableStr(String str) {
        String s = changeColumnStr(str);
        return s.substring(0,1).toUpperCase()+s.substring(1);
    }
}

  (3)FreeMarker模版工具類

package freemarker.util;

import freemarker.cache.FileTemplateLoader;
import freemarker.cache.NullCacheStorage;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

/**
 * FreeMarker模版工具類
 */
public class FreeMarkerTemplateUtils {
    private FreeMarkerTemplateUtils(){}
    private static final Configuration CONFIGURATION = new Configuration(Configuration.VERSION_2_3_22);
    static{
        //ClassTemplateLoader方式:需要將模版放在FreeMarkerTemplateUtils類所在的包,加載模版時(shí)會(huì)從該包下加載
        //CONFIGURATION.setTemplateLoader(new ClassTemplateLoader(FreeMarkerTemplateUtils.class,""));

        try {
            String path = java.net.URLDecoder.decode(FreeMarkerTemplateUtils.class.getClassLoader().getResource("").getPath(),"utf-8");
            //FileTemplateLoader方式:需要將模版放置在classpath目錄下 目錄有中文也可以
            CONFIGURATION.setTemplateLoader(new FileTemplateLoader(new File(path)));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        CONFIGURATION.setDefaultEncoding("UTF-8");
        CONFIGURATION.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
        CONFIGURATION.setCacheStorage(NullCacheStorage.INSTANCE);
    }
 
    public static Template getTemplate(String templateName) throws IOException {
        try {
            return CONFIGURATION.getTemplate(templateName);
        } catch (IOException e) {
            throw e;
        }
    }
 
    public static void clearCache() {
        CONFIGURATION.clearTemplateCache();
    }
}

  4.2.3 實(shí)體類

  (1)表實(shí)體類

package freemarker.param;

import lombok.Data;

@Data
public class TableClass {
    /**
     * 表名 tb_user
     **/
    private String tableName;

    /**
     *  表注釋
     **/
    private String tableComment;

}

  (2)列實(shí)體類

package freemarker.param;

import lombok.Data;

@Data
public class ColumnClass {
    /**
     * 數(shù)據(jù)庫(kù)字段名稱 user_name
     **/
    private String columnName;
    /**
     * 數(shù)據(jù)庫(kù)字段類型
     **/
    private String columnType;
    /**
     * 數(shù)據(jù)庫(kù)字段首字母小寫且去掉下劃線字符串 userName
     **/
    private String changeColumnName;
    /**
     * 數(shù)據(jù)庫(kù)字段注釋
     **/
    private String columnComment;

}

  (3)模版相關(guān)參數(shù)類

package freemarker.param;

import lombok.Data;
import org.apache.commons.lang3.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Date;

@Data
public class TemplatePathParam {

    private String currentDate = new SimpleDateFormat("yyyy/MM/dd").format(new Date());

    //包名 com.itheima.user
    private String packageName;
    //代碼生成路徑 D:\\path
    private String basePath;
    //項(xiàng)目名稱  英文  比如itheima-user
    private String projectName;
    //作者
    private String author ;

    //實(shí)體類生成的絕對(duì)路徑
    private String entityPath;
    //vo實(shí)體類生成的絕對(duì)路徑
    private String entityVoPath;
    //Dto實(shí)體類生成的絕對(duì)路徑
    private String entityDtoPath;
    //mapper生成絕對(duì)路徑
    private String mapperPath;
    //mapper映射文件生成的絕對(duì)路徑
    private String mapperXmlPath;
    //service接口生成的絕對(duì)路徑
    private String servicePath;
    //service實(shí)現(xiàn)類生成的絕對(duì)路徑
    private String serviceImplPath;
    //controller生成的絕對(duì)路徑
    private String controllerPath;
    //pom文件生成的絕對(duì)路徑
    private String pomPath;
    //application.yml文件生成的絕對(duì)路徑
    private String applicationYmlPath;

    public TemplatePathParam(String packageName, String basePath, String projectName, String author) {
        if(StringUtils.isBlank(packageName)
                || StringUtils.isBlank(basePath)
                || StringUtils.isBlank(author)
                || StringUtils.isBlank(projectName)){
            throw new RuntimeException("參數(shù)不能為空");
        }
        this.packageName = packageName;
        this.basePath = basePath;
        this.author = author;
        this.projectName = projectName;

        String[] split = packageName.split("\\.");
        // D:\\path\\itheima-user\\src\\main\\java\\com\\itheima\\user
        String javaModelPath = basePath+"\\"+projectName+"\\src\\main\\java\\"+split[0]+"\\"+split[1]+"\\"+split[2];
        String xmlModelPath = basePath+"\\"+projectName+"\\src\\main\\resources\\"+split[0]+"\\"+split[1]+"\\"+split[2];
        this.setEntityPath(javaModelPath+"\\entity");
        this.setMapperPath(javaModelPath+"\\mapper");
        this.setMapperXmlPath(xmlModelPath+"\\mapper");
        this.setServicePath(javaModelPath+"\\service");
        this.setServiceImplPath(javaModelPath+"\\service\\impl");
        this.setControllerPath(javaModelPath+"\\http\\controller");
        this.setEntityVoPath(javaModelPath+"\\http\\vo");
        this.setEntityDtoPath(javaModelPath+"\\http\\dto");
        this.setEntityDtoPath(javaModelPath+"\\http\\dto");
        this.setPomPath(basePath+"\\"+projectName);
        this.setApplicationYmlPath(basePath+"\\"+projectName+"\\src\\main\\resources");
    }

}

  4.2.4 代碼生成器入口類

package freemarker;

import freemarker.constant.TemplateConstant;
import freemarker.param.ColumnClass;
import freemarker.param.TableClass;
import freemarker.param.TemplatePathParam;
import freemarker.template.Template;
import freemarker.util.DbUtil;
import freemarker.util.FreeMarkerTemplateUtils;
import freemarker.util.StrUtil;
import org.apache.commons.lang3.StringUtils;

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

/**
 * 代碼生成器入口
 */
public class CodeGenerateUtils {

    private TemplatePathParam templatePathParam = null;

    public static void main(String[] args) throws Exception{
        CodeGenerateUtils codeGenerateUtils = new CodeGenerateUtils();
        codeGenerateUtils.generate();
        System.out.println("============  全部生成完成!   =============");
    }

    public void generate() throws Exception{
        /**
         * 參數(shù)1:報(bào)名
         * 參數(shù)2:生成代碼的基礎(chǔ)路徑
         * 參數(shù)3:項(xiàng)目名稱
         * 參數(shù)4:作者
         */
        templatePathParam = new TemplatePathParam("com.itheima.wemedia",
                "D:\\heima\\技術(shù)文章\\代碼",
                "itheima-wemedia",
                "kdm");
        //數(shù)據(jù)庫(kù)相關(guān)
        DbUtil dbUtil = new DbUtil();
        //獲取所有表
        List<TableClass> allTable = dbUtil.getAllTables();
        for (TableClass tableClass : allTable) {
            //表名
            String table = tableClass.getTableName();
            //獲取所有列
            List<ColumnClass> allColumns = dbUtil.getAllColumns(table);
            System.out.println("-------- 正在生成  " + table+"  表相關(guān)文件------");
            //生成實(shí)體類
            System.out.println("生成實(shí)體類");
            generateEntityFile(tableClass, allColumns);

            //生成Mapper
            System.out.println("生成Mapper");
            generateMapperFile(tableClass, allColumns);
           
            //生成Mapper.xml
            System.out.println("生成Mapper映射文件");
            generateMapperXmlFile(tableClass, allColumns);
           
            //生成service接口
            System.out.println("生成service接口");
            generateServiceFile(tableClass, allColumns);
 
            //生成service實(shí)現(xiàn)類
            System.out.println("生成service實(shí)現(xiàn)類");
            generateServiceImplFile(tableClass, allColumns);

            //生成Controller層文件
            System.out.println("生成Controller層文件");
            generateControllerFile(tableClass, allColumns);

            //生成vo類
            System.out.println("生成vo類");
            generateEntityVoFile(tableClass, allColumns);

            //生成dto類
            System.out.println("生成dto類");
            generateEntityDtoFile(tableClass, allColumns);

            //生成pom文件
            System.out.println("生成pom文件");
            generatePomFile(tableClass, allColumns);

            //生成application.yml文件
            System.out.println("生成application.yml文件");
            generateApplicationYmlFile(tableClass, allColumns);
        }
        dbUtil.closeConnection();
    }


    /**
     * 生成實(shí)體文件
     */
    private void generateEntityFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = ".java";
        String filePath = templatePathParam.getEntityPath();
        String file = templatePathParam.getEntityPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap.put("model_column",allColumns);
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.entityTemplate, filePath, file, dataMap);
    }

    /**
     * 生成mapper文件
     */
    private void generateMapperFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Mapper.java";
        String filePath = templatePathParam.getMapperPath();
        String file = templatePathParam.getMapperPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);

        generateFileByTemplate(TemplateConstant.mapperTemplate, filePath, file, dataMap);
    }
    /**
     * 生成xml映射文件
     */
    private void generateMapperXmlFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Mapper.xml";
        String filePath = templatePathParam.getMapperXmlPath();
        String file = templatePathParam.getMapperXmlPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.mapperXmlTemplate, filePath, file, dataMap);
    }
    /**
     * 生成業(yè)務(wù)接口層
     */
    private void generateServiceFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Service.java";
        String filePath = templatePathParam.getServicePath();
        String file = templatePathParam.getServicePath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.serviceTemplate, filePath, file, dataMap);
    }
    /**
     * 生成業(yè)務(wù)實(shí)現(xiàn)層
     */
    private void generateServiceImplFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "ServiceImpl.java";
        String filePath = templatePathParam.getServiceImplPath();
        String file = templatePathParam.getServiceImplPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.serviceImplTemplate, filePath, file, dataMap);
    }
    /**
     * 生成控制層
     */
    private void generateControllerFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Controller.java";
        String filePath = templatePathParam.getControllerPath();
        String file = templatePathParam.getControllerPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.controllerTemplate, filePath, file, dataMap);
    }
    /**
     * 生成Vo類
     */
    private void generateEntityVoFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Vo.java";
        String filePath = templatePathParam.getEntityVoPath();
        String file = templatePathParam.getEntityVoPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap.put("model_column",allColumns);
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.entityVoTemplate, filePath, file, dataMap);
    }
    /**
     * 生成Dto類
     */
    private void generateEntityDtoFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "Dto.java";
        String filePath = templatePathParam.getEntityDtoPath();
        String file = templatePathParam.getEntityDtoPath() + "\\"+ StrUtil.changeTableStr(tableClass.getTableName()) + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap.put("model_column",allColumns);
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.entityDtoTemplate, filePath, file, dataMap);
    }
    /**
     * 生成Pom文件
     */
    private void generatePomFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "pom.xml";
        String filePath = templatePathParam.getPomPath();
        String file = templatePathParam.getPomPath() + "\\" + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.pomTemplate, filePath, file, dataMap);
    }
    /**
     * 生成application.yml文件
     */
    private void generateApplicationYmlFile(TableClass tableClass, List<ColumnClass> allColumns) throws Exception{
        String suffix = "application.yml";
        String filePath = templatePathParam.getApplicationYmlPath();
        String file = templatePathParam.getApplicationYmlPath() + "\\" + suffix;

        Map<String,Object> dataMap = new HashMap<String,Object>();
        dataMap = getCommonModel(dataMap, tableClass);
        generateFileByTemplate(TemplateConstant.applicationTemplate, filePath, file, dataMap);
    }

    /**
     * 模版通用參數(shù)
     * @param dataMap 模型map
     * @param tableClass 表名和表注釋參數(shù)
     * @return
     */
    public Map<String,Object> getCommonModel(Map<String,Object> dataMap, TableClass tableClass){
        dataMap.put("table_name", StrUtil.changeTableStr(tableClass.getTableName()));//TbUser
        dataMap.put("table_name_small",StrUtil.changeColumnStr(tableClass.getTableName()));//tbUser
        dataMap.put("table",tableClass.getTableName());//tb_user
        dataMap.put("author",templatePathParam.getAuthor());
        dataMap.put("date",templatePathParam.getCurrentDate());
        dataMap.put("package_name",templatePathParam.getPackageName());
        dataMap.put("project_name",templatePathParam.getProjectName());
        dataMap.put("table_annotation", StringUtils.isNotBlank(tableClass.getTableComment()) ? tableClass.getTableComment() : null);
        return dataMap;
    }
    /**
     * 靜態(tài)化方法
     * @param templateName 模版名稱
     * @param filePathParam 文件所在目錄 絕對(duì)路徑
     * @param fileParam 文件 絕對(duì)路徑
     * @param dataMap 數(shù)據(jù)模型
     * @throws Exception
     */
    private void generateFileByTemplate(final String templateName,
                                        String filePathParam,
                                        String fileParam,
                                        Map<String,Object> dataMap) throws Exception{
        Template template = FreeMarkerTemplateUtils.getTemplate(templateName);
        System.out.println(fileParam);
        //文件夾不存在創(chuàng)建文件夾
        File filePath = new File(filePathParam);
        if (!filePath.exists() && !filePath.isDirectory())
        {
            filePath.mkdirs();
        }
        //文件不存在創(chuàng)建文件夾
        File file = new File(fileParam);
        if(!file.exists())
        {
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        FileOutputStream fos = new FileOutputStream(file);
        Writer out = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"),10240);
        template.process(dataMap,out);
    }

}

  5 制作通用模版

  在 resources/templates 目錄下創(chuàng)建模版類

  5.1 實(shí)體類模版

package ${package_name}.entity;

import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.ToString;
import java.util.Date;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;

import java.io.Serializable;

/**
* 描述:<#if table_annotation??>${table_annotation}模型</#if>
* @author ${author}
* @date ${date}
*/
@Data
@ToString(callSuper = true)
@TableName("${table}")
public class ${table_name} implements Serializable {
<#if model_column?exists>
    <#list model_column as model>
    /**
     * ${model.columnComment!}
     */
    <#if (model.columnType = 'BIGINT' && model.columnName = 'id')>
    @TableId("${model.columnName?uncap_first}")
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'BIGINT' && model.columnName != 'id')>
    @TableField("${model.columnName?uncap_first}")
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'INT' || model.columnType = 'INT UNSIGNED' || model.columnType = 'TINYINT' || model.columnType = 'TINYINT UNSIGNED')>
    @TableField("${model.columnName?uncap_first}")
    private Integer ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'DECIMAL')>
    @TableField("${model.columnName?uncap_first}")
    private BigDecimal ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'VARCHAR' || model.columnType = 'TEXT' || model.columnType = 'CHAR')>
    @TableField("${model.columnName?uncap_first}")
    private String ${model.changeColumnName?uncap_first};
    </#if>
    <#if model.columnType = 'TIMESTAMP' || model.columnType = 'YEAR' || model.columnType = 'DATE' || model.columnType = 'DATETIME' >
    @TableField("${model.columnName?uncap_first}")
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    private Date ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType != 'BIGINT'
        && model.columnType != 'INT'
        && model.columnType != 'DECIMAL'
        && model.columnType != 'VARCHAR'
        && model.columnType != 'TEXT'
        && model.columnType != 'CHAR'
        && model.columnType != 'TIMESTAMP'
        && model.columnType != 'YEAR'
        && model.columnType != 'DATE'
        && model.columnType != 'DATETIME'
        && model.columnType != 'INT UNSIGNED'
        && model.columnType != 'TINYINT'
        && model.columnType != 'TINYINT UNSIGNED')>
    @TableField("${model.columnName?uncap_first}")
    private MISS ${model.changeColumnName?uncap_first};
    </#if>
    </#list>
</#if>

}

  5.2 Mapper模版

package ${package_name}.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import ${package_name}.entity.${table_name};
import org.apache.ibatis.annotations.Mapper;
/**
* 描述:<#if table_annotation??>${table_annotation}數(shù)據(jù)庫(kù)連接層</#if>
* @author ${author}
* @date ${date}
*/
@Mapper
public interface ${table_name}Mapper extends BaseMapper<${table_name}> {

}

  5.3 Mapper映射文件模版

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="${package_name}.mapper.${table_name}Mapper">

</mapper>

  5.4 Service接口模版

package ${package_name}.service;

import ${package_name}.entity.${table_name};
import com.baomidou.mybatisplus.extension.service.IService;

/**
* 描述:<#if table_annotation??>${table_annotation}服務(wù)實(shí)現(xiàn)層接口</#if>
* @author ${author}
* @date ${date}
*/
public interface ${table_name}Service extends IService<${table_name}>{

}

  5.5 Service實(shí)現(xiàn)類模版

package ${package_name}.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import ${package_name}.entity.${table_name};
import ${package_name}.service.${table_name}Service;
import ${package_name}.mapper.${table_name}Mapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

/**
* 描述:<#if table_annotation??>${table_annotation}服務(wù)實(shí)現(xiàn)層</#if>
* @author ${author}
* @date ${date}
*/
@Slf4j
@Service
public class ${table_name}ServiceImpl extends ServiceImpl<${table_name}Mapper, ${table_name}> implements ${table_name}Service{

}

  5.6 Controller模版

package ${package_name}.http.controller;

import org.springframework.web.bind.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanUtils;
import org.springframework.validation.annotation.Validated;
import ${package_name}.entity.${table_name};
import ${package_name}.service.${table_name}Service;
import ${package_name}.http.vo.${table_name}Vo;
import ${package_name}.http.dto.${table_name}Dto;

import java.util.List;

/**
* 描述:<#if table_annotation??>${table_annotation}控制層</#if>
* @author ${author}
* @date ${date}
*/
@RestController
@RequestMapping("/${table_name_small}")
public class ${table_name}Controller {

    @Autowired
    private ${table_name}Service ${table_name_small}Service;

    /**
     * 查詢所有
     */
    @GetMapping
    public List<${table_name}> list(){
        return ${table_name_small}Service.list();
    }

    /**
     * 查詢一個(gè)
     */
    @GetMapping("/{id}")
    public ${table_name} get(@PathVariable Long id){
        return ${table_name_small}Service.getById(id);
    }

    /**
     * 新增
     */
    @PostMapping
    public boolean save(@Validated @RequestBody ${table_name}Dto ${table_name_small}Dto){
        ${table_name} ${table_name_small} = new ${table_name}();
        BeanUtils.copyProperties(${table_name_small}Dto, ${table_name_small});
        return ${table_name_small}Service.save(${table_name_small});
    }

    /**
     * 修改
     */
    @PutMapping
    public boolean update(@Validated @RequestBody ${table_name}Dto ${table_name_small}Dto){
        ${table_name} ${table_name_small} = new ${table_name}();
        BeanUtils.copyProperties(${table_name_small}Dto, ${table_name_small});
        return ${table_name_small}Service.updateById(${table_name_small});
    }

     /**
     * 刪除
     * @param id
     * @return 是否成功
     */
    @DeleteMapping("/{id}")
    public boolean del(@PathVariable Long id){
        return ${table_name_small}Service.removeById(id);
    }
}

  5.7 實(shí)體類Vo模版

package ${package_name}.http.vo;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.ToString;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;

/**
* 描述:<#if table_annotation??>${table_annotation}模型</#if>Vo類
* @author ${author}
* @date ${date}
*/
@Data
@ToString(callSuper = true)
public class ${table_name}Vo implements Serializable {
<#if model_column?exists>
    <#list model_column as model>
    <#if (model.columnType = 'BIGINT' && model.columnName = 'id')>
    @JsonSerialize(using = ToStringSerializer.class)
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'BIGINT' && model.columnName != 'id')>
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'INT' || model.columnType = 'INT UNSIGNED' || model.columnType = 'TINYINT')>
    private Integer ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'DECIMAL')>
    private BigDecimal ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'VARCHAR' || model.columnType = 'TEXT' || model.columnType = 'CHAR')>
    private String ${model.changeColumnName?uncap_first};
    </#if>
    <#if model.columnType = 'TIMESTAMP' || model.columnType = 'YEAR' || model.columnType = 'DATE' || model.columnType = 'DATETIME' >
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    private Date ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType != 'BIGINT' && model.columnType != 'INT' && model.columnType != 'VARCHAR' && model.columnType != 'DECIMAL' && model.columnType != 'TEXT' && model.columnType != 'CHAR' && model.columnType != 'TIMESTAMP' && model.columnType != 'YEAR' && model.columnType != 'DATE' && model.columnType != 'DATETIME' && model.columnType != 'INT UNSIGNED')>
    private MISS ${model.changeColumnName?uncap_first};
    </#if>
    </#list>
</#if>
}

  5.8 實(shí)體類Dto模版

package ${package_name}.http.dto;

import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import lombok.ToString;
import java.math.BigDecimal;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.annotation.JsonFormat;

/**
* 描述:<#if table_annotation??>${table_annotation}模型</#if>Dto類
* @author ${author}
* @date ${date}
*/
@Data
@ToString(callSuper = true)
public class ${table_name}Dto implements Serializable {
<#if model_column?exists>
    <#list model_column as model>
    <#if (model.columnType = 'BIGINT' && model.columnName = 'id')>
    @JsonSerialize(using = ToStringSerializer.class)
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'BIGINT' && model.columnName != 'id')>
    private Long ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'INT' || model.columnType = 'INT UNSIGNED' || model.columnType = 'TINYINT')>
    private Integer ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'DECIMAL')>
    private BigDecimal ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType = 'VARCHAR' || model.columnType = 'TEXT' || model.columnType = 'CHAR')>
    private String ${model.changeColumnName?uncap_first};
    </#if>
    <#if model.columnType = 'TIMESTAMP' || model.columnType = 'YEAR' || model.columnType = 'DATE' || model.columnType = 'DATETIME' >
    @JsonFormat(pattern="yyyy-MM-dd HH:mm:ss", timezone="GMT+8")
    private Date ${model.changeColumnName?uncap_first};
    </#if>
    <#if (model.columnType != 'BIGINT' && model.columnType != 'INT' && model.columnType != 'VARCHAR' && model.columnType != 'DECIMAL' && model.columnType != 'TEXT' && model.columnType != 'CHAR' && model.columnType != 'TIMESTAMP' && model.columnType != 'YEAR' && model.columnType != 'DATE' && model.columnType != 'DATETIME' && model.columnType != 'INT UNSIGNED')>
    private MISS ${model.changeColumnName?uncap_first};
    </#if>
    </#list>
</#if>
}

  5.9 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>${package_name}</groupId>
    <artifactId>${project_name}</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- 繼承Spring boot工程 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.9.RELEASE</version>
    </parent>
    <properties>
        <!-- 項(xiàng)目源碼及編譯輸出的編碼 -->
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <!-- 項(xiàng)目編譯JDK版本 -->
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <!-- 依賴包版本管理 -->
        <spring.boot.version>2.3.9.RELEASE</spring.boot.version>
        <lombok.version>1.18.8</lombok.version>
        <mysql.version>5.1.46</mysql.version>
        <mybatis-plus.version>3.3.1</mybatis-plus.version>
    </properties>


    <dependencies>
        <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>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>${r"${mybatis-plus.version}"}</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${r"${mysql.version}"}</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${r"${lombok.version}"}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.10</version>
        </dependency>
    </dependencies>

</project>

  5.10 application.yml文件模版

server:
  port: ${r"${port:8888}"}
spring:
  application:
    name: ${project_name}

  6 測(cè)試

  運(yùn)行代碼生成器入口類 CodeGenerateUtils

  輸出日志如下

D:\app\devs\Java\jdk-11\bin\java.exe "-javaagent:D:\app\devs\JetBrains\IntelliJ IDEA 2018.2.4\lib\idea_rt.jar=60577:D:\app\devs\JetBrains\IntelliJ IDEA 2018.2.4\bin" -Dfile.encoding=UTF-8 -classpath D:\heima\技術(shù)文章\itheima-code\target\classes;D:\app\devs\apache-maven-3.3.9\maven_repository\org\freemarker\freemarker\2.3.23\freemarker-2.3.23.jar;D:\app\devs\apache-maven-3.3.9\maven_repository\mysql\mysql-connector-java\5.1.47\mysql-connector-java-5.1.47.jar;D:\app\devs\apache-maven-3.3.9\maven_repository\org\projectlombok\lombok\1.18.8\lombok-1.18.8.jar;D:\app\devs\apache-maven-3.3.9\maven_repository\org\apache\commons\commons-lang3\3.10\commons-lang3-3.10.jar freemarker.CodeGenerateUtils
-------- 正在生成  undo_log  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\UndoLog.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\UndoLogMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\UndoLogMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\UndoLogService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\UndoLogServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\UndoLogController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\UndoLogVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\UndoLogDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_channel  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmChannel.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmChannelMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmChannelMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmChannelService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmChannelServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmChannelController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmChannelVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmChannelDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_fans_statistics  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmFansStatistics.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmFansStatisticsMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmFansStatisticsMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmFansStatisticsService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmFansStatisticsServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmFansStatisticsController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmFansStatisticsVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmFansStatisticsDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_material  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmMaterial.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmMaterialMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmMaterialMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmMaterialService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmMaterialServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmMaterialController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmMaterialVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmMaterialDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_news  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmNews.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmNewsMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmNewsMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmNewsService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmNewsServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmNewsController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmNewsVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmNewsDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_news_material  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmNewsMaterial.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmNewsMaterialMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmNewsMaterialMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmNewsMaterialService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmNewsMaterialServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmNewsMaterialController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmNewsMaterialVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmNewsMaterialDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_news_statistics  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmNewsStatistics.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmNewsStatisticsMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmNewsStatisticsMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmNewsStatisticsService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmNewsStatisticsServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmNewsStatisticsController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmNewsStatisticsVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmNewsStatisticsDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_sensitive  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmSensitive.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmSensitiveMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmSensitiveMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmSensitiveService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmSensitiveServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmSensitiveController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmSensitiveVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmSensitiveDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
-------- 正在生成  wm_user  表相關(guān)文件------
生成實(shí)體類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\entity\WmUser.java
生成Mapper
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\mapper\WmUserMapper.java
生成Mapper映射文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\com\itheima\wemedia\mapper\WmUserMapper.xml
生成service接口
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\WmUserService.java
生成service實(shí)現(xiàn)類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\service\impl\WmUserServiceImpl.java
生成Controller層文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\controller\WmUserController.java
生成vo類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\vo\WmUserVo.java
生成dto類
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\java\com\itheima\wemedia\http\dto\WmUserDto.java
生成pom文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\pom.xml
生成application.yml文件
D:\heima\技術(shù)文章\代碼\itheima-wemedia\src\main\resources\application.yml
============  全部生成完成!   =============

Process finished with exit code 0

  在idea中點(diǎn)擊 File > open 打開 D:\heima\技術(shù)文章\代碼\itheima-wemedia

1668406011496_10.jpg

  

1668406028356_11.jpg

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!