新接手一个项目,没有数据库文件,并且Entity实体类放在不同的文件路径中,写了个转换工具,如下:
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.annotations.TableId;
import io.swagger.annotations.ApiModelProperty;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import java.io.*;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static cn.hutool.core.io.FileUtil.newFile;
/**
* 根据实体类生成表生成语句
*/
@Slf4j
class EntityToTablesUtil {
/**
* java类型与数据库类型映射
*/
public static HashMap<String,String> javaPropertyMap = new HashMap<>(16, 1);
static {
javaPropertyMap.put("integer", " int(8) ");
javaPropertyMap.put("int", " int(8) ");
javaPropertyMap.put("short", " tinyint(4) ");
javaPropertyMap.put("byte", " tinyint(4) ");
javaPropertyMap.put("long", " bigint(11) ");
javaPropertyMap.put("bigdecimal", " decimal(20,4) ");
javaPropertyMap.put("double", " double(10,2) ");
javaPropertyMap.put("float", " float(10,2) ");
javaPropertyMap.put("boolean", " tinyint(4) ");
javaPropertyMap.put("timestamp", " datetime ");
javaPropertyMap.put("date", " datetime ");
javaPropertyMap.put("localdatetime", " datetime ");
javaPropertyMap.put("string", " varchar(255) ");
}
public static void main(String[] args) {
// 生成sql的文件夹
String filePath = "E:\\";
// 实体类所在的package在磁盘上的绝对路径
String packageName1 = "D:\\4.program\\17\\tourdataplatform\\src\\main\\java\\com\\ichinae\\base\\mgr\\data\\entity";
// 项目中实体类的路径
String prefix1 = "com.ichinae.base.mgr.data.entity.";
StringBuilder sqlStr1 = buildSql(packageName1, prefix1);
// 实体类所在的package在磁盘上的绝对路径
String packageName2 = "D:\\4.program\\17\\tourdataplatform\\src\\main\\java\\com\\ichinae\\base\\mgr\\data\\entity\\datareport";
// 项目中实体类的路径
String prefix2 = "com.ichinae.base.mgr.data.entity.datareport.";
StringBuilder sqlStr2 = buildSql(packageName2, prefix2);
// 实体类所在的package在磁盘上的绝对路径
String packageName3 = "D:\\4.program\\17\\tourdataplatform\\src\\main\\java\\com\\ichinae\\base\\mgr\\data\\entity\\ticketstatistics\\task";
// 项目中实体类的路径
String prefix3 = "com.ichinae.base.mgr.data.entity.ticketstatistics.task.";
StringBuilder sqlStr3 = buildSql(packageName3, prefix3);
assert sqlStr1 != null;
sqlStr1.append(sqlStr2).append(sqlStr3);
System.out.println(sqlStr1);
// sqlToFile(sqlStr1.toString(), filePath + "work.sql");
}
private static StringBuilder buildSql(String packageName, String prefix) {
StringBuilder sqlStr = new StringBuilder();
// 获取包下的所有类名称
String className = "";
List<String> list = getAllClasses(packageName);
if (CollUtil.isEmpty(list)) {
return null;
}
for (String str : list) {
try {
className = prefix + str.substring(0, str.lastIndexOf("."));
String sql = generateSql(className, packageName,str);
sqlStr.append("\n ").append(sql);
}catch (Exception e) {
e.printStackTrace();
log.error("错误类:{}", str);
}
}
return sqlStr;
}
/**
* 根据实体类生成建表语句
* @param className 全类名
*/
public static String generateSql(String className,String packPath,String javaName){
try {
Class<?> clz = Class.forName(className);
String className1 = dealSubLine(clz.getSimpleName());
//处理className
className = className1.substring(1);
//获取表中文名称
String tableCommit = getTableName(packPath+"\\"+javaName);
String tableCommitVarchar=" COMMENT='"+tableCommit+"';";
Field[] fields = clz.getDeclaredFields();
StringBuilder column = new StringBuilder();
String primaryKey = null;
List<String> colList = new ArrayList<>();
for (Field f : fields) {
String dealName;
if(!"serialVersionUID".equals(f.getName())){
//获取注解名称
String commitVachr = "";
ApiModelProperty apiModelProperty = f.getAnnotation(ApiModelProperty.class);
if(Objects.nonNull(apiModelProperty)){
String filedChineseName = apiModelProperty.value();
commitVachr=" COMMENT '"+filedChineseName+"',";
}else{
commitVachr=" COMMENT '',";
}
//驼峰转换
dealName = dealSubLine(f.getName());
if (colList.contains(dealName)) {
continue;
}
String filedTypeName = f.getType().getName();
String suffix = filedTypeName.substring(filedTypeName.lastIndexOf(".")+1);
if ("List".equals(suffix)) {
continue;
}
String dataType = javaPropertyMap.get(suffix.toLowerCase());
if (StringUtils.isBlank(dataType)) {
log.error("字段类型为空:{}", suffix);
continue;
}
TableId tableId = f.getAnnotation(TableId.class);
if(Objects.nonNull(tableId)){
column.append(" \n `").append(dealName).append("`").append(dataType).append("NOT NULL AUTO_INCREMENT").append(commitVachr);
primaryKey = dealName;
}else {
column.append(" \n `").append(dealName).append("`").append(dataType).append(" DEFAULT NULL ").append(commitVachr);
}
colList.add(dealName);
}
}
return "\n DROP TABLE IF EXISTS `" + className + "`; " +
" \n CREATE TABLE `" + className + "` (" + " \n " + column +
" \n PRIMARY KEY (`" + primaryKey + "`) " +
" \n ) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci " +
tableCommitVarchar;
} catch (ClassNotFoundException e) {
log.debug("该类未找到!");
return null;
}
}
/**
* 获取包下的所有类名称,获取的结果类似于 XXX.java
* @param packageName 包路径
* @return 类List
*/
public static List<String> getAllClasses(String packageName){
List<String> classList = new ArrayList<>();
File f = new File(packageName);
if (!f.exists() || !f.isDirectory()) {
throw new RuntimeException("包路径未找到!");
}
File[] files = f.listFiles();
assert files != null;
for (File file : files) {
if (file.isFile()) {
classList.add(file.getName());
}
}
log.info("包路径中类有:{}个", classList.size());
return classList;
}
/**
* 将string 写入sql文件
* @param str sql
* @param path sql打印路径
*/
public static void sqlToFile(String str, String path){
byte[] sourceByte = str.getBytes();
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) {
e.printStackTrace();
}
}
private static String dealSubLine(String str){
//String str = "areaObjectCode";
StringBuilder ss = new StringBuilder();
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length; i++) {
if (charArray[i] >= 'A' && charArray[i] <= 'Z') {
ss.append("_").append(charArray[i]);
} else {
ss.append(charArray[i]);
}
}
return ss.toString().toLowerCase();
}
/**
* 获取表中文名称
*/
@SneakyThrows
private static String getTableName(String filePath){
File f= newFile(filePath);
InputStreamReader read= new InputStreamReader( new FileInputStream(f), StandardCharsets.UTF_8);
BufferedReader reader= new BufferedReader(read);
String line;
while((line=reader.readLine())!= null){
//判断字符串包含中文切读取中文
char[] t = line.toCharArray();
for (char a : t) {
// 判断是否为汉字字符
if (Character.toString(a).matches("[\\u4E00-\\u9FA5]+")) {
// System.out.print("字符串含有汉字");
// System.out.print(line.replaceAll("[^\\u4e00-\\u9fa5]", ""));
//获取中文名称
String tableChineseName =line.replaceAll("[^\\u4e00-\\u9fa5]", "");
return tableChineseName;
}
}
}
return null;
}
}