更新時(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ù)庫和表
根據(jù)表設(shè)計(jì)實(shí)體類
編寫mapper接口
編寫service接口和實(shí)現(xiàn)類
編寫controller控制器
編寫前端頁面
前后端聯(lián)調(diào)
基于代碼生成器開發(fā)步驟:
創(chuàng)建數(shù)據(jù)庫和表
使用代碼生成器生成實(shí)體類、mapper、service、controller、前端頁面
將生成好的代碼拷貝到項(xiàng)目中并做調(diào)整
前后端聯(lián)調(diào)
我們只需要知道數(shù)據(jù)庫和表相關(guān)信息,就可以結(jié)合模版生成各個(gè)模塊的代碼,減少了很多重復(fù)工作,也減少出錯(cuò)概率,提高效率。
1.2 實(shí)現(xiàn)思路
(1)需要對(duì)數(shù)據(jù)庫表解析獲取到元數(shù)據(jù),包含表字段名稱、字段類型等等。
(2)將通用的代碼編寫成模版文件,部分?jǐn)?shù)據(jù)需使用占位符替換。
(3)將元數(shù)據(jù)和模版文件結(jié)合,使用一些模版引擎工具(例如freemarker)即可生成源代碼文件。
2 Freemarker
2.1 介紹
FreeMarker 是一款 模板引擎: 即一種基于模板和要改變的數(shù)據(jù), 并用來生成輸出文本(HTML網(wǎng)頁,電子郵件,配置文件,源代碼等)的通用工具。 它不是面向最終用戶的,而是一個(gè)Java類庫,是一款程序員可以嵌入他們所開發(fā)產(chǎn)品的組件。
模板編寫為FreeMarker Template Language (FTL)。它是簡(jiǎn)單的,專用的語言, 在模板中,你可以專注于如何展現(xiàn)數(shù)據(jù), 而在模板之外可以專注于要展示什么數(shù)據(jù)。
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
效果如下
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
效果如下
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
效果如下
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
效果如下
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
效果如下
內(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
效果如下
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ù)庫元數(shù)據(jù)
3.1 介紹
元數(shù)據(jù)(Metadata)是描述數(shù)據(jù)的數(shù)據(jù)。
數(shù)據(jù)庫元數(shù)據(jù)(DatabaseMetaData)就是指定義數(shù)據(jù)庫各類對(duì)象結(jié)構(gòu)的數(shù)據(jù)。
在mysql中可以通過show關(guān)鍵字獲取相關(guān)的元數(shù)據(jù)
show status; 獲取數(shù)據(jù)庫的狀態(tài) show databases; 列出所有數(shù)據(jù)庫 show tables; 列出所有表 show create database [數(shù)據(jù)庫名]; 獲取數(shù)據(jù)庫的定義 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ù)庫中的參數(shù)定義值
也可以從 information_schema庫中獲取元數(shù)據(jù),information_schema數(shù)據(jù)庫是MySQL自帶的信息數(shù)據(jù)庫,它提供了訪問數(shù)據(jù)庫元數(shù)據(jù)的方式。存著其他數(shù)據(jù)庫的信息。
select schema_name from information_schema.schemata; 列出所有的庫 select table_name FROM information_schema.tables; 列出所有的表
在代碼中可以由JDBC的Connection對(duì)象通過getMetaData方法獲取而來,主要封裝了是對(duì)數(shù)據(jù)庫本身的一些整體綜合信息,例如數(shù)據(jù)庫的產(chǎn)品名稱,數(shù)據(jù)庫的版本號(hào),數(shù)據(jù)庫的URL,是否支持事務(wù)等等。
DatabaseMetaData的常用方法:
getDatabaseProductName:獲取數(shù)據(jù)庫的產(chǎn)品名稱 getDatabaseProductName:獲取數(shù)據(jù)庫的版本號(hào) getUserName:獲取數(shù)據(jù)庫的用戶名 getURL:獲取數(shù)據(jù)庫連接的URL getDriverName:獲取數(shù)據(jù)庫的驅(qū)動(dòng)名稱 driverVersion:獲取數(shù)據(jù)庫的驅(qū)動(dòng)版本號(hào) isReadOnly:查看數(shù)據(jù)庫是否只允許讀操作 supportsTransactions:查看數(shù)據(jù)庫是否支持事務(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&characterEncoding=UTF8", pro); } }
3.3 綜合信息元數(shù)據(jù)
(1)獲取數(shù)據(jù)庫元信息綜合信息
@Test public void testDatabaseMetaData() throws SQLException { //獲取數(shù)據(jù)庫元數(shù)據(jù) DatabaseMetaData dbMetaData = conn.getMetaData(); //獲取數(shù)據(jù)庫產(chǎn)品名稱 String productName = dbMetaData.getDatabaseProductName(); System.out.println(productName); //獲取數(shù)據(jù)庫版本號(hào) String productVersion = dbMetaData.getDatabaseProductVersion(); System.out.println(productVersion); //獲取數(shù)據(jù)庫用戶名 String userName = dbMetaData.getUserName(); System.out.println(userName); //獲取數(shù)據(jù)庫連接URL String userUrl = dbMetaData.getURL(); System.out.println(userUrl); //獲取數(shù)據(jù)庫驅(qū)動(dòng) String driverName = dbMetaData.getDriverName(); System.out.println(driverName); //獲取數(shù)據(jù)庫驅(qū)動(dòng)版本號(hào) String driverVersion = dbMetaData.getDriverVersion(); System.out.println(driverVersion); //查看數(shù)據(jù)庫是否允許讀操作 boolean isReadOnly = dbMetaData.isReadOnly(); System.out.println(isReadOnly); //查看數(shù)據(jù)庫是否支持事務(wù)操作 boolean supportsTransactions = dbMetaData.supportsTransactions(); System.out.println(supportsTransactions); }
(2)獲取數(shù)據(jù)庫列表
@Test public void testFindAllCatalogs() throws Exception { //獲取元數(shù)據(jù) DatabaseMetaData metaData = conn.getMetaData(); //獲取數(shù)據(jù)庫列表 ResultSet rs = metaData.getCatalogs(); //遍歷獲取所有數(shù)據(jù)庫表 while (rs.next()) { //打印數(shù)據(jù)庫名稱 System.out.println(rs.getString(1)); } //釋放資源 rs.close(); conn.close(); }
(3)獲取某數(shù)據(jù)庫中的所有表信息
@Test public void testFindAllTable() throws Exception { //獲取元數(shù)據(jù) DatabaseMetaData metaData = conn.getMetaData(); //獲取所有的數(shù)據(jù)庫表信息 ResultSet rs = metaData.getTables("庫名", "%", "%", new String[]{"TABLE"}); //拼裝table while (rs.next()) { //所屬數(shù)據(jù)庫 System.out.println(rs.getString(1)); //所屬schema System.out.println(rs.getString(2)); //表名 System.out.println(rs.getString(3)); //數(shù)據(jù)庫表類型 System.out.println(rs.getString(4)); //數(shù)據(jù)庫表備注 System.out.println(rs.getString(5)); System.out.println("--------------"); } }
(4)獲取某張表所有的列信息
@Test public void testFindAllColumns() throws Exception { //獲取元數(shù)據(jù) DatabaseMetaData metaData = conn.getMetaData(); //獲取所有的數(shù)據(jù)庫某張表所有列信息 ResultSet rs = metaData.getColumns("庫名", "%", "表名","%"); 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ù)庫執(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)如下
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ù)庫工具類
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ù)庫工具類 */ @Setter @Getter public class DbUtil { //數(shù)據(jù)庫連接地址 private String url = "jdbc:mysql://localhost:3306/heima_leadnews_wemedia?useSSL=false&nullCatalogMeansCurrent=true&serverTimezone=UTC"; //數(shù)據(jù)庫用戶名 private String username = "root"; //數(shù)據(jù)庫密碼 private String password = "123456"; //數(shù)據(jù)庫驅(qū)動(dòng) private String driver = "com.mysql.jdbc.Driver"; //數(shù)據(jù)庫名稱 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ù)庫下的所有表名稱及注釋 * @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ù)庫表信息 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ù)庫某張表所有列信息 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ù)庫字段名稱 user_name **/ private String columnName; /** * 數(shù)據(jù)庫字段類型 **/ private String columnType; /** * 數(shù)據(jù)庫字段首字母小寫且去掉下劃線字符串 userName **/ private String changeColumnName; /** * 數(shù)據(jù)庫字段注釋 **/ 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ù)庫相關(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ù)庫連接層</#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