自定义MBG:Mybatis-Generator使用FreeMarker进行代码生成

在最初的了解中,mybatis官方是有MBG的,但网上一直说不好用。于是网络上有各种开源MBG,各有优劣。基本上难以满足一些自定义的需求。

在百度摸索几天后,我决定自定义一个符合自己项目的generator,使用FreeMarker模板引擎,生成实体,mapper接口,MapperXml,Service,ServiceImpl,以及Controller

代码如下
思路:建立一个工具类执行入口,指定要生成实体的数据源、生成位置等信息

package com.kichun.ucenter;

import com.kichun.common.util.FreeMarkerGeneratorUtil;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**

  • 代码生成器配置

  • Created by wangqichang on 2018/5/31.
    /
    @SpringBootTest
    @RunWith(SpringJUnit4ClassRunner.class)
    @Slf4j
    public class CodeGenerator {
    /
    *

    • 数据库驱动
    • 未提供注入时请自行提供驱动
      /
      @Value("${druid.primary.driverClassName}")
      private String driverClassName;
      /
      *
    • 数据库URL
      /
      @Value("${druid.primary.url}")
      private String url;
      /
      *
    • 用户名
      */
      @Value("${druid.primary.username}")
      private String username;

    /**

    • 密码
      */
      @Value("${druid.primary.password}")
      private String password;

    /**

    • 数据库名
      */
      private String databaseName = “kichun_dev”;

    /**

    • 只生成单表,非必须
      */
      private String tableName = “”;

    /**

    • 表前缀,非必须
      */
      private String tablePrefix = “t_”;

    /**

    • 生成级别 必须
    • 1 仅生成dao层
    • 2 生成service层
    • 3 生成controller层
      */
      private int genenaterLevel = 1;

    /**

    • 基本包名 必须
      */
      private String basePackage = “com.kichun.ucenter.entity”;

    /**

    • mapper接口包名 无则使用基本包名
      */
      private String mapperPackage = “”;

    /**

    • mapper.xml 生成路径 无则使用基本包名
      */
      private String xmlDir = “”;

    /**

    • servcie包名 impl也在此包路径下 无则使用基本包名
      */
      private String servicePackage = “”;

    /**

    • controller包名 无则使用基本包名
      */
      private String controllerPackage = “”;

    @Test
    public void freeMarkerTest() {
    FreeMarkerGeneratorUtil.generatorMvcCode(
    driverClassName,
    url,
    username,
    password,
    tableName,
    databaseName,
    tablePrefix,
    genenaterLevel,
    basePackage,
    mapperPackage,
    xmlDir,
    servicePackage,
    controllerPackage);
    }

}

第二,定义工具类,根据提供的配置查询数据库,遍历表,根据对应模板文件生成文件到指定输出目录(可以根据包名生成对应目录)

ps:仅完成了实体生成,其他文件因为未准备模板没有时间继续搞了,但思路是ok的

