拒绝无意义劳动 -- java 数据表对应实体类生成器

01、需求

基于数据表结构生成java实体类。可以指定数据表,可以生成注解,自动引入包,生成字段注释。

02、思路

整个过程可以拆解成以下几个步骤:

  1. 连接数据库
  2. 获取数据表结构信息
  3. 解析数据表结构信息,包括字段名、表名下划线转驼峰, mysql数据类型转java包装类等。
  4. 根据解析后的数据使用类模板生成代码
  5. 获取工程路径,根据输入的包路径获取实体类生成位置
  6. 使用文件输出流输出.java文件

03、代码实现

数据列信息实体类

@Data
public class ColumnInfo {
    /**
     * 主键标识
     */
    private Integer Key;
    /**
     * 列名称
     */
    private String name;
    /**
     * 数据类型
     */
    private Integer dataType;
    /**
     * 数据类型名称
     */
    private String dataTypeName;
    /**
     * 自增标识
     */
    private Integer AutoIncrement;
    /**
     * 精度
     */
    private Integer precision;
    /**
     * 是否为空
     */
    private Integer isNull;
    /**
     * 小数位数
     */
    private Integer scale;
    /**
     * 默认值
     */
    private String defaultValue;
    /**
     * 注释
     */
    private String comment;
}
复制代码

数据库连接及表结构信息获取


public class DataBaseScan {

    private String dataBaseUrl;
    private Integer port;
    private String dataBaseName;
    private String userName;
    private String password;

    private static final long serialVersionUID = 1L;
    Connection conn = null;
    Statement st = null;

    /**
     * @param dataBaseUrl
     * @param port
     * @param userName
     * @param password
     */
    public DataBaseScan(String dataBaseUrl, Integer port, String dataBaseName, String userName, String password) {
        this.dataBaseUrl = dataBaseUrl;
        this.port = port;
        this.userName = userName;
        this.password = password;
        this.dataBaseName = dataBaseName;
    }


    //获取conn
    public void init() {
        try {
            if (StringUtils.isBlank(dataBaseUrl) || StringUtils.isBlank(dataBaseName) || StringUtils.isBlank(userName) || port == null) {
                throw new IllegalArgumentException("数据库连接信息缺失!");
            } else {
                Class.forName("com.mysql.jdbc.Driver").newInstance();
                conn = java.sql.DriverManager.getConnection("jdbc:mysql://"+ dataBaseUrl +":" + port + "/" + dataBaseName, userName, password);
            }
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }


    public List<ColumnInfo> getTableInfo(String tableName) throws SQLException {
        init();
        DatabaseMetaData dbmd = conn.getMetaData();
        ResultSet pkrs = dbmd.getPrimaryKeys(null, null, tableName);
        String pkrsName = "";
        while(pkrs.next()){
            pkrsName = pkrs.getString("COLUMN_NAME");
        }
        ResultSet rs = dbmd.getColumns(null, null, tableName.toUpperCase(), null);
        /**判断字段是否自增*/
        String sql = "select * from " + tableName + " where 1=2";
        ResultSet rst = conn.prepareStatement(sql).executeQuery();
        ResultSetMetaData rsmd = rst.getMetaData();
        int i=1;
        List<ColumnInfo> table = new ArrayList<>();
        while(rs.next()){
            //列名称
            String columnName = rs.getString("COLUMN_NAME");
            //数据类型
            int dataType = rs.getInt("DATA_TYPE");
            //数据类型名称
            String dataTypeName = rs.getString("TYPE_NAME");
            //精度,列的大小
            int precision = rs.getInt("COLUMN_SIZE");
            //小数位数
            int scale = rs.getInt("DECIMAL_DIGITS");
            //是否为空
            int isNull = rs.getInt("NULLABLE");
            //字段默认值
            String defaultValue = rs.getString("COLUMN_DEF");
            //注释
            String comennt = rs.getString("REMARKS");
            //是否自增
            boolean isAutoIncrement = false;
            try {
                isAutoIncrement = rsmd.isAutoIncrement(i);
            } catch (SQLException e) {
                break;
            }
            ColumnInfo col = new ColumnInfo();
            col.setComment(comennt);
            col.setName(columnName);
            col.setDataType(dataType);
            col.setDataTypeName(dataTypeName);
            col.setPrecision(precision);
            col.setScale(scale);
            col.setIsNull(isNull);
            col.setDefaultValue(defaultValue);
            if (isAutoIncrement) {
                col.setAutoIncrement(1);
            } else {
                col.setAutoIncrement(0);
            }
            if (columnName.equals(pkrsName)) {
                col.setKey(1);
            } else {
                col.setKey(0);
            }
            table.add(col);
            i++;
        }
        rs.close();
        return table;
    }
}
复制代码

mysql数据类型转java包装类

public class SqlTypeEnum {
    public static String transToJavaType(String mysqlType) {
        if (mysqlType == null) {
            return "null";
        }
        switch (mysqlType) {
            case "VARCHAR":
            case "CHAR" :
            case "TEXT" :
                return "String";

            case "BLOB" :
                return "byte[]";

            case "INTEGER" :
            case "BIGINT" :
            case "ID" :
                return "Long";

            case "TINYINT" :
            case "SMALLINT" :
            case "MEDIUMINT" :
            case "BOOLEAN" :
            case "INT" :
                return "Integer";

            case "BIT" :
                return "Boolean";

            case "FLOAT" :
                return "Float";

            case "DOUBLE" :
                return "Double";

            case "DECIMAL" :
                return "BigDecimal";

            case "DATE" :
            case "YEAR" :
                return "Date";

            case "DATETIME" :
            case "TIMESTAMP" :
                return "Timestamp";

            default :
                return "null";
        }
    }

}
复制代码

数据表结构信息解析及实体类生成

public class PojoGenerator {

