国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
所謂代碼生成,簡單!我詳細(xì)分析給你看!

現(xiàn)在很多開源的腳手架項目一般都會有自己的代碼生成器,能夠幫助快速生成代碼,一般都是根據(jù)表結(jié)構(gòu)生成實體,和實體對應(yīng)的操作類,比如controller、service、mapper等。這些初始新建的類都有個共同點,除了對應(yīng)的操作實體不一樣之外,其他沒啥區(qū)別,所以我們可以統(tǒng)一生成。除了后端的代碼,有些生成器還可以生成頁面,如表單、列表等。

說到這里,不經(jīng)想問一下,這代碼生成的原理是啥?

我們來分析一下,因為涉及到表反向生成代碼,所以需要先設(shè)計好表結(jié)構(gòu)。有了表結(jié)構(gòu)之后我們就可以生成對應(yīng)的實體類,這個過程是怎么完成的呢?也就是說,后端怎么知道我有哪些數(shù)據(jù)表?然后每個數(shù)據(jù)表又長什么樣子的呢?

這里給大家介紹兩種方法:

  • 1、通過默認(rèn)數(shù)據(jù)庫information_schema獲取

  • 2、通過show命令查看結(jié)構(gòu)或狀態(tài)

首先來說說第一種:

information_schema中獲取

大家在安裝完mysql之后,mysql并不是空的,而是默認(rèn)自帶了4個數(shù)據(jù)庫,分別如下:

  • information_schema

  • performance_schema

  • mysql

  • sys

information_schema

  • 保存整個mysql所有數(shù)據(jù)庫、表、索引的信息

 其中,用紅色框標(biāo)記出來的就是記錄著所有數(shù)據(jù)庫表和表字段信息的表。

performance_schema

  • 主要用于收集數(shù)據(jù)庫服務(wù)器性能參數(shù)

  • 提供進(jìn)程等待的詳細(xì)信息,包括鎖、互斥變量、文件信息;

mysql

  • 保存MySQL的權(quán)限、參數(shù)、對象和狀態(tài)信息。

sys

sys模式,這是一組幫助DBA和開發(fā)人員解釋性能模式收集的數(shù)據(jù)的對象。sys模式對象可用于典型的調(diào)優(yōu)和診斷用例。

這個sys數(shù)據(jù)庫雖然只有一個表,但是卻有大量的視圖: 

ok,上面我們對mysql中的幾個默認(rèn)數(shù)據(jù)庫做了一番認(rèn)識,那么現(xiàn)在我們找到答案了嗎?

information_schema數(shù)據(jù)庫中是不是存有所有的數(shù)據(jù)表和表字段信息,由此,我們就可以根據(jù)數(shù)據(jù)庫名稱獲取出所有的表,又可以通過表名稱獲取出具體的字段信息。

得出的sql如下:

  1. SELECT

  2. *

  3. FROM

  4. information_schema. TABLES

  5. WHERE

  6. TABLE_SCHEMA = (SELECT DATABASE());

因為我們項目都是指定數(shù)據(jù)庫的,所以select database()就是連接的數(shù)據(jù)庫。結(jié)果如下: 

 上面,我們找出了數(shù)據(jù)庫third-homework的所有表名稱。

有了表名稱我們是不是就可以生成實體啦?只需要去掉表前綴(如“t”等),然后下劃線轉(zhuǎn)駝峰,再首字母大寫,這樣useraction就轉(zhuǎn)成了UserAction實體了。

現(xiàn)在我們獲取到了所有表,那么接下來就循環(huán)獲取出所有表的字段信息。依然還是利用information_schema數(shù)據(jù)庫。

以user_action表為例子:

  1. SELECT

  2. *

  3. FROM

  4. information_schema. COLUMNS

  5. WHERE

  6. TABLE_SCHEMA = (SELECT DATABASE())

  7. AND TABLE_NAME = 'user_action';

 這樣,我們就又獲取到了字段信息,然后下劃線轉(zhuǎn)駝峰,就得到我們的實體屬性,然后類型在相對轉(zhuǎn)換成java的類型,如varchar用String類型等。

第一種方法總結(jié)如下:通過mysql的默認(rèn)數(shù)據(jù)庫information_schema中的TABLES和COLUMNS表的特性,通過條件查詢出對應(yīng)的數(shù)據(jù)表和字段的信息。

show命令查看

ok,接下來我們來看下show命令怎么來查看到指定數(shù)據(jù)庫的數(shù)據(jù)表和字段信息。首先來獲取third-homework數(shù)據(jù)庫下表的信息:

  1. show table status;

