第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());  }

结果:

所得结果符合我们的预期效果,和我们自己手写的代码一致。