第32次文章:手寫SORM框架(二)

  • 2019 年 10 月 8 日
  • 筆記

在上周,我們將整個SORM的框架結構梳理了一下,本周開始對整個框架的每個細節步驟進行相關的填充。目前還沒有把整個框架全部搭建起來,只完成了一小部分,這周我們就對已完成的類中,一些比較有意思的功能進行一個小介紹吧!


1、核心bean中的JavaFieldGetSet類

在核心Javabean類中,我們增加了一個JavaFieldGetSet類,主要用於封裝一個java屬性的get和set方法的源碼。

JavaFieldGetSet類中,設置有三個屬性參數,分別為:

(1)fieldInfo:主要存儲屬性源碼信息,如:private int userId;

(2)getInfo:get方法源碼。如:public int getUserId(){}

(3)setInfo:set方法源碼。如:public void setUserId(int id){this.id = id;}

需要注意的是JavaFieldGetSet類本身也屬於一個Javabean類,內部只包括三個屬性的set和get方法,以及無參構造器和帶參構造器。

2、工具類Utils中的JavaFileUtils類

根據上周我們的架構預設,JavaFileUtils中主要是封裝生成Java文件(源代碼)常用的操作。

針對上面提到的JavaFieldGetSet類,我們封裝相應的方法來生成源碼信息。此處我們着重分享生成源碼的方法:根據字段信息生成java屬性信息。如:var username –>private String username;以及相應的set和get方法源碼。該方法的程序代碼如下:

package com.peng.sorm.utils;    import com.peng.sorm.bean.ColumnInfo;  import com.peng.sorm.bean.JavaFieldGetSet;  import com.peng.sorm.core.MySqlTypeConvertor;  import com.peng.sorm.core.TypeConvertor;    /**   * 封裝了生成Java文件(源代碼)常用的操作   *   */  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();      String javaFieldType = convertor.databaseType2JavaType(column.getDataType());//獲取屬性在java中的數據類型        //private String username;      //生成屬性源碼      jfgs.setFieldInfo("tprivate "+javaFieldType+" "+column.getName()+";n");        //public String getUsername(){return username;}      //生成get方法的源碼      StringBuilder getSrc = new StringBuilder();      getSrc.append("tpublic "+javaFieldType+" get"+StringUtils.firstChar2UpperCase(column.getName())+"(){n");      getSrc.append("ttreturn "+column.getName()+";n" );      getSrc.append("t}n");      jfgs.setGetInfo(getSrc.toString());        //public void setUsername(String username){this.username=username;}      //生成set方法的源碼      StringBuilder setSrc = new StringBuilder();      setSrc.append("tpublic void set"+StringUtils.firstChar2UpperCase(column.getName())+"(");      setSrc.append(javaFieldType+" "+column.getName()+"){n");      setSrc.append("tt this."+column.getName()+"="+column.getName()+";n" );      setSrc.append("t}n");      jfgs.setSetInfo(setSrc.toString());      return jfgs;    }  }

tips:在上面的代碼中,我們封裝了一個createFieldGetSetSRC()方法,根據屬性聲明,set,get方法的格式,使用拼接字符串的方法來完成每一段源代碼的生成。

1.為了源碼生成之後的美觀問題,我們需要對每一行代碼的縮進與對齊方面進行控制,所以增加了製表符「t」和換行符「n"。

2.在生成set和get方法的源碼的時候,我們按照常規習慣,會將屬性名的第一字母變為大寫,然後在屬性名前面加上set或者get,形成set與get方法的方法名。為了便於後續的使用,我們封裝了一個改變字符串首字母大小寫的方法firstChar2UpperCase(),在後面我們將對其進行分析。

3.在生成源碼的時候,我們還需要對數據庫中傳遞過來的數據類型進行轉換,使用到了一個我們自己封裝的方法databaseType2JavaType(),此方法在後面進行詳解。

3、工具類Utils中的StringUtils類

在規劃整個SORM框架的時候,在StringUtils中主要封裝字符串常用的操作。

針對上面的createFieldGetSetSRC()方法,我們提到了一個轉換字符串首字母大小寫的方法firstChar2UpperCase()。下面給出此方法的源程序:

package com.peng.sorm.utils;    /**   * 封裝了字符串常用的操作   */  public class StringUtils {      /**     * 將目標字符串首字母變為大寫     * @param str 目標字符串     * @return 首字母變為大寫的字符串     */    public static String firstChar2UpperCase(String str) {      return str.toUpperCase().substring(0,1)+str.substring(1);    }  }

tips:在上述firstChar2UpperCase()方法裏面,轉換字符串首字母大小寫的思想很簡單:首先使用toUpperCase()方法,將字符串的全部字母轉換為大寫字母,然後使用subString(0,1)截取首字母;然後再用拼接字符串的方法,將原字符串的剩餘部分拼接在首字母后面,最後得到一個僅改變首字母大小寫的字符串。

4、核心架構中的MySqlTypeConvertor類

MySqlTypeConvertor類屬於核心架構中實現了TypeConvertor接口的一個實現類,主要負責將MySql數據庫和java之間的數據類型進行相互轉化。在上面的createFieldGetSetSRC()方法中,已經提到了這一部分。

package com.peng.sorm.core;    /**   * mysql數據類型和java數據類型的轉換   */  public class MySqlTypeConvertor implements TypeConvertor {      @Override    public String databaseType2JavaType(String columnType) {      // varchar ---- >String      if("varchar".equalsIgnoreCase(columnType)||"char".equalsIgnoreCase(columnType)) {        return "String";      }else if("int".equalsIgnoreCase(columnType)          ||"tinyint".equalsIgnoreCase(columnType)          ||"smallint".equalsIgnoreCase(columnType)          ||"integer".equalsIgnoreCase(columnType)          ) {        return "Integer";      }else if("bigint".equalsIgnoreCase(columnType)) {        return "Long";      }else if("double".equalsIgnoreCase(columnType)||"float".equalsIgnoreCase(columnType)) {        return "Double";      }else if("blob".equalsIgnoreCase(columnType)) {        return "java.sql.BLob";      }else if("clob".equalsIgnoreCase(columnType)) {        return "java.sql.CLob";      }else if("date".equalsIgnoreCase(columnType)) {        return "java.sql.Date";      }else if("time".equalsIgnoreCase(columnType)) {        return "java.sql.Time";      }else if("timeStamp".equalsIgnoreCase(columnType)) {        return "java.sql.TimeStamp";      }      return null;    }      @Override    public String javaType2DatebaseType(String columnType) {      return null;    }  }

tips:在類型轉換的時候,我們僅實現TypeCOnvertor接口中的databaseType2JavaType()方法。思想很簡單,就是使用條件語句來對每一個數據庫中的數據類型進行判斷,然後再將其轉換為對應的java中的數據類型。

5、最後檢測一下生成源碼的的效果

public static void main(String[] args) {      ColumnInfo ci = new ColumnInfo("username","varchar",0);      JavaFieldGetSet jfgs = createFieldGetSetSRC(ci, new MySqlTypeConvertor());      System.out.println(jfgs.toString());  }

結果:

所得結果符合我們的預期效果,和我們自己手寫的代碼一致。