結(jié)果如下:

這里比較巧妙,這條命令的本意是查看所有表的一些狀態(tài)信息,所以就有字段是專門說明表名稱的,這樣我們就可以理解成是獲取所有表信息。

那有如何獲取表的字段呢?

  1. show full fields from `user_action`;

結(jié)果如下:

所以,我們又可以獲取到表的字段了。是不是挺簡單的?

好啦,上面都是教如何去獲取數(shù)據(jù)庫表和字段的,那么獲取到表結(jié)構(gòu)之后又是如何生成實體的呢?帶著這個問題我們繼續(xù)往下面去分析。

~~實體類是個java文件,一般來說我們要生成一個文件,我們需要一些文件操作類,先定義好模板,然后再傳參進(jìn)去,進(jìn)行渲染。比如我們要生成Excel、PDF等。但java文件不需要這么麻煩,java文件其實和一個txt文件的文本格式一樣,通常我們都可以直接把txt文件的后綴改成java后綴。然后html文件其實也算是一個txt文件,他們之間其實都可以相互強(qiáng)轉(zhuǎn)后綴,不影響打開和使用。~~

不知道大家有沒用過頁面靜態(tài)化?頁面靜態(tài)化的意思就是把原本需要動態(tài)加載和渲染的節(jié)點預(yù)先渲染成一個完全靜態(tài)的html頁面,這樣我們打開頁面的時候就完全是個靜態(tài)的html頁面,不再需要經(jīng)過后端的動態(tài)渲染,這樣可以大大減輕后端服務(wù)的壓力,同時提高響應(yīng)速度。

我們先來看下頁面靜態(tài)化是怎么做到的。首先,我們定義一個動態(tài)頁面,controller中傳參過去:

  • com.example.IndexController#index

  1. @GetMapping({'', '/', 'index'})

  2. public String index(HttpServletRequest req) {

  3. req.setAttribute('name', '呂一明');

  4. return 'index';

  5. }

然后頁面如下:

  • templates/index.ftl

  1. <!DOCTYPE html>

  2. <html lang='zh-CN'>

  3. <head>

  4. <meta charset='utf-8'>

  5. <title>公眾號:java思維導(dǎo)圖</title>

  6. </head>

  7. <body>

  8. <div>我是:<strong>${name}</strong></div>

  9. </body>

  10. </html>

得到的頁面效果如下:

那么有沒有辦法,不需要經(jīng)過controller,然后直接得出最后的這個頁面渲染結(jié)果呢?答案就是我們剛才說到的提前靜態(tài)化。因為我們頁面用的是模板引擎freemaker,所以用起來就簡單了。

百科介紹:FreeMarker是一款模板引擎 :即一種基于模板和要改變的數(shù)據(jù), 并用來生成輸出文本( HTML 網(wǎng)頁、 電子郵件 、 配置文件 、 源代碼 等)的通用工具。

所以我們使用freemaker,其實底層原理就是在后端預(yù)先把參數(shù)和模板進(jìn)行渲染之后得到網(wǎng)頁再傳給瀏覽器顯示的。所以我們?nèi)藶橄劝训讓拥匿秩静襟E先提取出來,代碼如下:

  • com.example.IndexController#toHtml

  1. @ResponseBody

  2. @RequestMapping('/toHtml/{id}')

  3. public Object toHtml(@PathVariable Long id, HttpServletRequest req) throws IOException {

  4. Template template = configuration.getTemplate('/index.ftl');

  5. String fileName = id '.html';

  6. String htmlDir = 'D:\\git-job\\open-demo\\src\\main\\resources\\static\\html';

  7. Map<String, Object> params = new HashMap<>();

  8. params.put('name', '呂一明' id);

  9. return FreemarkerUtil.printToFile(template, htmlDir, fileName, params);

  10. }

而FreemarkerUtil.printToFile代碼比較長,就不貼出來了,原理就是先定義一個輸出流,然后使用模板把參數(shù)和流渲染得到文件。關(guān)鍵代碼如下:

  1. //創(chuàng)建輸出流

  2. File file = new File(fileDir File.separator fileName);

  3. Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file),'UTF-8'));

  4. //輸出模板和數(shù)據(jù)模型都對應(yīng)的文件

  5. template.process(params, writer);

梳理一下,上面的代碼意思是我從templates中獲取index.ftl頁面,然后指定了一個params的map交給Template進(jìn)行渲染,得到的html頁面放在指定的static/html文件夾下。

