根据java已经定义好的Class生成DDL SQL

  1 package com.yjcmp.exchange.generator;
  2 
  3 import cn.hutool.core.collection.CollectionUtil;
  4 import cn.hutool.core.lang.ClassScanner;
  5 import com.baomidou.mybatisplus.annotation.IdType;
  6 import com.baomidou.mybatisplus.annotation.TableField;
  7 import com.baomidou.mybatisplus.annotation.TableId;
  8 import com.baomidou.mybatisplus.annotation.TableName;
  9 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 10 import io.swagger.annotations.ApiModel;
 11 import io.swagger.annotations.ApiModelProperty;
 12 import lombok.extern.slf4j.Slf4j;
 13 import java.io.File;
 14 import java.io.FileOutputStream;
 15 import java.io.IOException;
 16 import java.lang.reflect.Field;
 17 import java.net.JarURLConnection;
 18 import java.net.URL;
 19 import java.util.*;
 20 import java.util.jar.JarEntry;
 21 import java.util.jar.JarFile;
 22 
 23 /** * @Title SqlGenerator * @Description 根据JAVA实体生成SQL建表语句工具 * @Copyright: 版权所有 (c) 2018 - 2019 * @Company: wt * @Author root * @Version 1.0.0 * @Create 19-4-1 下午4:22 */
 24 @Slf4j
 25 public class JavaObject2SqlDDLGenerator {
 26 
 27     /**
 28      * 常见MYSQL字段类型 VS java对象属性类型 映射集合
 29      */
 30     public static Map<String, String> javaFiled2TableColumnMappingMap = new HashMap<>();
 31     static {
 32         javaFiled2TableColumnMappingMap.put("integer", "int(10)");
 33         javaFiled2TableColumnMappingMap.put("short", "tinyint");
 34         javaFiled2TableColumnMappingMap.put("long", "bigint");
 35         javaFiled2TableColumnMappingMap.put("bigdecimal", "decimal(19,2)");
 36         javaFiled2TableColumnMappingMap.put("double", "double(10,2)");
 37         javaFiled2TableColumnMappingMap.put("float", "float");
 38         javaFiled2TableColumnMappingMap.put("boolean", "bit");
 39         javaFiled2TableColumnMappingMap.put("timestamp", "datetime");
 40         javaFiled2TableColumnMappingMap.put("date", "datetime");
 41         javaFiled2TableColumnMappingMap.put("string", "varchar(200)");
 42         javaFiled2TableColumnMappingMap.put("localdatetime", "datetime");
 43     }
 44 
 45     /**
 46      * 批量生成
 47      * @param classNamePath
 48      * @param filePath
 49      * @throws IOException
 50      */
 51     public static void batchDdlSqlGenerate2File(String classNamePath, String filePath) throws IOException {
 52         List<String> classFromPackage = getClassFromPackage(classNamePath);
 53         System.out.println(classFromPackage);
 54         StringBuilder sub = new StringBuilder();
 55         if(CollectionUtil.isNotEmpty(classFromPackage)){
 56             for (String s : classFromPackage) {
 57                 String s1 = ddlSqlGenerate(s, null, null, null);
 58                 sub.append(s1).append("\n");
 59             }
 60         }
 61         if(StringUtils.isNotBlank(filePath)){
 62             sqlSave2File(sub.toString(),filePath);
 63         }
 64 
 65     }
 66 
 67     /**
 68      * 获取指定包下面的java
 69      * @param packageName
 70      * @return
 71      */
 72     public static List<String> getClassFromPackage(String packageName) {
 73         List<String> classNames = new ArrayList<>();
 74         ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
 75         String path = packageName.replace(".", "/");
 76         try {
 77             Enumeration<URL> resources = classLoader.getResources(path);
 78             while (resources.hasMoreElements()) {
 79                 URL resource = resources.nextElement();
 80                 if (resource.getProtocol().equals("file")) {
 81                     File file = new File(resource.getFile());
 82                     File[] files = file.listFiles();
 83                     if (files != null) {
 84                         for (File f : files) {
 85                             String className = f.getName().replace(".class", "");
 86                             classNames.add(packageName + "." + className);
 87                         }
 88                     }
 89                 } else if (resource.getProtocol().equals("jar")) {
 90                     JarURLConnection jarURLConnection = (JarURLConnection) resource.openConnection();
 91                     JarFile jarFile = jarURLConnection.getJarFile();
 92                     Enumeration<JarEntry> entries = jarFile.entries();
 93                     while (entries.hasMoreElements()) {
 94                         JarEntry jarEntry = entries.nextElement();
 95                         String className = jarEntry.getName().replace("/", ".");
 96                         if (className.startsWith(packageName) && className.endsWith(".class")) {
 97                             classNames.add(className.substring(0, className.length() - 6));
 98                         }
 99                     }
100                 }
101             }
102         } catch (IOException e) {
103             e.printStackTrace();
104         }
105         return classNames;
106     }
107 
108     /**
109      * 生成SQL
110      * @param className
111      * @param tableName
112      * @param primaryKey
113      * @param filePath
114      * @return
115      */
116     public static String ddlSqlGenerate(String className,String tableName,String primaryKey,String filePath){
117         try {
118             Class<?> clz = Class.forName(className);
119             String clzName = clz.getName();
120             Field[] fields = clz.getDeclaredFields();
121             // 获取该类的父类下的字段
122             Class<?> superclass = clz.getSuperclass();
123             Field[] declaredFields = superclass.getDeclaredFields();
124             List<Field> fieldList = new ArrayList<>();
125             for (Field declaredField : declaredFields) {
126                 fieldList.add(declaredField);
127             }
128             for (Field declaredField : fields) {
129                 fieldList.add(declaredField);
130             }
131 
132             // 查询主键字段
133             String sqlPrimaryKey = null;
134             Field keyField = null;
135             StringBuffer column = new StringBuffer();
136             for (int i = 0; i < fieldList.size(); i++) {
137                 Field f = fieldList.get(i);
138                 if (StringUtils.isNotBlank(primaryKey) && f.getName().equals(primaryKey)){
139                     // 根据TableId 注释获取逐渐信息
140                     TableId annotation = f.getAnnotation(TableId.class);
141                     if(null != annotation){
142                         IdType type = annotation.type();
143                         if(IdType.AUTO == type){
144                             sqlPrimaryKey = " \n `"+primaryKey+"` int(16) not null auto_increment primary key,";
145                         }else{
146                             sqlPrimaryKey = " \n `"+primaryKey+"` varchar(100),";
147                         }
148                     }else{
149                         sqlPrimaryKey = " \n `"+primaryKey+"` varchar(100),";
150                     }
151                     continue;
152                 }
153 
154                 // 剔除序列化自动生成的字段
155                 if(f.getName().equalsIgnoreCase("serialVersionUID")){
156                     continue;
157                 }
158                 TableId tableId = f.getAnnotation(TableId.class);
159                 if(null != tableId){
160                     keyField = f;
161                     continue;
162                 }
163                 // 跳过不是表字段的属性@TableField(exist=false)
164                 TableField annotation = f.getAnnotation(TableField.class);
165                 if(null != annotation){
166                     boolean exist = annotation.exist();
167                     if(!exist){
168                         continue;
169                     }
170                 }
171                 column.append(wrapperTableColumnSql(f));
172             }
173             // 如果没参数中指定主键,则根据注释@TableId自动捕获
174             if(StringUtils.isBlank(primaryKey)){
175                 if(null != keyField){
176                     TableId tableId = keyField.getAnnotation(TableId.class);
177                     IdType type = tableId.type();
178                     String columnName = StringUtils.camelToUnderline(keyField.getName()).toLowerCase();
179                     if(IdType.AUTO == type){
180                         sqlPrimaryKey = " \n `"+columnName+"` int(16) not null auto_increment primary key,";
181                     }else{
182                         sqlPrimaryKey = " \n `"+columnName+"` varchar(100),";
183                     }
184                 }
185             }
186 
187             // 从注解@ApiModel获取表名称(description、value)
188             ApiModel annotation = clz.getAnnotation(ApiModel.class);
189             String tableNameCn = null;
190             if(null != annotation){
191                 tableNameCn = annotation.description();
192                 if(StringUtils.isNotBlank(tableNameCn)){
193                     if(!tableNameCn.endsWith("表")){
194                         tableNameCn += "表";
195                     }
196                 }else{
197                     tableNameCn = annotation.value();
198                     if(!tableNameCn.endsWith("表")){
199                         tableNameCn += "表";
200                     }
201                 }
202             }
203 
204             // 从注解@TableName获取表名称
205             if(StringUtils.isBlank(tableName)){
206                 TableName tName = clz.getAnnotation(TableName.class);
207                 if(null == tName){
208                     tableName =  StringUtils.camelToUnderline(clzName).toLowerCase();
209                 }else{
210                     String value = tName.value();
211                     tableName = value;
212                 }
213             }
214 
215             StringBuffer sql = new StringBuffer();
216             String toString = column.toString();
217             String columnStr =  toString.substring(0, column.lastIndexOf(","));
218             sql.append("\ndrop table if exists `"+tableName+"`; ")
219                     .append("\ncreate table `"+tableName+"` (")
220                     .append(StringUtils.isNotBlank(sqlPrimaryKey) ? sqlPrimaryKey : "")
221                     .append(" \n "+columnStr)
222                     .append(" \n ) engine = innodb  character set = utf8 collate = utf8_general_ci")
223                     .append(StringUtils.isNotBlank(tableName) ? " comment='"+tableNameCn+"'" : "")
224                     .append(";");
225             String sqlText = sql.toString();
226             if(StringUtils.isNotBlank(filePath)){
227                 sqlSave2File(sqlText,filePath);
228             }
229             return sqlText;
230         } catch (ClassNotFoundException e) {
231             log.debug("SQL生成异常:",e);
232             return null;
233         }
234     }
235 
236     /**
237      * 构建字段部分
238      * @param field
239      * @return
240      */
241     private static String wrapperTableColumnSql(Field field){
242         String tpl = "`%s` %s default null comment '%s', \n";
243         String typeName = field.getType().getSimpleName().toLowerCase();
244         String sqlType = javaFiled2TableColumnMappingMap.get(typeName);
245         if (sqlType == null || sqlType.isEmpty()){
246             log.info(field.getName() + ":"+field.getType().getName()+" 需要单独创建表");
247             return "";
248         }
249         String comment = "";
250         // 从注解@ApiModelProperty获取字段信息
251         ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
252         if(null != annotation){
253             comment = annotation.value();
254             if("".equalsIgnoreCase(comment)){
255                 comment = annotation.name();
256             }
257             if("".equalsIgnoreCase(comment)){
258                 comment = annotation.notes();
259             }
260         }
261         // 将java对象属性值的驼峰写法转换为下划线模式
262         String column = StringUtils.camelToUnderline(field.getName()).toLowerCase();
263         String sql = String.format(tpl,column,sqlType.toLowerCase(),comment);
264         return sql;
265     }
266 
267     /**
268      * 生成的SQL保存指定文件
269      * @param str
270      * @param path
271      */
272     private static void sqlSave2File(String str,String path){
273         byte[] sourceByte = str.getBytes();
274         if(null != sourceByte){
275             try {
276                 File file = new File(path);
277                 if (!file.exists()) {
278                     File dir = new File(file.getParent());
279                     dir.mkdirs();
280                     file.createNewFile();
281                 }
282                 FileOutputStream outStream = new FileOutputStream(file);
283                 outStream.write(sourceByte);
284                 outStream.flush();
285                 outStream.close();
286                 System.out.println("生成成功");
287             } catch (Exception e) {
288                 log.debug("保存SQL文件异常:",e);
289             }
290         }
291     }
292 
293 
294 
295     public static void main(String[] args) throws Exception {
296         String str = ddlSqlGenerate("com.yjcmp.exchange.entity.ExApiBuckets", "ex_api_buckets", null, null);
297         log.error(str);
298         // batchDdlSqlGenerate2File("com.yjcmp.exchange.entity","./ddl.sql");
299     }
300 }

 

posted @ 2024-03-04 10:15  521pingguo1314  阅读(25)  评论(0编辑  收藏  举报