package com.kichun.common.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.kichun.common.vo.Coloum;
import com.kichun.common.vo.EntityDataModel;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**

  • 代码生成工具类

  • Created by wangqichang on 2018/5/30.
    */
    @Slf4j
    public class FreeMarkerGeneratorUtil {

    /**

    • 生成三层代码 包含 仅生成dao层 (包含实体Entity及mapper接口及xml) 生成service层 (包含service接口及impl) 生成controller层

    • @param driver

    • @param url

    • @param user

    • @param pwd
      */
      public static void generatorMvcCode(String driver, String url, String user, String pwd, String tableName, String databaseName,
      String tablePrefix, int generateLevel, String basePackage, String mapperPackage, String xmlDir, String servicePackage,
      String controllerPackage) {

      Connection con = null;
      //注册驱动
      try {
      Class.forName(driver);
      con = DriverManager.getConnection(url, user, pwd);
      } catch (Exception e) {
      log.error(“获取数据连接失败,{}”, e.getMessage());
      return;
      }

      //查询dbName所有表
      String sql = “select table_name from information_schema.tables where table_schema=’” + databaseName + “’”;

      //获取当前项目路径
      String path = FreeMarkerGeneratorUtil.class.getResource("/").getPath();
      path = StrUtil.sub(path, 1, path.indexOf("/target"));

      log.info(“当前项目路径为:{}”, path);
      String parentProjectPath = StrUtil.sub(path, 0, path.lastIndexOf("/"));
      //获取模板路径
      String templatePath = path + “/src/main/resources/template”;
      log.info(“当前模板路径为:{}”, templatePath);

      boolean onlySingleTable = StrUtil.isNotBlank(tableName);
      try {

       PreparedStatement ps = con.prepareStatement(sql);
       ResultSet rs = ps.executeQuery();
       while (rs.next()) {
           if (!onlySingleTable) {
               tableName = rs.getString(1);
           }
           String entityDir = null;
           //根据实体包名创建目录
           if (generateLevel > 0) {
               File[] ls = FileUtil.ls(parentProjectPath);
               for (File f: ls) {
                   String currModule = f.toString();
                   boolean matches = currModule.matches("(.*?pojo.*?)|(.*?domain.*?)|(.*?entity.*?)");
                   if (f.isDirectory()&&matches){
                       entityDir = f.toString()+ "/src/main/java/" + basePackage.replace(".", "/");
                       break;
                   }
               }
               if (StrUtil.isBlank(entityDir)){
                   entityDir = path + "/src/main/java/" + basePackage.replace(".", "/");
               }
               if (!FileUtil.exist(entityDir)) {
                   FileUtil.mkdir(entityDir);
                   log.info("创建目录:{} 成功! ",entityDir);
               }
           }
           EntityDataModel entityModel = getEntityModel(con, tableName, basePackage, tablePrefix);
           //生成每个表实体
           generateCode(entityModel, templatePath, "Entity.ftl", entityDir);
           //创建mapperxml路径
      
           /*String mapperxmlPath = null;
           //根据实体包名创建目录
           if (StrUtil.isNotBlank(mapperPackage)) {
               mapperxmlPath = path + mapperPackage.replace(".", "/");
               if (!FileUtil.exist(mapperxmlPath)) {
                   FileUtil.mkdir(mapperxmlPath);
               }
           } else {
               mapperxmlPath = entityDir;
           }*/
           //generateCode(MapperXmlDataModel,templatePath,"MapperXml.ftl",mapperxmlPath);
      
           //创建service包名
           //创建serviceImpl包名
           //创建controller包名
      
           //生成mapper
           //生成xml
           //生成service
           //生成impl
           //生成controller
           if (onlySingleTable) {
               return;
           }
       }
      

      } catch (Exception e) {
      log.error(“代码生成出错 {}”, e.getMessage());
      }

    }

    private static EntityDataModel getEntityModel(Connection con, String tableName, String basePackage, String tablePrefix)
    throws Exception {
    //查询表属性,格式化生成实体所需属性
    String sql = "SELECT table_name, column_name, column_comment, column_type, column_key, column_default "
    + "FROM INFORMATION_SCHEMA. COLUMNS " + “WHERE table_name = '” + tableName + "’ " + “AND table_schema = ‘kichun_dev’”;

     PreparedStatement ps = con.prepareStatement(sql);
     ResultSet rs = ps.executeQuery();
    
     List<Coloum> columns = new ArrayList<>();
     while (rs.next()) {
         Coloum col = new Coloum();
         String name = rs.getString("column_name");
         String type = rs.getString("column_type");
         String comment = rs.getString("column_comment");
         String annotation = null;
         if ("id".equals(name)) {
             if (type.contains("int")) {
                 annotation = "@TableId(type = IdType.AUTO)";
             }
         }
         if (type.contains("varchar")) {
             type = "String";
         } else if (type.contains("datetime")) {
             type = "Date";
         } else if (type.contains("int")) {
             type = "Integer";
         } else {
             type = "String";
         }
         col.setName(StrUtil.toCamelCase(name));
         col.setType(type);
         col.setAnnotation(annotation);
         col.setComment(comment);
         columns.add(col);
     }
     EntityDataModel dataModel = new EntityDataModel();
     dataModel.setEntityPackage(basePackage);
     dataModel.setCreateTime(new Date().toString());
     if (StrUtil.isNotBlank(tablePrefix)) {
         dataModel.setEntityName(StrUtil.upperFirst(StrUtil.toCamelCase(StrUtil.removePrefix(tableName, tablePrefix))));
     } else {
         dataModel.setEntityName(StrUtil.upperFirst(StrUtil.toCamelCase(tableName)));
     }
     dataModel.setTableName(tableName);
     dataModel.setColumns(columns);
     return dataModel;
    

    }

    private static void generateCode(EntityDataModel dataModel, String templatePath, String templateName, String outDir)
    throws IOException, TemplateException {

     String file = outDir +"/"+ dataModel.getEntityName() + dataModel.getFileSuffix();
     if (FileUtil.exist(file)){
         log.info("文件:{} 已存在,如需覆盖请先对该文件进行");
         return;
     }
     //获取模板对象
     Configuration conf = new Configuration();
     File temp = new File(templatePath);
     conf.setDirectoryForTemplateLoading(temp);
     Template template = conf.getTemplate(templateName);
     Writer writer = new FileWriter(file);
     //填充数据模型
     template.process(dataModel, writer);
     writer.close();
     log.info("代码生成成功,文件位置:{}",file);
    

    }
    }

