在最初的了解中,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来源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。