1. 程式人生 > >自己寫一個ORM框架-實現生成javabean檔案--也是一個程式碼生成器的實現

自己寫一個ORM框架-實現生成javabean檔案--也是一個程式碼生成器的實現

我自己實現了一遍:碼雲克隆地址:點選開啟連結

眾所周知,ORM框架有很多,例如Hibernate,MyBatis,還有BeetlSQL等等,裡面獲取有很多我們不需要的功能,本系列部落格主要教大家如何寫一個簡單的ORM框架

我們這次先講如何生成JavaBean程式碼

主要有以下幾個步驟:

1. 獲取資料庫連線 
2. 獲取表的資訊 
3. 將資料庫的型別轉為Java型別 
4. 生成程式碼檔案

1.獲取資料庫連線

先寫配置檔案

#資料庫驅動
driver=com.mysql.jdbc.Driver
#資料庫url
url=jdbc\:mysql\://localhost\:3306/shiro
#資料庫使用者名稱 user=root #資料庫密碼 pwd=root #使用資料庫型別 usingDB=mysql #專案src地址 srcPath=/home/xjk/IdeaProjects/SORM/src #生成JavaBean包名 poPackage=com.jk.po
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

我們還需要一個配置資訊的管理類

public class Configuration {
    private String driver;
    private String url;
    private String user;
    private String pwd;
    private
String usingDB; private String srcPath; private String poPackage; public Configuration() { } /** * 省略setter和getter */ }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

然後需要一個數據庫管理類,來使用配置資訊生成資料庫連線

