從mybatis-plus-generator看如何編寫(xiě)代碼生成器

      網(wǎng)友投稿 950 2025-04-02

      項(xiàng)目中常常用到代碼生成器生成代碼,下面介紹velocity代碼生成原理,及如何編寫(xiě)代碼生成器。


      Velocity介紹

      Velocity是一個(gè)基于Java的模板引擎,基于MVC模型實(shí)現(xiàn),其提供了一個(gè)Context容器(相當(dāng)于Spring的Model),在java代碼里面我們可以往容器中存值,然后在vm文件中使用特定的語(yǔ)法獲取(相當(dāng)于Spring頁(yè)面中取值如freemarker、thymeleaf)。

      官網(wǎng):http://velocity.apache.org/

      maven引入

      org.apache.velocity velocity 1.7

      velocity 基本語(yǔ)法

      設(shè)置變量 #set($foo =“hello”) 取值 $foo

      訪問(wèn)對(duì)象屬性 $user.name ${user.name}

      使用

      v

      a

      r

      i

      獲取變量時(shí),如果變量不存在,

      V

      e

      l

      o

      c

      i

      t

      y

      引擎會(huì)將其原樣輸出,通過(guò)使用

      vari獲取變量時(shí),如果變量不存在,Velocity引擎會(huì)將其原樣輸出,通過(guò)使用

      vari獲取變量時(shí),如果變量不存在,Velocity引擎會(huì)將其原樣輸出,通過(guò)使用!{}的形式可以將不存在的變量變成空白輸出. 見(jiàn)示例 ${notExist} $!{notExistEmpty}

      velocity中大小寫(xiě)敏感。

      #foreach($i in $list) $i #end

      velocity 只會(huì)替換變量,所以velocity的語(yǔ)句一般頂行寫(xiě),以保持文件格式

      如上 $i前的空格將會(huì)原樣輸出

      #if(condition) ...dosonmething... #elseif(condition) ...dosomething... #else ...dosomething... #end

      hello world generator

      初始化了VelocityEngine這個(gè)模板引擎,對(duì)其設(shè)置參數(shù)進(jìn)行初始化,指定使用ClasspathResourceLoader來(lái)加載vm文件。

      在VelocityContext這個(gè)Velocity容器中存放對(duì)象了。

      在.vm文件中我們可以取出這些變量,

      Template模板輸出 template.merge(ctx,sw)

      public class HelloWorldVelocity { public static void main(String[] args) { // 初始化模板引擎 VelocityEngine velocityEngine = new VelocityEngine(); velocityEngine.setProperty(RuntimeConstants.RESOURCE_LOADER, "classpath"); velocityEngine.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName()); velocityEngine.init(); // 獲取模板文件 Template template = velocityEngine.getTemplate("helloVelocity.vm"); // 設(shè)置變量 VelocityContext ctx = new VelocityContext(); ctx.put("name", "Velocity"); User user = new User(); user.setName("zhang san"); user.setPhone("18612345678"); ctx.put("user", user); List list = new ArrayList(); list.add("1"); list.add("2"); ctx.put("list", list); // 輸出 StringWriter sw = new StringWriter(); template.merge(ctx,sw); System.out.println(sw.toString()); }

      resouces目錄下的模板文件helloVelocity.vm

      #set($foo = 'hello') $foo $name ${notExist} $!{notExistEmpty} $user.name ${user.name} #foreach($i in $list) $i #end

      Gitee: https://gitee.com/tg_seahorse/paw-demos/tree/master/paw-generator

      Mybatis-Plus-generator

      Mybatsi-Plus官網(wǎng)文檔

      官網(wǎng)源碼Git

      com.baomidou Mybatis-plus-generator 3.4.1

      MyBatis-Plus 支持 Velocity(默認(rèn))、Freemarker、Beetl模板引擎

      org.apache.velocity velocity-engine-core 2.3

      參照官網(wǎng)修改的生成代碼類

      配置信息寫(xiě)在了main方法的開(kāi)頭,項(xiàng)目路徑、包名、要生成的表、表前綴

      配置數(shù)據(jù)源 mysql 引入依賴mysql-connector-java

      cfg.setFileCreate 文件生成策略,return true 會(huì)生成文件,覆蓋原有文件。

      開(kāi)啟swaggergc.setSwagger2(true);代碼使用時(shí)需引入swagger依賴

      com.github.xiaoymin knife4j-spring-boot-starter

      代碼生成類

      public class CodeGenerator { public static void main(String[] args) { String projectPath = "/Users/rubble/workSpace/paw/paw-demos/paw-generator"; String author = "Rubble"; String packageParent = "com.paw.generator"; String module = "system"; // 多個(gè)用,分隔 String tables = "sys_user"; String tablePrefix = "sys_"; // 代碼生成器 AutoGenerator mpg = new AutoGenerator(); // 全局配置 GlobalConfig gc = new GlobalConfig(); gc.setOutputDir(projectPath + "/src/main/java"); gc.setAuthor(author); gc.setOpen(false); // gc.setSwagger2(true); 實(shí)體屬性 Swagger2 注解 mpg.setGlobalConfig(gc); // 數(shù)據(jù)源配置 DataSourceConfig dsc = new DataSourceConfig(); dsc.setUrl("jdbc:mysql://localhost:3306/ry?useUnicode=true&useSSL=false&characterEncoding=utf8"); // dsc.setSchemaName("public"); dsc.setDriverName("com.mysql.cj.jdbc.Driver"); dsc.setUsername("root"); dsc.setPassword("123456"); mpg.setDataSource(dsc); // 包配置 PackageConfig pc = new PackageConfig(); pc.setModuleName(module); pc.setParent(packageParent); mpg.setPackageInfo(pc); // 自定義配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap() { // to do nothing } }; // 如果模板引擎是 freemarker // String templatePath = "/templates/mapper.xml.ftl"; // 如果模板引擎是 velocity String templatePath = "/templates/mapper.xml.vm"; // 自定義輸出配置 List focList = new ArrayList<>(); // 自定義配置會(huì)被優(yōu)先輸出 focList.add(new FileOutConfig(templatePath) { @Override public String outputFile(TableInfo tableInfo) { // 自定義輸出文件名 , 如果你 Entity 設(shè)置了前后綴、此處注意 xml 的名稱會(huì)跟著發(fā)生變化!! return projectPath + "/src/main/resources/mapper/" + pc.getModuleName() + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML; } }); /* 允許生成模板文件 */ cfg.setFileCreate(new IFileCreate() { @Override public boolean isCreate(ConfigBuilder configBuilder, FileType fileType, String filePath) { // 判斷自定義文件夾是否需要?jiǎng)?chuàng)建 checkDir(projectPath); if (fileType == FileType.MAPPER) { // 已經(jīng)生成 mapper 文件判斷存在,不想重新生成返回 false return !new File(filePath).exists(); } // 允許生成模板文件 return true; } }); cfg.setFileOutConfigList(focList); mpg.setCfg(cfg); // 配置模板 TemplateConfig templateConfig = new TemplateConfig(); // 配置自定義輸出模板 //指定自定義模板路徑,注意不要帶上.ftl/.vm, 會(huì)根據(jù)使用的模板引擎自動(dòng)識(shí)別 // templateConfig.setEntity("templates/entity2.java"); // templateConfig.setService(); // templateConfig.setController(); templateConfig.setXml(null); mpg.setTemplate(templateConfig); // 策略配置 StrategyConfig strategy = new StrategyConfig(); strategy.setNaming(NamingStrategy.underline_to_camel); strategy.setColumnNaming(NamingStrategy.underline_to_camel); // strategy.setSuperEntityClass("你自己的父類實(shí)體,沒(méi)有就不用設(shè)置!"); strategy.setEntityLombokModel(true); strategy.setRestControllerStyle(true); // 公共父類 // strategy.setSuperControllerClass("你自己的父類控制器,沒(méi)有就不用設(shè)置!"); // 寫(xiě)于父類中的公共字段 strategy.setSuperEntityColumns("id"); strategy.setInclude(tables.split(",")); strategy.setControllerMappingHyphenStyle(true); strategy.setTablePrefix(tablePrefix); mpg.setStrategy(strategy); mpg.setTemplateEngine(new VelocityTemplateEngine()); mpg.execute(); } }

      CodeGenerator可以用于日常基于mybatis-plus項(xiàng)目的開(kāi)發(fā)中。

      自定義模板

      擴(kuò)展control模板

      Mybatis-plus 模板默認(rèn)位置resources/templates下,可在配置中進(jìn)行修改templatePath

      從git項(xiàng)目或jar包中復(fù)制controller.java.vm 增加CRUD的方法,只寫(xiě)了簡(jiǎn)單的add、list方法,可自行就行擴(kuò)展,如增加分頁(yè)查找。

      package ${package.Controller}; import java.util.List; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.paw.generator.system.entity.User; import com.paw.generator.system.service.IUserService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; #if(${restControllerStyle}) import org.springframework.web.bind.annotation.RestController; #else import org.springframework.stereotype.Controller; #end #if(${superControllerClassPackage}) import ${superControllerClassPackage}; #end /** *

      * $!{table.comment} 前端控制器 *

      * * @author ${author} * @since ${date} */ #if(${restControllerStyle}) @RestController #else @Controller #end @RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end") #if(${kotlin}) class ${table.controllerName}#if(${superControllerClass}) : ${superControllerClass}()#end #else #if(${superControllerClass}) public class ${table.controllerName} extends ${superControllerClass} { #else public class ${table.controllerName} { #end @Autowired private ${table.serviceName} service; @GetMapping("add") public Object add(${entity} entity){ boolean saved = service.save(entity); return entity; } @GetMapping("list") public List<${entity}> list(${entity} entity){ return service.list(new QueryWrapper<>(entity)); } } #end

      生成代碼

      /** *

      * 用戶信息表 前端控制器 *

      * * @author Rubble * @since 2021-07-07 */ @RestController @RequestMapping("/system/user") public class UserController { @Autowired private IUserService service; @GetMapping("add") public Object add(User entity){ boolean saved = service.save(entity); return entity; } @GetMapping("list") public List list(User entity){ return service.list(new QueryWrapper<>(entity)); } }

      自定義模板hello

      配置中增加模板hello.java.vm,定義文件輸出位置

      String helloTemplatePath = "/templates/hello.java.vm"; focList.add(new FileOutConfig(helloTemplatePath) { @Override public String outputFile (TableInfo tableInfo) { return projectPath + "/src/main/java/" + packageParent.replace(".", File.separator) + File.separator + pc.getModuleName() + File.separator + "entity" + File.separator + "Hello" + tableInfo.getEntityName() + StringPool.DOT_JAVA; } });

      最簡(jiǎn)單的模板

      package ${package.Entity}; public class Hello${entity}{ }

      執(zhí)行輸出

      package com.paw.generator.system.entity; public class HelloUser{ }

      mybatis-plus-generator解析

      git下載項(xiàng)目,用jdk8, gradle 6.3 編譯通過(guò)。

      自動(dòng)配置類AutoGenerator, 除datasource外其他均可默認(rèn)設(shè)置。

      /** * 配置信息 */ protected ConfigBuilder config; /** * 注入配置 */ protected InjectionConfig injection; /** * 數(shù)據(jù)源配置 */ private DataSourceConfig dataSource; /** * 數(shù)據(jù)庫(kù)表配置 */ private StrategyConfig strategy; /** * 包 相關(guān)配置 */ private PackageConfig packageInfo; /** * 模板 相關(guān)配置 */ private TemplateConfig template; /** * 全局 相關(guān)配置 */ private GlobalConfig globalConfig;

      模板引擎

      AbstractTemplateEngine 實(shí)現(xiàn)了文件的輸出controller、service、 entity、mapper。

      VelocityTemplateEngine模板引擎

      init()初始化VelocityEngine指定文件位置、編碼等;

      writer引擎模板的渲染 template.merge(new VelocityContext(objectMap), writer);

      Map objectMap = this.getObjectMap(config, tableInfo);

      @Override public @NotNull VelocityTemplateEngine init(@NotNull ConfigBuilder configBuilder) { if (null == velocityEngine) { Properties p = new Properties(); p.setProperty(ConstVal.VM_LOAD_PATH_KEY, ConstVal.VM_LOAD_PATH_VALUE); p.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, StringPool.EMPTY); p.setProperty(Velocity.ENCODING_DEFAULT, ConstVal.UTF8); p.setProperty(Velocity.INPUT_ENCODING, ConstVal.UTF8); p.setProperty("file.resource.loader.unicode", StringPool.TRUE); velocityEngine = new VelocityEngine(p); } return this; } @Override public void writer(@NotNull Map objectMap, @NotNull String templatePath, @NotNull File outputFile) throws Exception { Template template = velocityEngine.getTemplate(templatePath, ConstVal.UTF8); try (FileOutputStream fos = new FileOutputStream(outputFile); OutputStreamWriter ow = new OutputStreamWriter(fos, ConstVal.UTF8); BufferedWriter writer = new BufferedWriter(ow)) { template.merge(new VelocityContext(objectMap), writer); } }

      // objectMap在 AbstractTemplateEngine類中 從配置文件中生成上下文變量加入到context中

      objectMap.put的即在模板中可用的屬性。

      主要屬性 PackageInfo, TableInfo

      @NotNull public Map getObjectMap(@NotNull ConfigBuilder config, @NotNull TableInfo tableInfo) { GlobalConfig globalConfig = config.getGlobalConfig(); Map controllerData = config.getStrategyConfig().controller().renderData(tableInfo); Map objectMap = new HashMap<>(controllerData); Map mapperData = config.getStrategyConfig().mapper().renderData(tableInfo); objectMap.putAll(mapperData); Map serviceData = config.getStrategyConfig().service().renderData(tableInfo); objectMap.putAll(serviceData); Map entityData = config.getStrategyConfig().entity().renderData(tableInfo); objectMap.putAll(entityData); objectMap.put("config", config); objectMap.put("package", config.getPackageConfig().getPackageInfo()); objectMap.put("author", globalConfig.getAuthor()); objectMap.put("kotlin", globalConfig.isKotlin()); objectMap.put("swagger", globalConfig.isSwagger()); objectMap.put("date", globalConfig.getCommentDate()); // 存在 schemaName 設(shè)置拼接 . 組合表名 String schemaName = config.getDataSourceConfig().getSchemaName(); if (StringUtils.isNotBlank(schemaName)) { schemaName += "."; tableInfo.setConvert(true); } else { schemaName = ""; } objectMap.put("schemaName", schemaName); objectMap.put("table", tableInfo); objectMap.put("entity", tableInfo.getEntityName()); return objectMap; }

      下載源碼的方式擴(kuò)展可以任意的put你想要的屬性。

      引用jar的方式可以增加全局自定義配置, 模板中使用 ${cfg.abc}

      // 自定義配置 InjectionConfig cfg = new InjectionConfig() { @Override public void initMap () { // to do nothing Map map = new HashMap<>(); map.put("abc","123"); setMap(map); } };

      若依(ruoyi)框架中的generator

      本文是若依單體項(xiàng)目thymeleaf版本。module: ruoyi-generator.

      生成工具通過(guò)后臺(tái)管理界面的方式讓用戶進(jìn)行設(shè)置,配置信息保存在數(shù)據(jù)庫(kù)中,根據(jù)配置生成一套CRUD代碼,很是方便。

      入口控制類GenController preview 預(yù)覽代碼, download 下載zip包,genCode生成代碼。

      數(shù)據(jù)庫(kù)查詢配置信息GenTable 加入到VelocityContext中,在vm模板中即可取值

      對(duì)定義的模板進(jìn)行渲染 tpl.merge(context, sw)

      public Map previewCode(Long tableId) { Map dataMap = new LinkedHashMap<>(); // 查詢表信息 GenTable table = genTableMapper.selectGenTableById(tableId); // 設(shè)置主子表信息 setSubTable(table); // 設(shè)置主鍵列信息 setPkColumn(table); VelocityInitializer.initVelocity(); VelocityContext context = VelocityUtils.prepareContext(table); // 獲取模板列表 List templates = VelocityUtils.getTemplateList(table.getTplCategory()); for (String template : templates) { // 渲染模板 StringWriter sw = new StringWriter(); Template tpl = Velocity.getTemplate(template, Constants.UTF8); tpl.merge(context, sw); dataMap.put(template, sw.toString()); } return dataMap; }

      Put到VelocityContext中的變量

      public static VelocityContext prepareContext(GenTable genTable) { String moduleName = genTable.getModuleName(); String businessName = genTable.getBusinessName(); String packageName = genTable.getPackageName(); String tplCategory = genTable.getTplCategory(); String functionName = genTable.getFunctionName(); VelocityContext velocityContext = new VelocityContext(); velocityContext.put("tplCategory", genTable.getTplCategory()); velocityContext.put("tableName", genTable.getTableName()); velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【請(qǐng)?zhí)顚?xiě)功能名稱】"); velocityContext.put("ClassName", genTable.getClassName()); velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); velocityContext.put("moduleName", genTable.getModuleName()); velocityContext.put("businessName", genTable.getBusinessName()); velocityContext.put("basePackage", getPackagePrefix(packageName)); velocityContext.put("packageName", packageName); velocityContext.put("author", genTable.getFunctionAuthor()); velocityContext.put("datetime", DateUtils.getDate()); velocityContext.put("pkColumn", genTable.getPkColumn()); velocityContext.put("importList", getImportList(genTable)); velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); velocityContext.put("columns", genTable.getColumns()); velocityContext.put("table", genTable); setMenuVelocityContext(velocityContext, genTable); if (GenConstants.TPL_TREE.equals(tplCategory)) { setTreeVelocityContext(velocityContext, genTable); } if (GenConstants.TPL_SUB.equals(tplCategory)) { setSubVelocityContext(velocityContext, genTable); } return velocityContext; }

      生成代碼的模板,

      html: crud的方法add.html,edit.html,list.html,list-tree.html

      Java: controller,service,domain,mapper,serviceImpl

      從mybatis-plus-generator看如何編寫(xiě)代碼生成器

      Sql:生成菜單用

      自定義的mapper.xml

      若依框架generator為前端頁(yè)面框架ruoyi-admin生成了一套完美契合的快速開(kāi)發(fā)的CRUD代碼,并支持的用戶的選擇配置,頁(yè)面的查詢功能都已封裝,在此學(xué)習(xí),向大神致敬。

      總結(jié):

      velocity模板引擎分三步,1.初始化 配置模板加載地址;2.放置上下文變量velocityContext;3.渲染模板。

      有框架的項(xiàng)目一般會(huì)為,框架定制一個(gè)代碼生成器,以使代碼規(guī)范化,同時(shí)提高開(kāi)發(fā)效率。

      個(gè)人項(xiàng)目或中小項(xiàng)目開(kāi)發(fā)應(yīng)用現(xiàn)成框架即可,若不滿足需求,要進(jìn)行修改,了解模板原理,即可快速擴(kuò)展。

      擼文不易,感謝您的鼓勵(lì)。

      Generator Java MyBatis

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實(shí)的內(nèi)容,請(qǐng)聯(lián)系我們jiasou666@gmail.com 處理,核實(shí)后本網(wǎng)站將在24小時(shí)內(nèi)刪除侵權(quán)內(nèi)容。

      上一篇:Excel如何在單元格內(nèi)批量加前綴或后綴?
      下一篇:企業(yè)生產(chǎn)管理目標(biāo)(企業(yè)生產(chǎn)管理目標(biāo)主要內(nèi)容)
      相關(guān)文章
      亚洲精品视频在线播放| 亚洲a在线视频视频| 亚洲欧洲尹人香蕉综合| 亚洲av无码国产精品夜色午夜| 久久综合亚洲色HEZYO国产| 亚洲国产成人爱av在线播放| 国产精品自拍亚洲| 亚洲av无码乱码在线观看野外| 久久亚洲中文无码咪咪爱| 亚洲av成人一区二区三区观看在线 | 亚洲人成网站观看在线播放| 亚洲国产小视频精品久久久三级| 亚洲av无码成人精品区在线播放| 亚洲AV无码不卡在线观看下载| 亚洲国产成人久久精品99 | 午夜亚洲国产理论秋霞| 亚洲国产高清人在线| 色播亚洲视频在线观看| 亚洲美免无码中文字幕在线| 亚洲大片免费观看| 亚洲天堂2016| 亚洲精品无码永久在线观看男男| 亚洲成av人片在线天堂无| 日产国产精品亚洲系列| 亚洲精品无码久久久| 亚洲色成人中文字幕网站 | 亚洲欧美国产日韩av野草社区| 亚洲国产一区二区三区在线观看 | 亚洲一区影音先锋色资源| 亚洲国产精品线观看不卡| 亚洲中文字幕久久精品无码A| 亚洲精品9999久久久久无码| 亚洲第一页综合图片自拍| 久久乐国产精品亚洲综合| 国产亚洲精品一品区99热| 色婷婷亚洲十月十月色天| 2020亚洲男人天堂精品| 风间由美在线亚洲一区| 中文字幕无码精品亚洲资源网| 亚洲中文字幕无码久久2017| 亚洲狠狠久久综合一区77777|