Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.gitee.sunchenbin.mybatis.actable.manager.system.SysMysqlCreateTableManagerImpl Maven / Gradle / Ivy
Go to download
A.CTable is a Maven project based on Spring and Mybatis, which enhances the function of Mybatis
package com.gitee.sunchenbin.mybatis.actable.manager.system;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.gitee.sunchenbin.mybatis.actable.annotation.*;
import com.gitee.sunchenbin.mybatis.actable.command.*;
import com.gitee.sunchenbin.mybatis.actable.utils.ColumnUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.sunchenbin.mybatis.actable.constants.Constants;
import com.gitee.sunchenbin.mybatis.actable.constants.MySqlTypeConstant;
import com.gitee.sunchenbin.mybatis.actable.dao.system.CreateMysqlTablesMapper;
import com.gitee.sunchenbin.mybatis.actable.manager.util.ConfigurationUtil;
import com.gitee.sunchenbin.mybatis.actable.utils.ClassTools;
import org.springframework.util.StringUtils;
/**
* 项目启动时自动扫描配置的目录中的model,根据配置的规则自动创建或更新表 该逻辑只适用于mysql,其他数据库尚且需要另外扩展,因为sql的语法不同
*
* @author sunchenbin, Spet
* @version 2019/07/06
*/
@Transactional
@Service("sysMysqlCreateTableManager")
public class SysMysqlCreateTableManagerImpl implements SysMysqlCreateTableManager {
private static final Logger log = LoggerFactory.getLogger(SysMysqlCreateTableManagerImpl.class);
@Autowired
private CreateMysqlTablesMapper createMysqlTablesMapper;
@Autowired
private ConfigurationUtil springContextUtil;
// 获取Mysql的类型,以及类型需要设置几个长度
private static Map mySqlTypeAndLengthMap = mySqlTypeAndLengthMap();
/**
* 要扫描的model所在的pack
*/
private static String pack = null;
/**
* 自动创建模式:update表示更新,create表示删除原表重新创建
*/
private static String tableAuto = null;
/**
* 读取配置文件的三种状态(创建表、更新表、不做任何事情)
*/
public void createMysqlTable() {
// 读取配置信息
pack = springContextUtil.getConfig(Constants.MODEL_PACK_KEY);
tableAuto = springContextUtil.getConfig(Constants.TABLE_AUTO_KEY);
// 不做任何事情
if (!"none".equals(tableAuto) && !"update".equals(tableAuto) && !"create".equals(tableAuto) && !"add".equals(tableAuto)) {
log.warn("配置mybatis.table.auto错误无法识别,当前配置只支持[none/update/create/add]三种类型!");
return;
}
// 不做任何事情
if ("none".equals(tableAuto)) {
log.info("配置mybatis.table.auto=none,不需要做任何事情");
return;
}
// 从包package中获取所有的Class
Set> classes = ClassTools.getClasses(pack);
// 初始化用于存储各种操作表结构的容器
Map> baseTableMap = initTableMap();
// 循环全部的model
for (Class> clas : classes) {
// 没有打注解不需要创建表
if (!ColumnUtils.hasTableAnnotation(clas)) {
log.warn("{},没有@Table注解直接跳过", clas.getName());
continue;
}
// 构建出全部表的增删改的map
buildTableMapConstruct(clas, baseTableMap);
}
// 根据传入的map,分别去创建或修改表结构
createOrModifyTableConstruct(baseTableMap);
}
/**
* 初始化用于存储各种操作表结构的容器
*
* @return 初始化map
*/
private Map> initTableMap() {
Map> baseTableMap = new HashMap>();
// 1.用于存需要创建的表名+(字段结构/表信息)
baseTableMap.put(Constants.NEW_TABLE_MAP, new HashMap());
// 2.用于存需要更新字段类型等的表名+结构
baseTableMap.put(Constants.MODIFY_TABLE_MAP, new HashMap());
// 3.用于存需要增加字段的表名+结构
baseTableMap.put(Constants.ADD_TABLE_MAP, new HashMap());
// 4.用于存需要删除字段的表名+结构
baseTableMap.put(Constants.REMOVE_TABLE_MAP, new HashMap());
// 5.用于存需要删除主键的表名+结构
baseTableMap.put(Constants.DROPKEY_TABLE_MAP, new HashMap());
// 6.用于存需要删除唯一约束的表名+结构
baseTableMap.put(Constants.DROPINDEXANDUNIQUE_TABLE_MAP, new HashMap());
// 7.用于存需要增加的索引
baseTableMap.put(Constants.ADDINDEX_TABLE_MAP, new HashMap());
// 8.用于存需要增加的唯一约束
baseTableMap.put(Constants.ADDUNIQUE_TABLE_MAP, new HashMap());
// 9.更新表注释
baseTableMap.put(Constants.MODIFY_TABLE_COMMENT_MAP, new HashMap());
return baseTableMap;
}
/**
* 构建出全部表的增删改的map
*
* @param clas
* package中的model的Class
* @param baseTableMap
* 用于存储各种操作表结构的容器
*/
private void buildTableMapConstruct(Class> clas, Map> baseTableMap) {
// 获取model的tablename
String tableName = ColumnUtils.getTableName(clas);
// 获取表注释
String tableComment = ColumnUtils.getTableComment(clas);
// 1. 用于存表的全部字段
List allFieldList = getAllFields(clas);
if (allFieldList.size() == 0) {
log.warn("扫描发现" + clas.getName() + "没有建表字段请检查!");
return;
}
// 如果配置文件配置的是create,表示将所有的表删掉重新创建
if ("create".equals(tableAuto)) {
log.info("由于配置的模式是create,因此先删除表后续根据结构重建");
createMysqlTablesMapper.dropTableByName(tableName);
}
// 先查该表是否以存在
SysMysqlTable table = createMysqlTablesMapper.findTableByTableName(tableName);
// 不存在时
if (table == null) {
Map map = null;
if (!StringUtils.isEmpty(tableComment)){
map = new HashMap();
map.put(SysMysqlTable.TABLE_COMMENT_KEY, tableComment);
}
baseTableMap.get(Constants.NEW_TABLE_MAP).put(tableName, new TableConfig(allFieldList, map));
baseTableMap.get(Constants.ADDINDEX_TABLE_MAP).put(tableName, new TableConfig(getAddIndexList(null, allFieldList)));
baseTableMap.get(Constants.ADDUNIQUE_TABLE_MAP).put(tableName, new TableConfig(getAddUniqueList(null, allFieldList)));
return;
}else{
// 判断表注释是否要更新
if (!tableComment.equals(table.getTable_comment())){
List list = new ArrayList();
list.add(tableComment);
baseTableMap.get(Constants.MODIFY_TABLE_COMMENT_MAP).put(tableName, new TableConfig(list));
}
}
// 已存在时理论上做修改的操作,这里查出该表的结构
List tableColumnList = createMysqlTablesMapper.findTableEnsembleByTableName(tableName);
// 从sysColumns中取出我们需要比较的列的List
// 先取出name用来筛选出增加和删除的字段
List columnNames = ClassTools.getPropertyValueList(tableColumnList, SysMysqlColumns.COLUMN_NAME_KEY);
// 验证对比从model中解析的allFieldList与从数据库查出来的columnList
// 2. 找出增加的字段
List addFieldList = getAddFieldList(allFieldList, columnNames);
// 3. 找出删除的字段
List removeFieldList = getRemoveFieldList(columnNames, allFieldList);
// 4. 找出更新的字段
List modifyFieldList = getModifyFieldList(tableColumnList, allFieldList);
// 5. 找出需要删除主键的字段
List dropKeyFieldList = getDropKeyFieldList(tableColumnList, allFieldList);
// 查询当前表中全部acteble创建的索引和唯一约束,也就是名字前缀是actable_和actable_的
Set allIndexAndUniqueNames = createMysqlTablesMapper.findTableIndexByTableName(tableName);
// 6. 找出需要删除的索引和唯一约束
List dropIndexAndUniqueFieldList = getDropIndexAndUniqueList(allIndexAndUniqueNames, allFieldList);
// 7. 找出需要新增的索引
List addIndexFieldList = getAddIndexList(allIndexAndUniqueNames, allFieldList);
// 8. 找出需要新增的唯一约束
List addUniqueFieldList = getAddUniqueList(allIndexAndUniqueNames, allFieldList);
if (addFieldList.size() != 0) {
baseTableMap.get(Constants.ADD_TABLE_MAP).put(tableName, new TableConfig(addFieldList));
}
if (removeFieldList.size() != 0) {
baseTableMap.get(Constants.REMOVE_TABLE_MAP).put(tableName, new TableConfig(removeFieldList));
}
if (modifyFieldList.size() != 0) {
baseTableMap.get(Constants.MODIFY_TABLE_MAP).put(tableName, new TableConfig(modifyFieldList));
}
if (dropKeyFieldList.size() != 0) {
baseTableMap.get(Constants.DROPKEY_TABLE_MAP).put(tableName, new TableConfig(dropKeyFieldList));
}
if (dropIndexAndUniqueFieldList.size() != 0) {
baseTableMap.get(Constants.DROPINDEXANDUNIQUE_TABLE_MAP).put(tableName, new TableConfig(dropIndexAndUniqueFieldList));
}
if (addIndexFieldList.size() != 0) {
baseTableMap.get(Constants.ADDINDEX_TABLE_MAP).put(tableName, new TableConfig(addIndexFieldList));
}
if (addUniqueFieldList.size() != 0) {
baseTableMap.get(Constants.ADDUNIQUE_TABLE_MAP).put(tableName, new TableConfig(addUniqueFieldList));
}
}
/**
* 找出需要新建的索引
*
* @param allIndexAndUniqueNames
* 当前数据库的索引很约束名
* @param allFieldList
* model中的所有字段
* @return 需要新建的索引
*/
private List getAddIndexList(Set allIndexAndUniqueNames, List allFieldList) {
List addIndexFieldList = new ArrayList();
if (null == allIndexAndUniqueNames) {
allIndexAndUniqueNames = new HashSet();
}
for (Object obj : allFieldList) {
CreateTableParam createTableParam = (CreateTableParam) obj;
if (null != createTableParam.getFiledIndexName()
&& !allIndexAndUniqueNames.contains(createTableParam.getFiledIndexName())) {
addIndexFieldList.add(createTableParam);
}
}
return addIndexFieldList;
}
/**
* 找出需要新建的唯一约束
*
* @param allIndexAndUniqueNames
* 当前数据库的索引很约束名
* @param allFieldList
* model中的所有字段
* @return 需要新建的唯一约束
*/
private List getAddUniqueList(Set allIndexAndUniqueNames, List allFieldList) {
List addUniqueFieldList = new ArrayList();
if (null == allIndexAndUniqueNames) {
allIndexAndUniqueNames = new HashSet();
}
for (Object obj : allFieldList) {
CreateTableParam createTableParam = (CreateTableParam) obj;
if (null != createTableParam.getFiledUniqueName()
&& !allIndexAndUniqueNames.contains(createTableParam.getFiledUniqueName())) {
addUniqueFieldList.add(createTableParam);
}
}
return addUniqueFieldList;
}
/**
* 找出需要删除的索引和唯一约束
*
* @param allIndexAndUniqueNames
* 当前数据库的索引很约束名
* @param allFieldList
* model中的所有字段
* @return 需要删除的索引和唯一约束
*/
private List getDropIndexAndUniqueList(Set allIndexAndUniqueNames, List allFieldList) {
List dropIndexAndUniqueFieldList = new ArrayList();
if (null == allIndexAndUniqueNames || allIndexAndUniqueNames.size() == 0) {
return dropIndexAndUniqueFieldList;
}
List currentModelIndexAndUnique = new ArrayList();
for (Object obj : allFieldList) {
CreateTableParam createTableParam = (CreateTableParam) obj;
if (null != createTableParam.getFiledIndexName()) {
currentModelIndexAndUnique.add(createTableParam.getFiledIndexName());
}
if (null != createTableParam.getFiledUniqueName()) {
currentModelIndexAndUnique.add(createTableParam.getFiledUniqueName());
}
}
for (String string : allIndexAndUniqueNames) {
if (!currentModelIndexAndUnique.contains(string)) {
dropIndexAndUniqueFieldList.add(string);
}
}
return dropIndexAndUniqueFieldList;
}
/**
* 返回需要删除主键的字段
*
* @param tableColumnList
* 表结构
* @param allFieldList
* model中的所有字段
* @return 需要删除主键的字段
*/
private List getDropKeyFieldList(List tableColumnList, List allFieldList) {
Map fieldMap = getAllFieldMap(allFieldList);
List dropKeyFieldList = new ArrayList();
for (SysMysqlColumns sysColumn : tableColumnList) {
// 数据库中有该字段时
CreateTableParam createTableParam = fieldMap.get(sysColumn.getColumn_name().toLowerCase());
if (createTableParam != null) {
// 原本是主键,现在不是了,那么要去做删除主键的操作
if ("PRI".equals(sysColumn.getColumn_key()) && !createTableParam.isFieldIsKey()) {
dropKeyFieldList.add(createTableParam);
}
}
}
return dropKeyFieldList;
}
/**
* 根据数据库中表的结构和model中表的结构对比找出修改类型默认值等属性的字段
*
* 数据库中的结构
* @param tableColumnList
* 表结构
* @param allFieldList
* model中的所有字段
* @return 需要修改的字段
*/
private List getModifyFieldList(List tableColumnList, List allFieldList) {
Map fieldMap = getAllFieldMap(allFieldList);
List modifyFieldList = new ArrayList();
for (SysMysqlColumns sysColumn : tableColumnList) {
// 数据库中有该字段时,验证是否有更新
CreateTableParam createTableParam = fieldMap.get(sysColumn.getColumn_name().toLowerCase());
if (createTableParam != null) {
// 该复制操作时为了解决multiple primary key defined的同时又不会drop primary key
CreateTableParam modifyTableParam = createTableParam.clone();
// 1.验证主键
// 原本不是主键,现在变成了主键,那么要去做更新
if (!"PRI".equals(sysColumn.getColumn_key()) && createTableParam.isFieldIsKey()) {
modifyFieldList.add(modifyTableParam);
continue;
}
// 原本是主键,现在依然主键,坚决不能在alter语句后加primary key,否则会报multiple primary
// key defined
if ("PRI".equals(sysColumn.getColumn_key()) && createTableParam.isFieldIsKey()) {
modifyTableParam.setFieldIsKey(false);
}
// 2.验证类型
if (!sysColumn.getData_type().toLowerCase().equals(createTableParam.getFieldType().toLowerCase())) {
modifyFieldList.add(modifyTableParam);
continue;
}
// 3.验证长度个小数点位数
// 4.验证小数点位数
MySqlTypeAndLength mySqlTypeAndLength = mySqlTypeAndLengthMap.get(createTableParam.getFieldType().toLowerCase());
int length = mySqlTypeAndLength.getLengthCount();
String typeAndLength = createTableParam.getFieldType().toLowerCase();
if (length == 1) {
// 拼接出类型加长度,比如varchar(1)
typeAndLength = typeAndLength + "(" + createTableParam.getFieldLength() + ")";
} else if (length == 2) {
// 拼接出类型加长度,比如varchar(1)
typeAndLength = typeAndLength + "(" + createTableParam.getFieldLength() + ","
+ createTableParam.getFieldDecimalLength() + ")";
}
// 判断类型+长度是否相同
if (!sysColumn.getColumn_type().toLowerCase().equals(typeAndLength)) {
modifyFieldList.add(modifyTableParam);
continue;
}
// 5.验证自增
if ("auto_increment".equals(sysColumn.getExtra()) && !createTableParam.isFieldIsAutoIncrement()) {
modifyFieldList.add(modifyTableParam);
continue;
}
if (!"auto_increment".equals(sysColumn.getExtra()) && createTableParam.isFieldIsAutoIncrement()) {
modifyFieldList.add(modifyTableParam);
continue;
}
// 6.验证默认值
if (sysColumn.getColumn_default() == null || sysColumn.getColumn_default().equals("")) {
// 数据库默认值是null,model中注解设置的默认值不为NULL时,那么需要更新该字段
if (!"NULL".equals(createTableParam.getFieldDefaultValue())) {
modifyFieldList.add(modifyTableParam);
continue;
}
} else if (!sysColumn.getColumn_default().equals(createTableParam.getFieldDefaultValue())) {
// 两者不相等时,需要更新该字段
modifyFieldList.add(modifyTableParam);
continue;
}
// 7.验证是否可以为null(主键不参与是否为null的更新)
if (sysColumn.getIs_nullable().equals("NO") && !createTableParam.isFieldIsKey()) {
if (createTableParam.isFieldIsNull()) {
// 一个是可以一个是不可用,所以需要更新该字段
modifyFieldList.add(modifyTableParam);
continue;
}
} else if (sysColumn.getIs_nullable().equals("YES") && !createTableParam.isFieldIsKey()) {
if (!createTableParam.isFieldIsNull()) {
// 一个是可以一个是不可用,所以需要更新该字段
modifyFieldList.add(modifyTableParam);
continue;
}
}
// 8.验证注释
if (!sysColumn.getColumn_comment().equals(createTableParam.getFieldComment())) {
modifyFieldList.add(modifyTableParam);
}
}
}
return modifyFieldList;
}
/**
* 将allFieldList转换为Map结构
*
* @param allFieldList
* @return
*/
private Map getAllFieldMap(List allFieldList) {
// 将fieldList转成Map类型,字段名作为主键
Map fieldMap = new HashMap();
for (Object obj : allFieldList) {
CreateTableParam createTableParam = (CreateTableParam) obj;
fieldMap.put(createTableParam.getFieldName().toLowerCase(), createTableParam);
}
return fieldMap;
}
/**
* 根据数据库中表的结构和model中表的结构对比找出删除的字段
*
* @param columnNames
* 数据库中的结构
* @param allFieldList
* model中的所有字段
*/
private List getRemoveFieldList(List columnNames, List allFieldList) {
List toLowerCaseColumnNames = ClassTools.toLowerCase(columnNames);
Map fieldMap = getAllFieldMap(allFieldList);
// 用于存删除的字段
List removeFieldList = new ArrayList();
for (String fieldNm : toLowerCaseColumnNames) {
// 判断该字段在新的model结构中是否存在
if (fieldMap.get(fieldNm) == null) {
// 不存在,做删除处理
removeFieldList.add(fieldNm);
}
}
return removeFieldList;
}
/**
* 根据数据库中表的结构和model中表的结构对比找出新增的字段
*
* @param allFieldList
* model中的所有字段
* @param columnNames
* 数据库中的结构
* @return 新增的字段
*/
private List getAddFieldList(List allFieldList, List columnNames) {
List toLowerCaseColumnNames = ClassTools.toLowerCase(columnNames);
List addFieldList = new ArrayList();
for (Object obj : allFieldList) {
CreateTableParam createTableParam = (CreateTableParam) obj;
// 循环新的model中的字段,判断是否在数据库中已经存在
if (!toLowerCaseColumnNames.contains(createTableParam.getFieldName().toLowerCase())) {
// 不存在,表示要在数据库中增加该字段
addFieldList.add(obj);
}
}
return addFieldList;
}
/**
* 迭代出所有model的所有fields
*
* @param clas
* 准备做为创建表依据的class
* @return 表的全部字段
*/
private List getAllFields(Class> clas) {
List fieldList = new ArrayList();
Field[] fields = clas.getDeclaredFields();
// 判断是否有父类,如果有拉取父类的field,这里只支持多层继承
fields = recursionParents(clas, fields);
for (Field field : fields) {
// 判断方法中是否有指定注解类型的注解
boolean hasAnnotation = field.isAnnotationPresent(Column.class);
boolean hasAnnotationCommon = field.isAnnotationPresent(javax.persistence.Column.class);
if (hasAnnotation) {
// 根据注解类型返回方法的指定类型注解
Column column = field.getAnnotation(Column.class);
CreateTableParam param = new CreateTableParam();
param.setFieldName(ColumnUtils.getColumnName(field));
String type = ColumnUtils.getType(field);
// 类型不为空时,因为类型现在可以为空
if (type != null){
param.setFieldType(type.toLowerCase());
// TODO: bit 特殊处理,后期优化
if("bit".equals(type)){
if(column.length() >= 255){
param.setFieldLength(1);
}
if(column.length() <= 64){
param.setFieldLength(column.length());
}
}else{
param.setFieldLength(column.length());
}
param.setFieldDecimalLength(column.decimalLength());
MySqlTypeAndLength mySqlTypeAndLength = mySqlTypeAndLengthMap.get(type.toLowerCase());
int length = mySqlTypeAndLength.getLengthCount() ;
param.setFileTypeLength(length);
}else{
// 类型为空根据字段类型去默认匹配类型
String mysqlType = JavaToMysqlType.javaToMysqlTypeMap.get(field.getGenericType().toString());
if (StringUtils.isEmpty(mysqlType)){
log.error("不支持{}类型转换到mysql类型",field.getGenericType().toString());
continue;
}
param.setFieldType(mysqlType);
MySqlTypeAndLength mySqlTypeAndLength = mySqlTypeAndLengthMap.get(mysqlType.toLowerCase());
if (null == mySqlTypeAndLength){
log.error("{}类型,没有配置对应的MySqlTypeConstant",mysqlType);
continue;
}
int length = mySqlTypeAndLength.getLengthCount();
param.setFileTypeLength(length);
if (length == 1){
param.setFieldLength(mySqlTypeAndLength.getLength());
}else if (length == 2){
param.setFieldLength(mySqlTypeAndLength.getLength());
param.setFieldDecimalLength(mySqlTypeAndLength.getDecimalLength());
}
}
// 主键时设置必须不为null
if (ColumnUtils.isKey(field)) {
param.setFieldIsNull(false);
} else {
param.setFieldIsNull(ColumnUtils.isNull(field));
}
param.setFieldIsKey(ColumnUtils.isKey(field));
param.setFieldIsAutoIncrement(ColumnUtils.isAutoIncrement(field));
param.setFieldDefaultValue(ColumnUtils.getDefaultValue(field));
param.setFieldComment(ColumnUtils.getComment(field));
// 获取当前字段的@Index注解
Index index = field.getAnnotation(Index.class);
if (null != index) {
String[] indexValue = index.columns();
param.setFiledIndexName((index.value() == null || index.value().equals(""))
? (Constants.IDX + ((indexValue.length == 0) ? ColumnUtils.getColumnName(field) : stringArrFormat(indexValue)))
: Constants.IDX + index.value());
param.setFiledIndexValue(
indexValue.length == 0 ? Arrays.asList(ColumnUtils.getColumnName(field)) : Arrays.asList(indexValue));
}
// 获取当前字段的@Unique注解
Unique unique = field.getAnnotation(Unique.class);
if (null != unique) {
String[] uniqueValue = unique.columns();
param.setFiledUniqueName((unique.value() == null || unique.value().equals(""))
? (Constants.UNI
+ ((uniqueValue.length == 0) ? ColumnUtils.getColumnName(field) : stringArrFormat(uniqueValue)))
: Constants.UNI + unique.value());
param.setFiledUniqueValue(
uniqueValue.length == 0 ? Arrays.asList(ColumnUtils.getColumnName(field)) : Arrays.asList(uniqueValue));
}
fieldList.add(param);
}else if (hasAnnotationCommon) {
// 根据注解类型返回方法的指定类型注解
javax.persistence.Column column = field.getAnnotation(javax.persistence.Column.class);
CreateTableParam param = new CreateTableParam();
param.setFieldName(ColumnUtils.getColumnName(field));
// 数据类型
String type = ColumnUtils.getType(field);
// 类型不为空时,因为类型现在可以为空
if (type != null){
param.setFieldType(type.toLowerCase());
// TODO: bit 特殊处理,后期优化
if("bit".equals(type)){
if(column.length() >= 255){
param.setFieldLength(1);
}
if(column.length() <= 64){
param.setFieldLength(column.length());
}
}else{
param.setFieldLength(column.length());
}
param.setFieldDecimalLength(column.scale());
MySqlTypeAndLength mySqlTypeAndLength = mySqlTypeAndLengthMap.get(type.toLowerCase());
int length = mySqlTypeAndLength.getLengthCount() ;
param.setFileTypeLength(length);
}else{
// 类型为空根据字段类型去默认匹配类型
String mysqlType = JavaToMysqlType.javaToMysqlTypeMap.get(field.getGenericType().toString());
if (StringUtils.isEmpty(mysqlType)){
log.error("不支持{}类型转换到mysql类型",field.getGenericType().toString());
continue;
}
param.setFieldType(mysqlType);
MySqlTypeAndLength mySqlTypeAndLength = mySqlTypeAndLengthMap.get(mysqlType.toLowerCase());
if (null == mySqlTypeAndLength){
log.error("{}类型,没有配置对应的MySqlTypeConstant",mysqlType);
continue;
}
int length = mySqlTypeAndLength.getLengthCount();
param.setFileTypeLength(length);
if (length == 1){
param.setFieldLength(mySqlTypeAndLength.getLength());
}else if (length == 2){
param.setFieldLength(mySqlTypeAndLength.getLength());
param.setFieldDecimalLength(mySqlTypeAndLength.getDecimalLength());
}
}
// 主键时设置必须不为null
if (ColumnUtils.isKey(field)) {
param.setFieldIsNull(false);
} else {
param.setFieldIsNull(ColumnUtils.isNull(field));
}
param.setFieldIsKey(ColumnUtils.isKey(field));
param.setFieldIsAutoIncrement(ColumnUtils.isAutoIncrement(field));
param.setFieldDefaultValue(ColumnUtils.getDefaultValue(field));
param.setFieldComment(ColumnUtils.getComment(field));
// 获取当前字段的@Index注解
Index index = field.getAnnotation(Index.class);
if (null != index) {
String[] indexValue = index.columns();
param.setFiledIndexName((index.value() == null || index.value().equals(""))
? (Constants.IDX + ((indexValue.length == 0) ? ColumnUtils.getColumnName(field) : stringArrFormat(indexValue)))
: Constants.IDX + index.value());
param.setFiledIndexValue(
indexValue.length == 0 ? Arrays.asList(ColumnUtils.getColumnName(field)) : Arrays.asList(indexValue));
}
// 获取当前字段的@Unique注解
Unique unique = field.getAnnotation(Unique.class);
if (null != unique) {
String[] uniqueValue = unique.columns();
param.setFiledUniqueName((unique.value() == null || unique.value().equals(""))
? (Constants.UNI
+ ((uniqueValue.length == 0) ? ColumnUtils.getColumnName(field) : stringArrFormat(uniqueValue)))
: Constants.UNI + unique.value());
param.setFiledUniqueValue(
uniqueValue.length == 0 ? Arrays.asList(ColumnUtils.getColumnName(field)) : Arrays.asList(uniqueValue));
}
fieldList.add(param);
}
}
return fieldList;
}
/**
* String[] to format xxx_yyy_sss
* @param arr
* @return
*/
private String stringArrFormat(String[] arr) {
return String.valueOf(Arrays.toString(arr)).replaceAll(",", "_").replaceAll(" ", "").replace("[", "")
.replace("]", "");
}
/**
* 递归扫描父类的fields
*
* @param clas
* 类
* @param fields
* 属性
*/
@SuppressWarnings("rawtypes")
private Field[] recursionParents(Class> clas, Field[] fields) {
if (clas.getSuperclass() != null) {
Class clsSup = clas.getSuperclass();
List fieldList = new ArrayList();
fieldList.addAll(Arrays.asList(fields));
fieldList.addAll(Arrays.asList(clsSup.getDeclaredFields()));
fields = new Field[fieldList.size()];
int i = 0;
for (Object field : fieldList.toArray()) {
fields[i] = (Field) field;
i++;
}
fields = recursionParents(clsSup, fields);
}
return fields;
}
/**
* 根据传入的map创建或修改表结构
*
* @param baseTableMap
* 操作sql的数据结构
*/
private void createOrModifyTableConstruct(Map> baseTableMap) {
// 1. 创建表
createTableByMap(baseTableMap.get(Constants.NEW_TABLE_MAP));
// add是追加模式不做删除和修改操作
if(!"add".equals(tableAuto)){
// 2. 删除要变更主键的表的原来的字段的主键
dropFieldsKeyByMap(baseTableMap.get(Constants.DROPKEY_TABLE_MAP));
}
// 3. 添加新的字段
addFieldsByMap(baseTableMap.get(Constants.ADD_TABLE_MAP));
// add是追加模式不做删除和修改操作
if(!"add".equals(tableAuto)) {
// 4. 删除索引和约束
dropIndexAndUniqueByMap(baseTableMap.get(Constants.DROPINDEXANDUNIQUE_TABLE_MAP));
// 5. 删除字段
removeFieldsByMap(baseTableMap.get(Constants.REMOVE_TABLE_MAP));
// 6. 修改表注释
modifyTableCommentByMap(baseTableMap.get(Constants.MODIFY_TABLE_COMMENT_MAP));
// 7. 修改字段类型等
modifyFieldsByMap(baseTableMap.get(Constants.MODIFY_TABLE_MAP));
}
// 8. 创建索引
addIndexByMap(baseTableMap.get(Constants.ADDINDEX_TABLE_MAP));
// 9. 创建约束
addUniqueByMap(baseTableMap.get(Constants.ADDUNIQUE_TABLE_MAP));
}
/**
* 根据map结构删除索引和唯一约束
*
* @param dropIndexAndUniqueMap
* 用于删除索引和唯一约束
*/
private void dropIndexAndUniqueByMap(Map dropIndexAndUniqueMap) {
if (dropIndexAndUniqueMap.size() > 0) {
for (Entry entry : dropIndexAndUniqueMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
log.info("开始删除表" + entry.getKey() + "中的索引" + obj);
createMysqlTablesMapper.dropTabelIndex(map);
log.info("完成删除表" + entry.getKey() + "中的索引" + obj);
}
}
}
}
/**
* 根据map结构创建索引
*
* @param addIndexMap
* 用于创建索引和唯一约束
*/
private void addIndexByMap(Map addIndexMap) {
if (addIndexMap.size() > 0) {
for (Entry entry : addIndexMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
CreateTableParam fieldProperties = (CreateTableParam) obj;
if (null != fieldProperties.getFiledIndexName()) {
log.info("开始创建表" + entry.getKey() + "中的索引" + fieldProperties.getFiledIndexName());
createMysqlTablesMapper.addTableIndex(map);
log.info("完成创建表" + entry.getKey() + "中的索引" + fieldProperties.getFiledIndexName());
}
}
}
}
}
/**
* 根据map结构创建唯一约束
*
* @param addUniqueMap
* 用于创建索引和唯一约束
*/
private void addUniqueByMap(Map addUniqueMap) {
if (addUniqueMap.size() > 0) {
for (Entry entry : addUniqueMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
CreateTableParam fieldProperties = (CreateTableParam) obj;
if (null != fieldProperties.getFiledUniqueName()) {
log.info("开始创建表" + entry.getKey() + "中的唯一约束" + fieldProperties.getFiledUniqueName());
createMysqlTablesMapper.addTableUnique(map);
log.info("完成创建表" + entry.getKey() + "中的唯一约束" + fieldProperties.getFiledUniqueName());
}
}
}
}
}
/**
* 根据map结构修改表中的字段类型等
*
* @param modifyTableMap
* 用于存需要更新字段类型等的表名+结构
*/
private void modifyFieldsByMap(Map modifyTableMap) {
// 做修改字段操作
if (modifyTableMap.size() > 0) {
for (Entry entry : modifyTableMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
CreateTableParam fieldProperties = (CreateTableParam) obj;
log.info("开始修改表" + entry.getKey() + "中的字段" + fieldProperties.getFieldName());
createMysqlTablesMapper.modifyTableField(map);
log.info("完成修改表" + entry.getKey() + "中的字段" + fieldProperties.getFieldName());
}
}
}
}
/**
* 根据map结构删除表中的字段
*
* @param removeTableMap
* 用于存需要删除字段的表名+结构
*/
private void removeFieldsByMap(Map removeTableMap) {
// 做删除字段操作
if (removeTableMap.size() > 0) {
for (Entry entry : removeTableMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
String fieldName = (String) obj;
log.info("开始删除表" + entry.getKey() + "中的字段" + fieldName);
createMysqlTablesMapper.removeTableField(map);
log.info("完成删除表" + entry.getKey() + "中的字段" + fieldName);
}
}
}
}
/**
* 根据map结构更新表的注释
*
* @param modifyTableCommentMap
* 用于存需要更新表名+注释
*/
private void modifyTableCommentByMap(Map modifyTableCommentMap) {
// 做更新的表注释
if (modifyTableCommentMap.size() > 0) {
for (Entry entry : modifyTableCommentMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
String fieldName = (String) obj;
log.info("开始更新表" + entry.getKey() + "的注释" + fieldName);
createMysqlTablesMapper.modifyTableComment(map);
log.info("完成更新表" + entry.getKey() + "的注释" + fieldName);
}
}
}
}
/**
* 根据map结构对表中添加新的字段
*
* @param addTableMap
* 用于存需要增加字段的表名+结构
*/
private void addFieldsByMap(Map addTableMap) {
// 做增加字段操作
if (addTableMap.size() > 0) {
for (Entry entry : addTableMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
CreateTableParam fieldProperties = (CreateTableParam) obj;
log.info("开始为表" + entry.getKey() + "增加字段" + fieldProperties.getFieldName());
createMysqlTablesMapper.addTableField(map);
log.info("完成为表" + entry.getKey() + "增加字段" + fieldProperties.getFieldName());
}
}
}
}
/**
* 根据map结构删除要变更表中字段的主键
*
* @param dropKeyTableMap
* 用于存需要删除主键的表名+结构
*/
private void dropFieldsKeyByMap(Map dropKeyTableMap) {
// 先去做删除主键的操作,这步操作必须在增加和修改字段之前!
if (dropKeyTableMap.size() > 0) {
for (Entry entry : dropKeyTableMap.entrySet()) {
for (Object obj : entry.getValue().getList()) {
Map map = new HashMap();
map.put(entry.getKey(), obj);
CreateTableParam fieldProperties = (CreateTableParam) obj;
log.info("开始为表" + entry.getKey() + "删除主键" + fieldProperties.getFieldName());
createMysqlTablesMapper.dropKeyTableField(map);
log.info("完成为表" + entry.getKey() + "删除主键" + fieldProperties.getFieldName());
}
}
}
}
/**
* 根据map结构创建表
*
* @param newTableMap
* 用于存需要创建的表名+结构
*/
private void createTableByMap(Map newTableMap) {
// 做创建表操作
if (newTableMap.size() > 0) {
for (Entry entry : newTableMap.entrySet()) {
Map map = new HashMap();
map.put(entry.getKey(), entry.getValue());
log.info("开始创建表:" + entry.getKey());
createMysqlTablesMapper.createTable(map);
log.info("完成创建表:" + entry.getKey());
}
}
}
/**
* 获取Mysql的类型,以及类型需要设置几个长度,这里构建成map的样式
* 构建Map(字段名(小写),需要设置几个长度(0表示不需要设置,1表示需要设置一个,2表示需要设置两个))
*/
public static Map mySqlTypeAndLengthMap() {
Field[] fields = MySqlTypeConstant.class.getDeclaredFields();
Map map = new HashMap();
for (Field field : fields) {
LengthCount lengthCount = field.getAnnotation(LengthCount.class);
LengthDefault lengthDefault = field.getAnnotation(LengthDefault.class);
map.put(field.getName().toLowerCase(), new MySqlTypeAndLength(lengthCount, lengthDefault));
}
return map;
}
}