Java 中反向生成实体类思路和步骤

IDEA 2019.2.2
Java 8

根据不同的数据库数据去创建实体类,就要提取每个实体类的共同的特征,也就是先把它们共同的代码部分写出来,而需要更改的部分用一个不同的标记去进行替换。比如如下两个类:

package cn.hp.entity;

public class  Role {
    private Integer id;
    private String roleType;
}
package cn.hp.entity;

public class  User {
    private String uusername;
    private String upassword;
}

共同特征是

package cn.hp.entity;

public class 类名 {
    多个属性
}

因为不同的项目包名可能不一样,所以包名也要更改,修改如下

package 包名.entity;

public class 类名 {
    多个属性
}

好了,可以根据这个特征创建一个模板代码,这就需要有标记去替换要进行变化的代码部分,使用 ${} 方式去标记特定部分,做成模板如下:

package {packName}.entity;

public class{className} {
    ${propertyList}
}

根据 SQL 查询的内容去生成对应的实体类,就得获取到对应的字段名,在老师发的项目里的 DBUtil 类中的 query 方法中有这个关键的一条语句: ResultSetMetaData metaData = rst.getMetaData();rstResultSet 类型,获取结果集的元数据,里边有列名数据。在下面 query 方法代码中间的 while 语句块部分代码,代码内容如下:

public static List<Map> query(String sql, Object... obj) {
    getConn();
    try {
        pst = conn.prepareStatement(sql);
        System.out.println(sql);
        for (int i = 0; i < obj.length; i++) {
            System.out.println(obj[i]);
            pst.setObject(i + 1, obj[i]);
        }
        rst = pst.executeQuery();
        // 获取元数据
        ResultSetMetaData metaData = rst.getMetaData();
        List<Map> list = new ArrayList<>();
        while (rst.next()) {
            Map map = new HashMap();
            // 获取查询的元数据的总列数
            int count = metaData.getColumnCount();
            // 列数是从1开始
            for (int i = 1; i <= count; i++) {
                // 获取当前列的列名
                String key = metaData.getColumnLabel(i);
                // 获取记录的值
                Object value = rst.getObject(key);
                map.put(key, value);
            }
            list.add(map);
        }
        return list;
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        close();
    }
    return null;
}

有了这个方法,下面这条 SQL 语句获取表中所有表的字段名、类型等数据。

select TABLE_NAME tableName,COLUMN_NAME columnName,DATA_TYPE dataType,COLUMN_COMMENT columnComment from information_schema.`COLUMNS` where TABLE_SCHEMA = ?  and TABLE_NAME=?

现在开始写反向创建实体类的代码部分,功能请看注释

/**
 * 生成代码
 *
 * @param packName 包名
 * @param dbName 数据库名
 * @param tableName 表名
 */
public static String generate(String packName, String dbName, String tableName){
    // 实体类模板
    String classTemplate = "package {packName}.entity;\n" +
        "\n" +
        "public class{className} {\n" +
        "    {propertyList}\n" +
        "}";

    // 查询表结构
    List<Map> list = DBUtil.query("select TABLE_NAME tableName,COLUMN_NAME columnName,DATA_TYPE dataType,COLUMN_COMMENT columnComment from information_schema.`COLUMNS` where TABLE_SCHEMA = ?  and TABLE_NAME=?", dbName, tableName);

    // 根据查询到的表结构,获取字段名、字段类型
    // 进行生成拼接实体类的属性
    StringBuffer propertyList = new StringBuffer();
    for (Map map : list) {
        // 数据类型
        String type = map.get("dataType").toString();
        // 属性名
        String property = (String) map.get("columnName");
        propertyList.append("\tprivate " + convertDataType(type) + " " + property + ";\n");
    }

    // 把模板的对应的标签代码替换成生成的Java代码
    classTemplate = classTemplate.replace("{packName}", packName)
                .replace("{className}", toUpper(tableName))
                .replace("{propertyList}", propertyList.toString());

    // 返回生成代码
    return classTemplate;
}

/**
* 转化数据类型(将SQL中的数据类型转为Java的数据类型)
*
* @param dataType SQL中的数据类型
* @return
*/
public static String convertDataType(String dataType) {
    switch (dataType) {
        case "varchar":
        case "longtext":
        case "text":
            return "String";
        case "double":
            return "Double";
        case "int":
        case "tinyint":
            return "Integer";
        case "bigint":
            return "Long";
        case "datetime":
        case "timestamp":
        case "Date":
            return "Date";
        case "decimal":
            return "BigDecimal";
        default:
            return "";
    }
}


/**
* 开头字母转为大写
*
* @param s1
* @return
*/
public static String toUpper(String s1) {
    String r = "";
    //以_为分隔符,将单词分开
    String[] a = s1.split("_");
    String[] b = new String[a.length + 1];
    for (int i = 0; i < a.length; i++) {
        //substring(0,1)首字母,toUpperCase()大写
        b[i] = a[i].substring(0, 1).toUpperCase() + a[i].substring(1, a[i].length());
        r = r + b[i];
    }
    return r;
}

以上关键功能已经做好了,主要开始保存生成的代码了

public static void main(String[] args) {
    String packName = "cn.hp";
    String dbName = "test";
    String tableName = "userinfo";
    // 生成 test 数据库中的 userinfo 表的实体类代码
    String code = generate(packName, dbName, tableName);    
    // 保存文件
    saveFile(code, toUpper(tableName).concat(".java"));
}

/**
* 保存文件
*
* @param text 文件内容
* @param path 文件路径
*/
public static void saveFile(String text, String path) {
    PrintWriter pw = null;
    try {
        // 保存成 utf-8 格式文件
        pw = new PrintWriter(path, "UTF-8");
        pw.write(text);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (pw != null) {
            pw.close();
        }
    }
}

运行生成代码,生成实体类 .java 文件

《Java 中反向生成实体类思路和步骤》有1条评论

发表评论