乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      所謂代碼生成,簡(jiǎn)單!我詳細(xì)分析給你看!

       liang1234_ 2019-10-09

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

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

      我們來(lái)分析一下,因?yàn)樯婕暗奖矸聪蛏纱a,所以需要先設(shè)計(jì)好表結(jié)構(gòu)。有了表結(jié)構(gòu)之后我們就可以生成對(duì)應(yīng)的實(shí)體類(lèi),這個(gè)過(guò)程是怎么完成的呢?也就是說(shuō),后端怎么知道我有哪些數(shù)據(jù)表?然后每個(gè)數(shù)據(jù)表又長(zhǎng)什么樣子的呢?

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

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

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

      首先來(lái)說(shuō)說(shuō)第一種:

      information_schema中獲取

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

      • information_schema

      • performance_schema

      • mysql

      • sys

      information_schema

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

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

      performance_schema

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

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

      mysql

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

      sys

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

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

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

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

      得出的sql如下:

      1. SELECT

      2. *

      3. FROM

      4. information_schema. TABLES

      5. WHERE

      6. TABLE_SCHEMA = (SELECT DATABASE());

      因?yàn)槲覀冺?xiàng)目都是指定數(shù)據(jù)庫(kù)的,所以select database()就是連接的數(shù)據(jù)庫(kù)。結(jié)果如下:  上面,我們找出了數(shù)據(jù)庫(kù)third-homework的所有表名稱(chēng)。

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

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

      以u(píng)ser_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)駝峰,就得到我們的實(shí)體屬性,然后類(lèi)型在相對(duì)轉(zhuǎn)換成java的類(lèi)型,如varchar用String類(lèi)型等。

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

      show命令查看

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

      1. show table status;

      結(jié)果如下:

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

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

      1. show full fields from `user_action`;

      結(jié)果如下:

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

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

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

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

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

      • com.example.IndexController#index

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

      2. public String index(HttpServletRequest req) {

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

      4. return 'index';

      5. }

      然后頁(yè)面如下:

      • templates/index.ftl

      1. <!DOCTYPE html>

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

      3. <head>

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

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

      6. </head>

      7. <body>

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

      9. </body>

      10. </html>

      得到的頁(yè)面效果如下:

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

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

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

      • 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代碼比較長(zhǎng),就不貼出來(lái)了,原理就是先定義一個(gè)輸出流,然后使用模板把參數(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ù)模型都對(duì)應(yīng)的文件

      5. template.process(params, writer);

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

      于是我們?cè)L問(wèn)http://localhost:8080/toHtml/1234就得到如下結(jié)果:

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

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

      mybatis plus代碼生成器

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

      • https:///guide/generator.html

      (這里有個(gè)動(dòng)圖,但插入不進(jìn)來(lái),大家進(jìn)入鏈接看吧)

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

      我們先貼出生成器代碼,比較長(zhǎng):

      1. // 演示例子,執(zhí)行 main 方法控制臺(tái)輸入模塊表名回車(chē)自動(dòng)生成對(duì)應(yīng)項(xiàng)目目錄中

      2. public class CodeGenerator {

      3. /**

      4. * <p>

      5. * 讀取控制臺(tái)內(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('請(qǐng)輸入' 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('請(qǐng)輸入正確的' 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); 實(shí)體屬性 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. // 自定義配置會(huì)被優(yōu)先輸出

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

      60. @Override

      61. public String outputFile(TableInfo tableInfo) {

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

      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. // 判斷自定義文件夾是否需要?jiǎng)?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, 會(huì)根據(jù)使用的模板引擎自動(dòng)識(shí)別

      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. // 公共父類(lèi)

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

      97. // 寫(xiě)于父類(lèi)中的公共字段

      98. strategy.setSuperEntityColumns('id');

      99. strategy.setInclude(scanner('表名,多個(gè)英文逗號(hào)分割').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ù)源配置、輸出路徑配置、自定義模板配置、策略配置(配置超類(lèi)、公共字段等)。有了這些配置,就可以定義自己想要生成的效果,我們?cè)賮?lái)看看底層核心代碼。mpg.execute();方法里面核心的代碼如下:

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

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

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

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

      • batchOutput批量生成代碼

      • open打開(kāi)文件夾

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

      上面代碼中,開(kāi)頭就一個(gè)for循環(huán),循環(huán)所有的表,所以每個(gè)表都會(huì)生成controller等類(lèi),下面是獲取自定義的那些配置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. }

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

      • 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>

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

      結(jié)束

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

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類(lèi)似文章 更多