于是我們訪問http://localhost:8080/toHtml/1234就得到如下結(jié)果:

就可以通過http://localhost:8080/html/1234.html訪問到靜態(tài)頁面。

以上就是利用模板引擎頁面靜態(tài)化的原理。那么這和我們代碼生成有什么關(guān)聯(lián)呢?其實大部分的代碼都是類似這樣生成的,優(yōu)先定義好模板,然后再往模板中塞字段信息等,最后渲染出一個java文件。

mybatis plus代碼生成器

接下來,我們?nèi)シ治鲆幌耺ybatis plus的代碼生成器。官網(wǎng)代碼生成器說明:

  • https://mybatis.plus/guide/generator.html

(這里有個動圖,但插入不進(jìn)來,大家進(jìn)入鏈接看吧)

上面是代碼生成的演示,可以看到輸入一些參數(shù)之后,自動幫我們生成controller、service等。

我們先貼出生成器代碼,比較長:

  1. // 演示例子,執(zhí)行 main 方法控制臺輸入模塊表名回車自動生成對應(yīng)項目目錄中

  2. public class CodeGenerator {

  3. /**

  4. * <p>

  5. * 讀取控制臺內(nèi)容

  6. * </p>

  7. */

  8. public static String scanner(String tip) {

  9. Scanner scanner = new Scanner(System.in);

  10. StringBuilder help = new StringBuilder();

  11. help.append('請輸入' tip ':');

  12. System.out.println(help.toString());

  13. if (scanner.hasNext()) {

  14. String ipt = scanner.next();

  15. if (StringUtils.isNotEmpty(ipt)) {

  16. return ipt;

  17. }

  18. }

  19. throw new MybatisPlusException('請輸入正確的' tip '!');

  20. }

  21. public static void main(String[] args) {

  22. // 代碼生成器

  23. AutoGenerator mpg = new AutoGenerator();

  24. // 全局配置

  25. GlobalConfig gc = new GlobalConfig();

  26. String projectPath = System.getProperty('user.dir');

  27. gc.setOutputDir(projectPath '/src/main/java');

  28. gc.setAuthor('jobob');

  29. gc.setOpen(false);

  30. // gc.setSwagger2(true); 實體屬性 Swagger2 注解

  31. mpg.setGlobalConfig(gc);

  32. // 數(shù)據(jù)源配置

  33. DataSourceConfig dsc = new DataSourceConfig();

  34. dsc.setUrl('jdbc:mysql://localhost:3306/ant?useUnicode=true&useSSL=false&characterEncoding=utf8');

  35. // dsc.setSchemaName('public');

  36. dsc.setDriverName('com.mysql.jdbc.Driver');

  37. dsc.setUsername('root');

  38. dsc.setPassword('密碼');

  39. mpg.setDataSource(dsc);

  40. // 包配置

  41. PackageConfig pc = new PackageConfig();

  42. pc.setModuleName(scanner('模塊名'));

  43. pc.setParent('com.baomidou.ant');

  44. mpg.setPackageInfo(pc);

  45. // 自定義配置

  46. InjectionConfig cfg = new InjectionConfig() {

  47. @Override

  48. public void initMap() {

  49. // to do nothing

  50. }

  51. };

  52. // 如果模板引擎是 freemarker

  53. String templatePath = '/templates/mapper.xml.ftl';

  54. // 如果模板引擎是 velocity

  55. // String templatePath = '/templates/mapper.xml.vm';

  56. // 自定義輸出配置

  57. List<FileOutConfig> focList = new ArrayList<>();

  58. // 自定義配置會被優(yōu)先輸出

  59. focList.add(new FileOutConfig(templatePath) {

  60. @Override

  61. public String outputFile(TableInfo tableInfo) {

  62. // 自定義輸出文件名 , 如果你 Entity 設(shè)置了前后綴、此處注意 xml 的名稱會跟著發(fā)生變化!!

  63. return projectPath '/src/main/resources/mapper/' pc.getModuleName()

  64. '/' tableInfo.getEntityName() 'Mapper' StringPool.DOT_XML;

  65. }

  66. });

  67. /*

  68. cfg.setFileCreate(new IFileCreate() {

  69. @Override

  70. public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) {

  71. // 判斷自定義文件夾是否需要創(chuàng)建

  72. checkDir('調(diào)用默認(rèn)方法創(chuàng)建的目錄');

  73. return false;

  74. }

  75. });

  76. */

  77. cfg.setFileOutConfigList(focList);

  78. mpg.setCfg(cfg);

  79. // 配置模板

  80. TemplateConfig templateConfig = new TemplateConfig();

  81. // 配置自定義輸出模板

  82. //指定自定義模板路徑,注意不要帶上.ftl/.vm, 會根據(jù)使用的模板引擎自動識別

  83. // templateConfig.setEntity('templates/entity2.java');

  84. // templateConfig.setService();

  85. // templateConfig.setController();

  86. templateConfig.setXml(null);

  87. mpg.setTemplate(templateConfig);

  88. // 策略配置

  89. StrategyConfig strategy = new StrategyConfig();

  90. strategy.setNaming(NamingStrategy.underline_to_camel);

  91. strategy.setColumnNaming(NamingStrategy.underline_to_camel);

  92. strategy.setSuperEntityClass('com.baomidou.ant.common.BaseEntity');

  93. strategy.setEntityLombokModel(true);

  94. strategy.setRestControllerStyle(true);

  95. // 公共父類

  96. strategy.setSuperControllerClass('com.baomidou.ant.common.BaseController');

  97. // 寫于父類中的公共字段

  98. strategy.setSuperEntityColumns('id');

  99. strategy.setInclude(scanner('表名,多個英文逗號分割').split(','));

  100. strategy.setControllerMappingHyphenStyle(true);

  101. strategy.setTablePrefix(pc.getModuleName() '_');

  102. mpg.setStrategy(strategy);

  103. mpg.setTemplateEngine(new FreemarkerTemplateEngine());

  104. mpg.execute();

  105. }

  106. }

