package com.ai.exchange.generator;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.slf4j.Slf4j;
import java.io.File;
import java.io.FileOutputStream;
import java.lang.reflect.Field;
import java.util.*;
/** * @Title SqlGenerator *
@Description 根据JAVA实体生成SQL建表语句工具
*/
@Slf4j
public class JavaObject2SqlDDLGenerator {
/**
* 常见MYSQL字段类型 VS java对象属性类型 映射集合
*/
public static Map<String, String> javaFiled2TableColumnMappingMap = new HashMap<>();
static {
javaFiled2TableColumnMappingMap.put("integer", "int(10)");
javaFiled2TableColumnMappingMap.put("short", "tinyint");
javaFiled2TableColumnMappingMap.put("long", "bigint");
javaFiled2TableColumnMappingMap.put("bigDecimal", "decimal(19,2)");
javaFiled2TableColumnMappingMap.put("double", "double(10,2)");
javaFiled2TableColumnMappingMap.put("float", "float");
javaFiled2TableColumnMappingMap.put("boolean", "bit");
javaFiled2TableColumnMappingMap.put("timeStamp", "datetime");
javaFiled2TableColumnMappingMap.put("date", "datetime");
javaFiled2TableColumnMappingMap.put("string", "varchar(200)");
javaFiled2TableColumnMappingMap.put("localDateTime", "datetime");
}
/**
* 生成SQL
* @param className
* @param tableName
* @param primaryKey
* @param filePath
* @return
*/
public static String ddlSqlGenerate(String className,String tableName,String primaryKey,String filePath){
try {
Class<?> clz = Class.forName(className);
Field[] fields = clz.getDeclaredFields();
// 获取该类的父类下的字段
Class<?> superclass = clz.getSuperclass();
Field[] declaredFields = superclass.getDeclaredFields();
List<Field> fieldList = new ArrayList<>();
for (Field declaredField : declaredFields) {
fieldList.add(declaredField);
}
for (Field declaredField : fields) {
fieldList.add(declaredField);
}
// 查询主键字段
String sqlPrimaryKey = null;
Field keyField = null;
StringBuffer column = new StringBuffer();
for (int i = 0; i < fieldList.size(); i++) {
Field f = fieldList.get(i);
if (StringUtils.isNotBlank(primaryKey) && f.getName().equals(primaryKey)){
// 根据TableId 注释获取逐渐信息
TableId annotation = f.getAnnotation(TableId.class);
if(null != annotation){
IdType type = annotation.type();
if(IdType.AUTO == type){
sqlPrimaryKey = " \n `"+primaryKey+"` int(16) not null auto_increment primary key,";
}else{
sqlPrimaryKey = " \n `"+primaryKey+"` varchar(100),";
}
}else{
sqlPrimaryKey = " \n `"+primaryKey+"` varchar(100) ,";
}
continue;
}
// 剔除序列化自动生成的字段
if(f.getName().equalsIgnoreCase("serialVersionUID")){
continue;
}
TableId tableId = f.getAnnotation(TableId.class);
if(null != tableId){
keyField = f;
continue;
}
// 跳过不是表字段的属性@TableField(exist=false)
TableField annotation = f.getAnnotation(TableField.class);
if(null != annotation){
boolean exist = annotation.exist();
if(!exist){
continue;
}
}
// 最后一行SQL字符串特殊处理
if(i == fieldList.size() - 1){
column.append(wrapperTableColumnSql(f,false));
}else{
column.append(wrapperTableColumnSql(f,true));
}
}
// 如果没参数中指定主键,则根据注释@TableId自动捕获
if(StringUtils.isBlank(primaryKey)){
if(null != keyField){
TableId tableId = keyField.getAnnotation(TableId.class);
IdType type = tableId.type();
String columnName = StringUtils.camelToUnderline(keyField.getName()).toLowerCase();
if(IdType.AUTO == type){
sqlPrimaryKey = " \n `"+columnName+"` int(16) not null auto_increment primary key,";
}else{
sqlPrimaryKey = " \n `"+columnName+"` varchar(100),";
}
}
}
// 从注解@ApiModel获取表名称(description、value)
ApiModel annotation = clz.getAnnotation(ApiModel.class);
String tableNameCn = null;
if(null != annotation){
tableNameCn = annotation.description();
if(StringUtils.isNotBlank(tableNameCn)){
if(!tableNameCn.endsWith("表")){
tableNameCn += "表";
}
}else{
tableNameCn = annotation.value();
if(!tableNameCn.endsWith("表")){
tableNameCn += "表";
}
}
}
// 从注解@TableName获取表名称
if(StringUtils.isBlank(tableName)){
TableName tName = clz.getAnnotation(TableName.class);
String value = tName.value();
tableName = value;
}
StringBuffer sql = new StringBuffer();
sql.append("\n drop table if exists `"+tableName+"`; ")
.append(" \n create table `"+tableName+"` (")
.append(StringUtils.isNotBlank(sqlPrimaryKey) ? sqlPrimaryKey : "")
.append(" \n "+column)
.append(" ) engine = innodb character set = utf8 collate = utf8_general_ci")
.append(StringUtils.isNotBlank(tableName) ? " comment='"+tableNameCn+"'" : "")
.append(";");
String sqlText = sql.toString();
if(StringUtils.isNotBlank(filePath)){
sqlSave2File(sqlText,filePath);
}
return sqlText;
} catch (ClassNotFoundException e) {
log.debug("SQL生成异常:",e);
return null;
}
}
/**
* 构建字段部分
* @param field
* @return
*/
private static String wrapperTableColumnSql(Field field,boolean containQuota){
String tpl = containQuota ? "`%s` %s default null comment '%s', \n" : "`%s` %s default null comment '%s' \n";
String typeName = field.getType().getSimpleName().toLowerCase();
String sqlType = javaFiled2TableColumnMappingMap.get(typeName);
if (sqlType == null || sqlType.isEmpty()){
log.info(field.getName() + ":"+field.getType().getName()+" 需要单独创建表");
return "";
}
String comment = "";
// 从注解@ApiModelProperty获取字段信息
ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
if(null != annotation){
comment = annotation.value();
if("".equalsIgnoreCase(comment)){
comment = annotation.name();
}
if("".equalsIgnoreCase(comment)){
comment = annotation.notes();
}
}
// 将java对象属性值的驼峰写法转换为下划线模式
String column = StringUtils.camelToUnderline(field.getName()).toLowerCase();
String sql = String.format(tpl,column,sqlType.toLowerCase(),comment);
return sql;
}
/**
* 生成的SQL保存指定文件
* @param str
* @param path
*/
private static void sqlSave2File(String str,String path){
byte[] sourceByte = str.getBytes();
if(null != sourceByte){
try {
File file = new File(path);
if (!file.exists()) {
File dir = new File(file.getParent());
dir.mkdirs();
file.createNewFile();
}
FileOutputStream outStream = new FileOutputStream(file);
outStream.write(sourceByte);
outStream.flush();
outStream.close();
System.out.println("生成成功");
} catch (Exception e) {
log.debug("保存SQL文件异常:",e);
}
}
}
public static void main(String[] args) {
String str = ddlSqlGenerate("com.ai.exchange.entity.ExApiZabbixCloudHostMonitorItem", "ex_api_zabbix_cloud_host_monitor_item", null, null);
log.error(str);
}
}