实体模板Entity.ftl参考

ps :可以使用其他模板引擎进行生成,注意需要引入相关引擎依赖

package ${entityPackage};

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**

  • ${entityName} 实体类

  • Created by ${author} on c r e a t e T i m e . ∗ / @ D a t a @ T a b l e N a m e ( " {createTime}. */ @Data @TableName(" createTime./@Data@TableName("{tableName}")
    public class ${entityName} implements Serializable{
    <#list columns as column>

    /**

    • ${(column.comment)!}
      */
      ${(column.annotation)!}
      private ${column.type} ${column.name};
      </#list>
      }

数据模型参考

package com.kichun.common.vo;

import lombok.Data;

import java.util.Date;
import java.util.List;

/**

  • 模板生成属性

  • Created by wangqichang on 2018/5/30.
    /
    @Data
    public class EntityDataModel {
    /
    *

    • base package
      /
      private String entityPackage;
      /
      *
    • 文件名后缀
      */
      private String fileSuffix = “.java”;

    /**

    • 实体名
      */
      private String entityName;

    /**

    • 作者 默认
      */
      private String author=“auto generator”;

    /**

    • 创建时间
      */
      private String createTime = new Date().toString();

    /**

    • 表名
      */
      private String tableName;

    /**

    • 字段集合
      */
      private List columns;

}

字段模型

package com.kichun.common.vo;

import lombok.Data;

import java.io.Serializable;

/**

  • 代码生成列实体

  • Created by wangqichang on 2018/5/30.
    /
    @Data
    public class Coloum implements Serializable{
    /
    *

    • 属性注解
      */
      private String annotation;

    /**

    • 属性名
      */
      private String name;

    /**

    • 属性类型
      */
      private String type;

    /**

    • 属性注释
      */
      private String comment;
      }

生成的实体java文件

import com.baomidou.mybatisplus.annotations.TableId;
import com.baomidou.mybatisplus.annotations.TableName;
import com.baomidou.mybatisplus.enums.IdType;
import lombok.Data;

import java.io.Serializable;
import java.util.Date;

/**

  • User 实体类

  • Created by auto generator on Fri Jun 01 15:09:37 CST 2018.
    */
    @Data
    @TableName(“t_user”)
    public class User implements Serializable{

    /**
    *
    */
    @TableId(type = IdType.AUTO)
    private Integer id;

    /**
    *
    */

    private String name;

    /**
    *
    */

    private String pwd;

    /**
    *
    */

    private String realName;

    /**
    *
    */

    private Date createTime;

    /**
    *
    */

    private String createId;
    }

其他:

引入相关依赖(freeMarker)
使用了开源工具类hutool
适用于需自定义的MBG
然而,我发现了更齐全的MBG:mybatis-plus所带的生成器,更适合使用了mybatis-plus工具的代码生成,有兴趣可以了解下http://mp.baomidou.com/作者:老王_KICHUN链接:https://www.jianshu.com/p/0a5f8dba9b1d来源:简书

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值