上面做了一些配置,比如全局配置基本參數(shù)、數(shù)據(jù)源配置、輸出路徑配置、自定義模板配置、策略配置(配置超類、公共字段等)。有了這些配置,就可以定義自己想要生成的效果,我們再來看看底層核心代碼。mpg.execute();方法里面核心的代碼如下:

  1. // 模板引擎初始化執(zhí)行文件輸出

  2. templateEngine.init(this.pretreatmentConfigBuilder(config)).mkdirs().batchOutput().open();

  • init方法初始化環(huán)境,

  • mkdirs方法創(chuàng)建文件夾,

  • batchOutput批量生成代碼

  • open打開文件夾

所以核心的代碼再batchOutput方法中,我們?nèi)タ纯矗?/p>

上面代碼中,開頭就一個for循環(huán),循環(huán)所有的表,所以每個表都會生成controller等類,下面是獲取自定義的那些配置getObjectMap(tableInfo)方法;可以看下獲取到的參數(shù):

上面初始化了很多參數(shù),有了這些參數(shù),然后我們進(jìn)入writer方法中進(jìn)行渲染。我們看看writer方法:

  1. @Override

  2. public void writer(Map<String, Object> objectMap, String templatePath, String outputFile) throws Exception {

  3. Template template = configuration.getTemplate(templatePath);

  4. try (FileOutputStream fileOutputStream = new FileOutputStream(outputFile)) {

  5. template.process(objectMap, new OutputStreamWriter(fileOutputStream, ConstVal.UTF8));

  6. }

  7. logger.debug('模板:' templatePath '; 文件:' outputFile);

  8. }

看到這個方法,是不是和之前我們頁面靜態(tài)化的處理方式一樣的,通過template.process處理模板和參數(shù)得到文件。我們看看其中一個模板是怎么定義的,比如

  • mapper.java.ftl

  1. package ${package.Mapper};

  2. import ${package.Entity}.${entity};

  3. import ${superMapperClassPackage};

  4. /**

  5. * <p>

  6. * ${table.comment!} Mapper 接口

  7. * </p>

  8. *

  9. * @author ${author}

  10. * @since ${date}

  11. */

  12. <#if kotlin>

  13. interface ${table.mapperName} : ${superMapperClass}<${entity}>

  14. <#else>

  15. public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {

  16. }

  17. </#if>

我們再對比一下mapper.java.ftl還有之前初始化的參數(shù),渲染之后輸出為java文件,是不是就達(dá)到了我們代碼生成的效果了。

結(jié)束

好了,今天文章先到這里了。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
CodeSmith模板代碼生成實戰(zhàn)詳解
基于JavaScript的代碼自動生成工具
SpringBoot時間格式化的5種方法!
Mybatis類型轉(zhuǎn)換介紹
IDEA 28 個天花板技巧!
oracle 把查詢結(jié)果插入到表中幾種方式
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服