package com.tofflon.mes.admin.utils;import com.baomidou.mybatisplus.annotation.TableField;import com.baomidou.mybatisplus.annotation.TableName;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.core.io.support.ResourcePatternResolver;import org.springframework.core.type.classreading.CachingMetadataReaderFactory;import org.springframework.core.type.classreading.MetadataReader;import org.springframework.core.type.classreading.MetadataReaderFactory;import org.springframework.stereotype.Component;import org.springframework.util.ClassUtils;import org.springframework.util.CollectionUtils;import javax.annotation.PostConstruct;import java.lang.reflect.Field;import java.util.*;import java.util.regex.Matcher;import java.util.regex.Pattern;/** * @author X-MD * @date 2021/1/20 0020 * @description: 自动更新字段 **/@Slf4j@Componentpublic class BeanUtils { private final static Pattern HUMP_PATTERN = Pattern.compile("[A-Z]"); /** * 实体类路径 */ private final String[] BASE_PACKAGE = {"com.xxxx.mes.admin.api.entity"}; private final String RESOURCE_PATTERN = "/**/*.class"; //表名前缀 @Autowired protected BaseModelMapper baseModelMapper; @PostConstruct public void init() { try { Set<Class<?>> modelSet = new HashSet<>(); for (String spath : BASE_PACKAGE) { ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(spath) + RESOURCE_PATTERN; Resource[] resources = resourcePatternResolver.getResources(pattern); //MetadataReader 的工厂类 MetadataReaderFactory readerfactory = new CachingMetadataReaderFactory(resourcePatternResolver); for (Resource resource : resources) { //用于读取类信息 MetadataReader reader = readerfactory.getMetadataReader(resource); //扫描到的class String classname = reader.getClassMetadata().getClassName(); Class<?> clazz = Class.forName(classname); //将对应的类存在list modelSet.add(clazz); } } for (Class<?> aClass : modelSet) { String tableComment = StringUtils.EMPTY; //根据ApiModel获取表注释 ApiModel apiModel = aClass.getAnnotation(ApiModel.class); if (apiModel != null) { tableComment = apiModel.value(); } //根据TableName获取表名称 TableName tableNameAnn = aClass.getAnnotation(TableName.class); String tableName; //有的实体类别没有通过TableName竹节布指定表明,就是通过类名转下划线的形式 if (tableNameAnn == null) { String simpleName = aClass.getSimpleName(); //过滤掉不是数据库映射的类 if ("BaseEntity".equals(simpleName)) { continue; } tableName = StringUtils.strip(humpToLine2(simpleName), "_"); } else { tableName = tableNameAnn.value(); } //校测表是否存在,返回表的所有字段 List<String> columnTable = baseModelMapper.columnTable(tableName); //本类的所有字段 Field[] declaredFields = aClass.getDeclaredFields(); //父类所有字段 Field[] supercFields = aClass.getSuperclass().getDeclaredFields(); //数组合并 Field[] fields = new Field[declaredFields.length + supercFields.length]; System.arraycopy(declaredFields, 0, fields, 0, declaredFields.length); System.arraycopy(supercFields, 0, fields, declaredFields.length, supercFields.length); //字段集合 List<String> fieldList = new ArrayList<>(); //字段备注信息集合 Map<String, String> fieldRemarkMap = new HashMap<>(16); //字段数据类型信息集合 Map<String, String> dataTypeMap = new HashMap<>(16); for (Field declaredField : fields) { //读取字段上ApiModelProperty注解的值 ApiModelProperty annotation = declaredField.getAnnotation(ApiModelProperty.class); if (annotation == null) { continue; } //读取字段上TableField注解的值 TableField tableField = declaredField.getAnnotation(TableField.class); //去除无用字段 boolean serial = "serialVersionUID".equalsIgnoreCase(declaredField.getName()); //如果存在且exist值为false,说明该字段不与数据映射 boolean bool = tableField != null && !tableField.exist(); if (bool || serial) { continue; } //字段名称 String fieldName = humpToLine2(declaredField.getName()); fieldList.add(fieldName); //字段备注 String value = annotation.value(); fieldRemarkMap.put(fieldName, value); //添加字段时最好在注解里备注好 String dataType = annotation.dataType(); if (StringUtils.isBlank(dataType)) { dataType = declaredField.getType().getName(); } dataTypeMap.put(fieldName, dataType); } //如果表不存在,添加表 if (CollectionUtils.isEmpty(columnTable)) { //tableName 表明 ;;tableComment 表备注信息 baseModelMapper.createTable(tableName, tableComment); } for (String fieldName : fieldList) { //与数据库字段比较是否存在,如果存才不操作,不存在就添加 boolean match = columnTable.stream().anyMatch(s -> s.equalsIgnoreCase(fieldName)); if (!match) { //字段数据类型 String dataType = dataTypeMap.get(fieldName); String fieldadd = propertyType(dataType, fieldName); //备注信息 String comment = fieldRemarkMap.get(fieldName); alterTable(tableName, fieldadd, comment); } } } } catch (Exception e) { log.error(e.getMessage()); } } /** * 更新字段 * * @param tableName 表名称 * @param fieldadd 更新字段 * @param comment 字段备注 */ public void alterTable(String tableName, String fieldadd, String comment) { try { //更新字段 baseModelMapper.alterTable(tableName, fieldadd, comment); } catch (Exception e) { log.error(e.getMessage()); } } /** * @param type 数据类型 * @param name 表名称 * @return */ private static String propertyType(String type, String name) { name = humpToLine2(name); if ("java.util.Date".equals(type)) { return name + StringUtils.SPACE + "datetime(0)"; } else if ("java.lang.String".equals(type)) { return name + StringUtils.SPACE + "varchar(255)"; } else if ("java.lang.Integer".equals(type)) { return name + StringUtils.SPACE + "int(11)"; } else if ("java.math.BigDecimal".equals(type)) { return name + StringUtils.SPACE + "decimal(10,2)"; } else if ("java.lang.Long".equals(type)) { return name + StringUtils.SPACE + "bigint(20)"; } else if ("java.lang.Boolean".equals(type)) { return name + StringUtils.SPACE + "tinyint(2)"; } else if ("java.time.LocalDateTime".equals(type)) { return name + StringUtils.SPACE + "datetime(0)"; } return name + StringUtils.SPACE + type; } /** * 31 * 驼峰转下划线 * 32 */ public static String humpToLine2(String str) { Matcher matcher = HUMP_PATTERN.matcher(str); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase()); } matcher.appendTail(sb); return sb.toString(); }}