private static Configuration conf;
    static {
        Properties properties=new Properties();
        try {
            properties.load
(Thread.currentThread().getContextClassLoader().getResourceAsStream("db.properties")); } catch (IOException e) { e.printStackTrace(); } conf=new Configuration(); conf.setDriver(properties.getProperty("driver")); conf.setPoPackage(properties.getProperty("poPackage")); conf.setSrcPath(properties.getProperty("srcPath")); conf.setPwd(properties.getProperty("pwd")); conf.setUser(properties.getProperty("user")); conf.setUrl(properties.getProperty("url")); conf.setUsingDB(properties.getProperty("usingDB")); } public static Connection getConn(){ try { //要求JVM查詢並載入指定的資料庫驅動 Class.forName(conf.getDriver()); return DriverManager.getConnection(conf.getUrl(),conf.getUser(),conf.getPwd()); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } return null; } public static Configuration getConf(){ return conf; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

2.獲取表的資訊

我們使用TableContext來裝載所有表,使用T**ableInfo**來裝載每個表的資訊,ColumnInfo來裝載每個欄位的資訊,我們先從最小單位開始 
ColumnInfo

public  class ColumnInfo {
    /**
     * 欄位名
     */
    String name;
    /**
     * 欄位的資料型別
     */
    String dataType;
    /**
     * 欄位的鍵型別(0:普通鍵,1:主鍵,2:外來鍵)
     */
    int keyType;

    public ColumnInfo() {
    }
    /**
     * 省略setter和getter
     */
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

TableInfo

public class TableInfo {
    /**
     * 表名
     */
    private String tname;

    /**
     * 所有欄位資訊
     */
    private Map<String,ColumnInfo> columns;

    /**
     * 唯一主鍵(目前我們只能處理表中只有一個主鍵的情況)
     */
    private ColumnInfo onlyPriKey;

    /**
     * 聯合主鍵
     */
    private List<ColumnInfo> priKeys;

    public TableInfo() {
    }
    /**
     * 省略setter和getter
     * /
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

TableContext

public class TableContext {
    /**
     * 表名為key,表結構為value
     */
    public static Map<String,TableInfo> tables=new HashMap<>();

    private TableContext(){}

    static {
        try {
            Connection con=DBManager.getConn();
            DatabaseMetaData dbmd=con.getMetaData();
            //獲取所有表名
            ResultSet tableRet=dbmd.getTables(null,"%","%",new String[]{"TABLE"});
            while (tableRet.next()){
                String tableName= (String) tableRet.getObject("TABLE_NAME");
                TableInfo ti=new TableInfo(tableName,new HashMap<String,ColumnInfo>(),new ArrayList<ColumnInfo>());
                tables.put(tableName,ti);
                //獲取多個欄位和型別
                ResultSet set=dbmd.getColumns(null,"%",tableName,"%");
                while (set.next()){
                    ColumnInfo ci=new ColumnInfo(set.getString("COLUMN_NAME"),set.getString("TYPE_NAME"),0);
                    ti.getColumns().put(set.getString("COLUMN_NAME"),ci);
                }
                //獲取多個主鍵
                ResultSet set2=dbmd.getPrimaryKeys(null,"%",tableName);
                while (set2.next()){
                    String columnName=set2.getString("COLUMN_NAME");
                    System.out.println(columnName);
                    ColumnInfo ci2=ti.getColumns().get(columnName);
                    ci2.setKeyType(1);//設為主鍵
                    ti.getPriKeys().add(ci2);
                }
                if (ti.getPriKeys().size()>0){//取唯一主鍵,如果是聯合主鍵,則為空
                    ti.setOnlyPriKey(ti.getPriKeys().get(0));
                }
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

3.將資料庫的型別轉為Java型別

為了適配多種資料庫,我們先定義一個型別轉換器的介面

public interface TypeConvertor {
    /**
     * 將資料庫型別轉換為java資料型別
     * @param column 資料庫欄位的型別
     * @return java的資料型別
     */
    public String databaseType2JavaType(String column);

    /**
     * 將java資料型別轉換為資料庫型別
     * @param column java的資料型別
     * @return 資料庫欄位的型別
     */
    public String javaType2DatabaseType(String column);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

我們這裡只展示MySQL型別轉換器的寫法

public class MySQLTypeConvertor implements TypeConvertor{
    @Override
    public String databaseType2JavaType(String column) {
        switch (column.toLowerCase()){
            case "varchar":
            case "char":return "String";
            case "smallint":
            case "int":
            case "tinyint":return "Integer";
            case "bigint":return "Long";
            case "double":return "Double";
            case "float":return "Double";
            case "clob":return "java.sql.Clob";
            case "blob":return "java.sql.Blob";
            case "date":return "java.sql.Date";
            case "time":return "java.sql.Time";
            case "timestamp":return "java.sql.Timestamp";
            default:return null;
        }
    }

    @Override
    public String javaType2DatabaseType(String column) {
        //這裡後面再完善
        return null;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

4.生成程式碼檔案

我們需要用一個JavaFieldGetSet來裝載MySQL每個欄位對應的屬性還有setter和getter

public class JavaFieldGetSet {
    /**
     * 屬性原始碼資訊,如:private int id;
     */
    private String fieldInfo;
    /**
     * get方法的原始碼資訊,如:public int getId();
     */
    private String getInfo;
    /**
     * set方法的原始碼資訊,如:public void setId(int id);
     */
    private String setInfo;

    public JavaFieldGetSet() {

    }
    /**
     * 省略setter和getter
     * /
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在轉換的時候我們還要把名字格式從下劃線分隔轉為小駝峰,我們需要一個字元安轉換工具

public class StringUtils {
    /**
     * 將下劃線轉為大駝峰
     * @param str   目標字串
     * @return  變為大駝峰的字串
     */
    public static String underlineToBigCamel(String str){
        return underlineToSmallCamel(str.toUpperCase().substring(0,1)+str.substring(1));
    }

    /**
     * 將下劃線轉為小駝峰
     * @param str   目標字串
     * @return  變為小駝峰的字串
     */
    public static String underlineToSmallCamel(String str){
        if (str==null||"".equals(str.trim())){
            return "";
        }
        int len=str.length();
        StringBuilder sb=new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c=str.charAt(i);
            if (c=='_'){
                if (++i<len){
                    sb.append(Character.toUpperCase(str.charAt(i)));
                }
            }else{
                sb.append(c);
            }
        }
        return sb.toString();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

程式碼生成的工具

public class JavaFileUtils {
    /**
     * 根據欄位資訊生成java屬性資訊,如:var username-->private String username;相應的set和get方法原始碼
     * @param column    欄位資訊
     * @param convertor 型別轉換器
     * @return  java屬性的set/get方法
     */
    public static JavaFieldGetSet createFieldGetSetSRC(ColumnInfo column, TypeConvertor convertor){
        JavaFieldGetSet jfgs=new JavaFieldGetSet();
        //將欄位轉為java屬性
        String javaFiledType= convertor.databaseType2JavaType(column.getDataType());
        String colunmName=StringUtils.underlineToSmallCamel(column.getName());
        //生成欄位資訊
        jfgs.setFieldInfo("\tprivate "+javaFiledType+" "+colunmName+";\n");
        //生成getter
        StringBuilder getSrc=new StringBuilder();
        getSrc.append("\tpublic "+javaFiledType+" get"+StringUtils.underlineToBigCamel(column.getName())+"(){\n");
        getSrc.append("\t\treturn "+colunmName+";\n");
        getSrc.append("\t}\n");
        jfgs.setGetInfo(getSrc.toString());
        //生成setter
        StringBuilder setSrc=new StringBuilder();
        setSrc.append("\tpublic void set"+StringUtils.underlineToBigCamel(column.getName())+"("+javaFiledType+" "+colunmName+"){\n");
        setSrc.append("\t\tthis."+colunmName+"="+colunmName+";\n");
        setSrc.append("\t}\n");
        jfgs.setSetInfo(setSrc.toString());
        return jfgs;
    }

    /**
     * 根據表資訊生成java原始碼
     * @param tableInfo 表資訊
     * @param convertor 資料型別轉換器
     * @return  java類的原始碼
     */
    public static String createJavaSrc(TableInfo tableInfo,TypeConvertor convertor){
        Map<String,ColumnInfo>columns=tableInfo.getColumns();
        List<JavaFieldGetSet> javaFields=new ArrayList<>();
        for (ColumnInfo columnInfo:columns.values()){
            JavaFieldGetSet javaFieldGetSet=createFieldGetSetSRC(columnInfo,convertor);
            javaFields.add(javaFieldGetSet);
        }
        StringBuilder src=new StringBuilder();
        //生成package語句
        src.append("package "+ DBManager.getConf().getPoPackage()+";\n");
        //生成import語句
        src.append("import java.sql.*;\n");
        src.append("import java.util.*;\n\n");
        //生成類宣告語句
        src.append("public class "+StringUtils.underlineToBigCamel(tableInfo.getTname())+"{\n");
        //生成屬性列表
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            src.append(javaFieldGetSet.getFieldInfo());
        }
        src.append("\n\n");
        //生成get方法列表
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            src.append(javaFieldGetSet.getGetInfo());
        }
        src.append("\n\n");
        //生成set方法列表
        for (JavaFieldGetSet javaFieldGetSet:javaFields){
            src.append(javaFieldGetSet.getSetInfo());
        }
        src.append("\n\n");
        //生成結束符
        src.append("}");
        return src.toString();
    }

    /**
     * 生成java檔案
     * @param tableInfo 表資訊
     * @param convertor 型別轉換器
     */
    public static void createJavaPoFile(TableInfo tableInfo,TypeConvertor convertor){
        //獲取原始碼
        String src=createJavaSrc(tableInfo,convertor);
        String srcPath=DBManager.getConf().getSrcPath()+"/";
        //將包名轉換為檔名,然後和srcPath拼接
        String packagePath=DBManager.getConf().getPoPackage().replace(".","/");
        File f=new File(srcPath+packagePath);
        if (!f.exists()){
            f.mkdirs();
        }
        BufferedWriter bw=null;
        try {
            //將原始碼寫入檔案
            bw=new BufferedWriter(new FileWriter(f.getAbsoluteFile()+"/"+StringUtils.underlineToBigCamel(tableInfo.getTname())+".java"));
            bw.write(src);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (bw!=null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 更新表結構
     */
    public static void updateJavaPOFile(){
        Map<String,TableInfo>tables=TableContext.tables;
        for(TableInfo tableInfo:tables.values()){
            createJavaPoFile(tableInfo,new MySQLTypeConvertor());
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113

當我們呼叫JavaFileUtilsupdateJavaPOFile方法時,便會在相應的目錄生成該資料庫裡所有表物件的JavaBean


相關推薦

自己一個ORM框架-實現生成javabean檔案--一個程式碼生成器實現

我自己實現了一遍:碼雲克隆地址:點選開啟連結 眾所周知,ORM框架有很多,例如Hibernate,MyBatis,還有BeetlSQL等等,裡面獲取有很多我們不需要的功能,本系列部落格主要教大家如何寫一個簡單的ORM框架 我們這次先講如何生成JavaBean程式碼

深入Java日記——自己一個ORM框架(1)

眾所周知,ORM框架有很多,例如Hibernate,MyBatis,還有BeetlSQL等等,裡面獲取有很多我們不需要的功能,本系列部落格主要教大家如何寫一個簡單的ORM框架 這個ORM框架主要有以下功能: 1. 生成JavaBean程式碼 2. 通過

一個自己的MVC框架

xml文件 ast target 實現類 讀取 能說 位置 加載 -i   也有個一周沒有更新博客了,其實我沒有偷懶,因為之前一直在看Spring源碼,所以想著去寫一個類Spring的框架,也沒有給自己定什麽高的要求,簡單實現MVC、AOP、IOC等功能就行。現在這個框架基

建表sql生成javaBean檔案(PostgreSQL版本)

前言 在公司開發應用中,資料庫表、欄位的命名通常要與類、屬性命名相對應,例如欄位命名為user_id,對應的屬性名為userId,這樣駝峰式的命名。 開發一個模組去維護單表資料時,當確定好表結構時準備開發的時候,執行完建表sql,一開始編寫實體類,這個過程相當無聊,由於有了

從零分散式RPC框架 系列 2.0 (4)使用BeanPostProcessor實現自定義@RpcReference註解注入

之前服務提供方 RpcServer 我們是使用 ApplicationContextAware 來掃描 @RpcService 註解,新增一個註解即可實現服務暴露。現在,我們用 BeanPostProcessor 來實現服務注入,自動將服務實現類注入到被@RpcReference註解標記

開源ORM框架介紹

手寫開源ORM框架介紹 簡介 前段時間利用空閒時間,參照mybatis的基本思路手寫了一個ORM框架。一直沒有時間去補充相應的文件,現在正好抽時間去整理下。通過思路歷程和程式碼註釋,一方面重溫下知識,另一方面準備後期去完善這個框架。 傳統JDBC連線 參照傳統的JDBC連線資料庫過程如下,框架所做的事情就是把

shell自動生成檔案一個問號的字尾

寫了一個指令碼,自動處理一個檔案。   rm -f session.log rm -f link wget ftp://hostname/f:/ddn/session.log egrep '^N[[:digit:]]|^D[1-4]' session.log >>lin

Struts框架上傳下載檔案輔助類,簡單實現Struts上傳圖片以及下載

       首先在看這篇文章的前提下,你得會用Struts框架,有一定的基礎瞭解,說白了瞭解怎麼搭建就行了,然後基本就能順利執行本篇文章的Demo,當然這個類不僅僅侷限於圖片上傳下載的,因為是自己用流寫的方法所以可以支援其他檔案上傳下載。

程式碼生成器——實現生成pojo,sql,mapper介面

程式碼生成器(記錄一次興趣程式碼,多多指教。轉載請標明作者) 在我們開始實現程式碼生成器之前我們先來對程式碼生成器有一個簡單的瞭解。 1.什麼是程式碼生成器? 故名思義,也就是生成程式碼的一個程式。那它是一個什麼樣的機制?怎麼體現這種機制? 比如:我們學習的 JSP 技術,瀏覽器並不能直接識別 JSP 檔案。

自己的將BUFFER輸出成C檔案的陣列

#define TEXT(X) (X) typedef unsigned __int64 u64; typedef unsigned __int32 u32; typedef unsigned __int16 u16; typedef unsigned __i

POI實現生成excel檔案

匯入jar包,一般只操作xls檔案時匯入poi.version.date.jar包就可以 // 第一步,建立一個webbook,對應一個Excel檔案 HSSFWorkbook wb = new HSSFWorkbook(); // 第

利用Freemarker自動生成JavaBean檔案

序: 特點:基本上能夠滿足簡單JavaBean的生成,可以通過配置檔案的更改,靈活自動生成對應的bean。 缺點: 1.這裡只是作為一個簡單的例子,在實際應用當中仍需要更改具體的程式碼,以應對不同名稱,不同包名的類,總言之就是配置方面還不夠靈活。 2.對於配置資原始檔的對應

caffe使用均值檔案生成.npy檔案的Python程式碼,供後面模型測試使用

import sys,os caffe_root =’/home/hadoop/caffe/’ sys.path.append(’/home/hadoop/caffe/python’) import caffe os.chdir(caffe_root) impo

.NET Core實戰專案之CMS 第十二章 開發篇-Dapper封裝GURD及倉儲程式碼生成器實現

本篇我將帶著大家一起來對Dapper進行下封裝並實現基本的增刪改查、分頁操作的同步非同步方法的實現(已實現MSSQL,MySql,PgSQL)。同時我們再實現一下倉儲層的程式碼生成器,這樣的話,我們只需要結合業務來實現具體的業務部分的程式碼就可以了,可以大大減少我們重複而又繁瑣的增刪改查操作,多留點時間給生活

.NET Core實戰專案之CMS 第十二章 開發篇-Dapper封裝CURD及倉儲程式碼生成器實現

本篇我將帶著大家一起來對Dapper進行下封裝並實現基本的增刪改查、分頁操作的同步非同步方法的實現(已實現MSSQL,MySql,PgSQL)。同時我們再實現一下倉儲層的程式碼生成器,這樣的話,我們只需要結合業務來實現具體的業務部分的程式碼就可以了,可以大大減少我們重複而又繁瑣的增刪改查操作,多留點時間給生活

Java 實現上傳檔案服務端程式碼(一)

服務端:通過Servlet + fileupload 等實現 jar:commons-fileupload-1.3.1.jar,commons-io-2.4.jar 客戶端上傳見:Java 上傳檔案客戶端程式碼(二) package com.http.servlet;

ssm框架學習---mybatis學習檔案結構和程式碼示例

準備工作:mybatis的jar包,資料庫的驅動包,日誌log4j和單元測試的包 開發模式:(1)基於原始dao開發,需要編寫dao介面和dao介面的實現類                     (2)基於mapper開發,只需編寫dao介面,但是需要遵守一定規範(對映檔

自己ORM框架 DBUtils

技術 外部 acl reat 開源 htm pac top enter ORM框架想必大家都比較熟知了,即對象關系映射(英語:Object Relation Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程序技術,用於實現面向對象編程語言裏不同類

C#.NET 程序員的福利,自己一個XML操作類,可實現像jquery一樣方便的xml操作,且不用專門去處理命名空間。

console region ignorecas node 處理 命名空間 void clone 一個 此工具是進入一家新公司之後實現的,主要是工作當中操作 xml 的時間太多,因為公司按任務計“工作量”,領導給我安排的時間遠遠不夠完善此工具【悲哀的

傳智:自己簡單實現一個struts2框架的demo

throws for request 運行 本地化 color ray run main struts2的結構圖: 代碼實現: 組織結構: 主要代碼: package cn.itcast.config; import org.apache.log4j.Logg