在最初的了解中,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>
}
- ${(column.comment)!}
数据模型参考
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;
- base package
}
字段模型
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来源:简书著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。