Panda ORM原始碼-資料庫表自動生成Java實體類

longmanma發表於2021-09-09

一,整體思路

1,首先明確目標,需要透過指定資料庫名,自動生成該資料庫中所有表對應的Java實體類。

2,資料庫名及其他一些引數(跟資料庫url、使用者、密碼、實體類儲存路徑)透過配置檔案設定。

3,連線資料庫後,透過資料庫名獲取該資料庫中所有的表。對於MySQL來說,可以透過select table_name from information_schema.tables where table_schema='XXX',來獲取XXX資料庫中所有的表名。PS:對於information_schema資料庫不瞭解的可以開啟看下,information_schema.tables儲存了執行在MySQL上表的資訊。

4,透過Java程式碼讀取表結構資訊,生成對應的Java類字串,將字串寫入檔案。

二,引數設定

引數儲存在src目錄下config.properties檔案下,透過Constants的static方法獲取配置檔案資訊,具體程式碼如下:

config.properties程式碼如下,注意前五個引數為資料庫連線需要的引數,table_schema表示資料庫名,entity_package_name表示生成實體類的包名,兩個path分別表示實體類檔案及日誌儲存路徑。

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/bank_performance?useUnicode=true&characterEncoding=utf-8
user=root
password=Pass1234
table_schema=bank_performance
entity_package_name=panda.bank.entity
file_save_path=D:\Java\AutoEntity\
file_log_path=D:\Java\AutoEntity\

讀取配置檔案是透過Constants 中的static方法實現:

package panda.orm.util;
public class Constants {
        //Property類程式碼在下面
    public static Property CONFIG_PROPERTY;
    public static String getFormatDateTime(){
        SimpleDateFormat formater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return formater.format(new Date());
    }
    public static String getLogFormatDateTime(){
        SimpleDateFormat formater = new SimpleDateFormat("yyyyMMddhhmmss");
        return formater.format(new Date());
    }
    static{
        Properties fileProperties = new Properties();  
        InputStream inputStream = fileProperties.getClass().getResourceAsStream("/config.properties");  
        CONFIG_PROPERTY=new Property();
        try{  
            fileProperties.load(inputStream);  
            CONFIG_PROPERTY.setDriver(fileProperties.getProperty("driver"));  
            CONFIG_PROPERTY.setUrl(fileProperties.getProperty("url"));  
            CONFIG_PROPERTY.setUser(fileProperties.getProperty("user"));  
            CONFIG_PROPERTY.setPassword(fileProperties.getProperty("password"));  
            CONFIG_PROPERTY.setTable_schema(fileProperties.getProperty("table_schema"));  
            CONFIG_PROPERTY.setFile_save_path(fileProperties.getProperty("file_save_path"));  
            CONFIG_PROPERTY.setFile_log_path(fileProperties.getProperty("file_log_path"));  
            CONFIG_PROPERTY.setEntity_package_name(fileProperties.getProperty("entity_package_name"));  
        }catch (IOException ex){  
            ex.printStackTrace();  
        }finally{  
            try {
                inputStream.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }  
        }  
    }
}

