美文网首页
自定义MBG:Mybatis-Generator使用FreeMa

自定义MBG:Mybatis-Generator使用FreeMa

作者: KICHUN | 来源:发表于2018-06-04 12:49 被阅读0次

在最初的了解中,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 ${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<Coloum> 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;
}

其他:

  1. 引入相关依赖(freeMarker)
  2. 使用了开源工具类hutool
  3. 适用于需自定义的MBG

然而,我发现了更齐全的MBG:mybatis-plus所带的生成器,更适合使用了mybatis-plus工具的代码生成,有兴趣可以了解下http://mp.baomidou.com/

欢迎转载、以及指出问题

相关文章

网友评论

      本文标题:自定义MBG:Mybatis-Generator使用FreeMa

      本文链接:https://www.haomeiwen.com/subject/nbvesftx.html