    private DataBaseScan dataBaseScan = null;

    /**
     * 实体类生成构造方法
     * @param dataBaseUrl 数据库连接地址
     * @param port 端口
     * @param dataBaseName 数据库名
     * @param userName 用户名
     * @param password 密码
     */
    public PojoGenerator(String dataBaseUrl,Integer port, String dataBaseName, String userName, String password) {
        dataBaseScan = new DataBaseScan(dataBaseUrl, port, dataBaseName, userName, password);
    }

    /**
     * 实体类生成
     * @param packagePath 实体类包路径
     * @param tableName 表明
     * @param ORMType orm框架类型 【可选:jpa,mybatis等】
     */
    public void generate(String packagePath, String tableName, String ORMType) {
        try {

            List<ColumnInfo> tableInfo = dataBaseScan.getTableInfo(tableName);
            if (CollectionUtils.isEmpty(tableInfo)) {
                System.out.println("获取数据表信息失败!");
                return;
            }
            String head = headGenerator(packagePath, tableName, ORMType);
            String content = contentGenerator(tableInfo,ORMType);
            String pojo = head + content + "}";
            String folderPath = System.getProperty("user.dir") + "\src\main\java\" + packagePath.replace(".","\") + "\";
            String className = transToHump(tableName, true) + ".java";
            //文件流输出
            File file = new File(folderPath + className);

            try (FileOutputStream fileOutputStream = new FileOutputStream(file)) {

                fileOutputStream.write(pojo.getBytes(StandardCharsets.UTF_8));
                fileOutputStream.flush();

            } catch (IOException ie) {
                ie.printStackTrace();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

    /**
     * 生成头
     * @param ORMType
     * @return
    */
    private String headGenerator(String packagePath, String tableName, String ORMType) {
        String pack = "package " + packagePath +";\n";
        String className = "public class " + transToHump(tableName,true) + " {\n";
        String dependency;
        String annotion;
        if (ORMType.equals("jpa")) {
            dependency = "import javax.persistence.Entity;\n" +
                    "import javax.persistence.GeneratedValue;\n" +
                    "import javax.persistence.GenerationType;\n" +
                    "import javax.persistence.Id;\n" +
                    "import java.util.Date;\n" +
                    "import java.math.BigDecimal;\n" +
                    "import lombok.Data;\n" +
                    "import java.sql.Timestamp; \n";
            annotion = "@Data\n@Entity\n";
        } else {
            dependency = "import java.util.Date;\n" +
                    "import java.math.BigDecimal;\n" +
                    "import lombok.Data;\n" +
                    "import java.sql.Timestamp; \n";
            annotion = "@Data\n";
        }
        return pack + dependency + "\n\n" + annotion + className;
    }

    private String contentGenerator(List<ColumnInfo> tableInfo, String ORMType) {
        String modifier = "private ";
        StringBuilder content = new StringBuilder();
        for (ColumnInfo columnInfo : tableInfo) {
            String annotion = "";
            //字段名
            String fieldName = transToHump(columnInfo.getName(),false);
            //注释
            String comment = "";
            String fieldType = SqlTypeEnum.transToJavaType(columnInfo.getDataTypeName()) + gap(1);
            if (!StringUtils.isBlank(columnInfo.getComment())) {
                comment = "/**\n"
                        + "    * " + columnInfo.getComment() + "\n"
                        + "    */\n";
            }
            //主键注解
            if (columnInfo.getKey() == 1 && ORMType.equals("jpa")) {
                if (columnInfo.getAutoIncrement() == 1) {
                    annotion = "@Id\n" +
                            gap(4) + "@GeneratedValue(strategy= GenerationType.IDENTITY)\n";
                } else {
                    annotion = "@Id\n";
                }
            }
            if (!StringUtils.isBlank(comment) || !StringUtils.isBlank(annotion)) {
                content.append(gap(4) + comment + annotion + gap(4) + modifier + fieldType + fieldName + ";\n");
            } else {
                content.append(gap(4) + comment + annotion + modifier + fieldType + fieldName + ";\n");
            }
        }
        return content.toString();
    }


    /**
     * 生成缩进
     * @param num
     * @return
     */
    private String gap(int num) {
        StringBuilder gap = new StringBuilder();
        for (int i=0; i<num; i++) {
            gap.append(" ");
        }
        return gap.toString();
    }

    /**
     * 字段名转换成驼峰
     * @param field
     * @param isTableName  是否首字母大写
     * @return
     */
    private  String transToHump(String field, boolean isTableName){
        if (field == null){
            return "";
        }
        StringBuilder s = new StringBuilder();
        boolean flag = false;
        for (int i=0; i<field.length(); i++){
            if (field.charAt(i) == '_'){
                flag = true;
                continue;
            }
            if (flag){
                flag = false;
                //转换成大写
                s.append(String.valueOf(field.charAt(i)).toUpperCase());
                continue;
            }
            if (i == 0 && isTableName){
                //首字母大写
                s.append(String.valueOf(field.charAt(i)).toUpperCase());
            } else {
                s.append(field.charAt(i));
            }
        }
        return s.toString();
    }
复制代码

测试

    @Test
    void test() throws ServletException, IOException, SQLException {
        //参数:数据库地址,端口,数据库名,用户名,密码
        PojoGenerator pojoGenerator = new PojoGenerator("127.0.0.1",3306,"test","root","");
        //参数:包路径,表名,orm框架类型
        pojoGenerator.generate("com.feng.pojo", "news", "jpa");
        
    }
复制代码

总结

由于作者使用jpa比较多,所以可选的orm框架只有jpa,其他的orm框架需要生成特殊注解的则需要自己手动输入。在生成包引入时,为了方便,我直接把常用的实体类包全部引入。由于懒得再写get、set方法的生成,生成器需要配合lombok插件使用。 总之还是不够智能。不过也勉强能满足使用。聊胜于无吧。

Guess you like

Origin juejin.im/post/7031815779834134564