package panda.orm.util;
public class Property{
    private String driver;
    private String url;
    private String user;
    private String password;
    private String table_schema;
    private String file_save_path;  
    private String file_log_path;
    private String entity_package_name;
        //省略get set

三,EntityGenerater.generateClasses()方法直接生成資料庫中所有表對應實體類,直接上程式碼看註釋部分即可:

package panda.orm.util;
import java.io.File;
import java.io.FileOutputStream;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import panda.orm.database.MySQLHandler;
import panda.orm.exception.SqlExcuteException;
/**
 * 由MySQL資料庫自動生成Java實體類
 * @author 貓哥
 * @date 2017.3.23
 */
public class EntityGenerater {
    //在配置完config.properties之後,直接呼叫EntityGenerater類的靜態方法generateClasses即可生成對應Java實體類
    public static void main(String[] args) {
        EntityGenerater.generateClasses();
    }
    //generateClasses方法做了三件事
    //1,構造方法獲取需要的引數
    //2,init方法生成資料庫對應的表-類結構
    //3,write方法負責將類結構轉換為實體類程式碼字串並寫入檔案
    public static void generateClasses(){
        EntityGenerater eg=new EntityGenerater(Constants.CONFIG_PROPERTY.getTable_schema(),
                Constants.CONFIG_PROPERTY.getEntity_package_name(),Constants.CONFIG_PROPERTY.getFile_save_path());
        eg.init();
        eg.write();
        System.out.println("Panda ORM generate success!");
    }
    //tables儲存了資料庫的結構,tables的key表示表名,key對應的結合表示該表的所有列名集合
    private Map> tables=new HashMap>();
    private String table_schema;
    private String entity_package_name;
    private String entity_save_path;
    public EntityGenerater(String table_schema,String entity_package_name,String entity_save_path){
        this.table_schema=table_schema;
        this.entity_package_name=entity_package_name;
        this.entity_save_path=entity_save_path;
    }
    public void init(){
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        //資料庫名
        String table_schema =Constants.CONFIG_PROPERTY.getTable_schema();
        //獲取資料庫下所有表的sql語句
        String sql="select table_name from information_schema.tables where table_schema='"+table_schema+"'";
        tables.clear();
        try {
            rs=hand.query(sql);
            while(rs.next()){
                String tableName=rs.getString("table_name");
                //getColumns方法獲取表對應的列
                Set columns=getColumns(tableName);
                //將表和對應列結合放入tables
                tables.put(tableName, columns);
            }
        } catch (Exception ex) {
            new SqlExcuteException(ex.getMessage(),this.getClass().getName(),"sql執行異常",sql);
        }finally{
            hand.sayGoodbye();
        }
    }
    //獲取表對應的列名集合
    private Set getColumns(String tableName){
        MySQLHandler hand=new MySQLHandler();
        ResultSet rs=null;
        String sql="select * from "+tableName;
        Set columns=new HashSet();
        try {
            rs=hand.query(sql);
            ResultSetMetaData meta=rs.getMetaData();
            int count=meta.getColumnCount();
            for(int i=0;i columns = (Set)entry.getValue();
            //核心方法,將表明和對應列資訊轉換為實體類程式碼
            String entityString=getEntityString(tableName,columns);
            //寫檔案
            try{
                String path=entity_save_path+turnFirstUp(tableName)+".java";
                File file=new File(path);
                if(!file.exists())
                    file.createNewFile();
                FileOutputStream out=new FileOutputStream(file,true);       
                out.write(entityString.getBytes("utf-8"));
                out.close();
            }
            catch(Exception ex){
                ex.printStackTrace();
            }          
        }
    }
    //核心方法,將表明和對應列資訊轉換為實體類程式碼
    private String getEntityString(String tableName,Set columns){
        StringBuilder sb=new StringBuilder();
        //包名及類註釋
        sb.append("package "+entity_package_name+";rn");
        sb.append("/**rn");
        sb.append("* " + new Date() + "rn");
        sb.append("* Panda ORM atuo generate: " + tableName + " rn");
        sb.append("*/ rn");   
        //類定義
        sb.append("public class " + turnFirstUp(tableName) + "{rn");
        //屬性
        for(String colName:columns){
            sb.append("tprivate String "+colName+";rn");
        }
        //方法
        for(String colName:columns){
            sb.append("tpublic String get"+turnFirstUp(colName)
                    +"(){rn");
            sb.append("ttreturn "+colName+";rn");
            sb.append("t}rn");
            sb.append("tpublic void set"+turnFirstUp(colName)
                    + "(String "+colName+"){rn");
            sb.append("ttthis."+colName+"="+colName+";rn");
            sb.append("t}rn");
        }
        sb.append("}");
        return sb.toString();
    }
    //首字母大寫
    private String turnFirstUp(String str) {
        char[] ch = str.toCharArray();
        if(ch[0]>='a'&&ch[0]

四,測試,以馬上要開始講解的銀行業績系統資料庫為例,表結構如下圖(具體含義先不解釋,只是演示由資料庫生成實體程式碼):

圖片描述

然後執行,注意配置檔案就按開頭說的配置的。

public static void main(String[] args) {
        EntityGenerater.generateClasses();
    }

執行後,控制檯提示:Panda ORM generate success!,表示成功,根據配置檔案在目錄下發現:
圖片描述

開啟User.java,成功。

package panda.bank.entity;
/**
* Thu Mar 23 11:30:12 CST 2017
* Panda ORM atuo generate: user 
*/ 
public class User{
    private String user_name;
    private String user_role;
    private String user_job;
    private String user_password;
    private String user_id;
    private String user_department;
    public String getUser_name(){
        return user_name;
    }
    public void setUser_name(String user_name){
        this.user_name=user_name;
    }
    public String getUser_role(){
        return user_role;
    }
    public void setUser_role(String user_role){
        this.user_role=user_role;
    }
    public String getUser_job(){
        return user_job;
    }
    public void setUser_job(String user_job){
        this.user_job=user_job;
    }
    public String getUser_password(){
        return user_password;
    }
    public void setUser_password(String user_password){
        this.user_password=user_password;
    }
    public String getUser_id(){
        return user_id;
    }
    public void setUser_id(String user_id){
        this.user_id=user_id;
    }
    public String getUser_department(){
        return user_department;
    }
    public void setUser_department(String user_department){
        this.user_department=user_department;
    }
}

五,補充說明

根據Panda ORM整體的設計,所有類屬性都是String型別,其實可以根據表中的資料型別轉換屬性型別,此處不再加以演示。

有了實體類程式碼後,需要新增主鍵、外來鍵註釋,並需要將外來鍵對應屬性型別改為外來鍵指向表實體型別,然後就可以直接利用Panda ORM生成常用的增、刪、改、查方法。

增、刪、改沒有問題,查的話只提供了最基本的查數量、分頁查、查全部、按主鍵查的功能。更加複雜的查詢還是要寫原生的sql程式碼,有點遺憾。但是想想MyBatis每個都要單獨寫sql和Hibernate複雜的配置,心裡又好受了很多,哈哈。下篇演示透過註解實現ORM的思路和原始碼。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2730/viewspace-2798541/,如需轉載,請註明出處,否則將追究法律責任。

相關文章