使用Velocity引擎生成数据库对应实体类

2022-04-20 00:00:00 数据库 字段 模板 生成 字段名

Velocity是一种Java模版引擎技术,该项目由Apache提出。 Apache对它的定义是:一种基于Java的模板引擎,它允许任何人使用简单而强大的模板语言来引用定义在Java代码中的对象。

Velocity应用于web开发时,界面设计人员可以和java程序开发人员同步开发一个遵循MVC架构的web站点,也就是说,页面设计人员可以只关注页面的显示效果,而由java程序开发人员关注业务逻辑编码。Velocity将java代码从web页面中分离出来,这样为web站点的长期维护提供了便利,同时也为我们在JSP和PHP之外又提供了一种可选的方案。

Velocity还被用在其他地方,比如系统中用户注册或修改密码时,往往会向用户的邮箱发一封邮件,该邮件的内容可以由Velocity生成,而不是传统的字符串拼接的形式。另外,在一个新项目要开发之前,可能都会先提供实体类,用于和数据库中设计好的表对应,类似写实体类这样的重复的相似劳动,我们也可以使用Velocity解决。

我们今天就来看一下,使用Velocity生成数据库对应的实体类的过程。

项目结构图如下:

其中pojo中的类为自动生成的 

其主要流程为: 

一、准备数据库
二、通过JDBC建立程序和数据库的连接 
三、通过JDBC得到数据库中所有的表和表中的字段信息(类型、字段名) 
四、准备Velocity的vm模板,用于生成对应的文件 
五、使用Velocity,生成指定名字和字段的单个文件 
六、定义main方法,通过第三步得到的数据,根据第四步准备的vm模板,调用第五步生成单个文件的方法,将整个数据库对应的实体类生成

下面详细为详细介绍:

一、准备数据库

这里使用SQLite数据库,表结构如下:

二、通过JDBC建立程序和数据库的连接

1、准备MySql的驱动包,这里使用的是sqlite-jdbc-3.7.2.jar 
2、编写数据库连接工具类,如下:

package cn.ucai.util;


import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;


public class SQLiteDBUtils {

   /**

    * 得到对数据库的连接

    * @return

    */

   public static Connection getConnection(){

       Connection conn = null;

       try {

           Class.forName("org.sqlite.JDBC");

           conn = DriverManager.getConnection("jdbc:sqlite:C:/Users/sks/Desktop/superwechat_Database_V02-master/superwechat_v04.db");

       }catch(Exception e){

           e.printStackTrace();

       }

       return conn;

   }

   

   /**

    * 关闭所有数据库操作的相关资源

    * @param conn

    * @param ment

    * @param rs

    */

   public static void closeAll(Connection conn,PreparedStatement ps ,ResultSet rs){

       if(rs!=null){

           try {

               rs.close();

           } catch (SQLException e) {

               e.printStackTrace();

           }

       }

       if(ps!=null){

           try {

               ps.close();

           } catch (SQLException e) {

               e.printStackTrace();

           }

       }

       if(conn!=null){


           try {

               conn.close();

           } catch (SQLException e) {

               e.printStackTrace();

           }

       }

   }

}



三、通过JDBC得到数据库中所有的表和表中的字段信息(类型、字段名)

1、封装一个实体类,用于接收从数据库中读取到的全部数据信息,如下:

package cn.ucai.bean;


import java.util.Arrays;


public class Classes {

   /** 表名 **/

   private String className;

   /** 一维数组存字段个数,二维数组存每个字段的类型和名称 **/

   private String[][] strArr;

   public Classes() {

       super();

   }

   public Classes(String classNameString[][] strArr) {

       super();

       this.className = className;

       this.strArr = strArr;

   }

   public String getClassName() {

       return className;

   }

   public void setClassName(String className) {

       String result = "";

       for(int i=0;i<className.length();i++){

           if(i==0){

               result += (className.charAt(i)+"").toUpperCase();

           }else{

               result += className.charAt(i)+"";

           }

       }

       this.className = result;

   }

   public String[][] getStrArr() {

       return strArr;

   }

   public void setStrArr(String[][] strArr) {

       this.strArr = strArr;


   }

   @Override

   public String toString() {

       String toString = "";

       for(int i=0;i<strArr.length;i++){

           toString += " "+Arrays.toString(strArr[i]);

       }

       return "Classes [className=" + className + ", strArr=" +toString + "]";

   }

}



2、从数据库获取所有的表和表中的字段名和字段类型信息

/**

* 从数据库获取所有的表和表中的字段名和字段类型信息

@return

*/

public static List<Classes> getClassesData(){

   List<Classes> claList = new ArrayList<Classes>();

   // 获得数据库连接

   Connection conn = SQLiteDBUtils.getConnection();

   try {

       DatabaseMetaData databaseMataDate = conn.getMetaData();

       // 得到数据库中的所有表

       ResultSet tabs = databaseMataDate.getTables(nullnullnull,new String[] { "TABLE" });

       ResultSet rs = null;

       Statement st = null;

       while (tabs.next()) {// 遍历所有表

           Classes cla = new Classes();

           // 得到表名

           String className = tabs.getObject("TABLE_NAME").toString();

           String lastClassName =getUpString(className.substring(className.lastIndexOf("_")+1));


           if(lastClassName.equalsIgnoreCase("Sequence")){

               continue;

           }

           cla.setClassName(lastClassName);

           String sql = "select * from "+tabs.getObject("TABLE_NAME");

           st = conn.createStatement();

           rs = st.executeQuery(sql);

           // 得到所有的字段类型和字段名

           ResultSetMetaData rsmd = rs.getMetaData();

           int colCount = rsmd.getColumnCount();

           String[][] strArr = new String[colCount][3];

           for (int i = 1; i <= colCounti++) {

               // 得到对应Java数据类型的类型

               strArr[i-1][0] =  getDataType(rsmd.getColumnTypeName(i),rsmd.getColumnName(i));

               // 得到字段名

               strArr[i-1][1] =  getFieldName(rsmd.getColumnName(i));

               // 得到首字母大写的字段名

               strArr[i-1][2] =  getUpString(rsmd.getColumnName(i));

           }

           cla.setStrArr(strArr);

           

           claList.add(cla);

       }

       tabs.close();

       rs.close();

       st.close();

       conn.close();

   } catch (SQLException e) {

       e.printStackTrace();

   }

   return claList;

}


得到的表名,字段名和数据类型一般还不能直接用,这个时候我们需要转换,如将全小写的表名转为首字母大写的类名,将数据库中的数据类型转为Java中的数据类型,将数据库中的列名中的下划线去掉,下划线后面跟的字母大写等。


四、准备Velocity的vm模板,用于生成对应的文件


package cn.ucai.pojo;


import java.io.Serializable;


public class ${classNameUpCase} implements Serializable {

   private static final long serialVersionUID = 1L;

   #foreach ($attr in ${attrs})

private ${attr[0]} ${attr[1]};

   #end

public ${classNameUpCase}(){

       super();

   }

   public ${classNameUpCase}(${allargs}){

   #foreach($attr in ${attrs})

   this.${attr[1]} = ${attr[1]};

   #end

}

   

   #foreach ($attr in ${attrs})

public ${attr[0]} get${attr[2]}() {

        return this.${attr[1]};

    }

    

   public void set${attr[2]}(${attr[0]} ${attr[1]}){

       this.${attr[1]} = ${attr[1]};

   }

    

    #end

    @Override

    public String toString() {

        return "${classNameUpCase} ["

    #foreach($attr in ${attrs})    

    + "this.${attr[1]}=" + ${attr[1]}

   #end    ;

    }


}


在vm文件中,可以发现很多以 # 和$符开头的内容,这些都是Velocity的语法,在 Velocity 中所有的关键字都是以 # 开头的,而所有的变量则是以$开头,变量所代表的值,由上一步得到的数据,经由VelocityContext类提供。

除了变量外,这里用的多的就是Velocity中的循环语句,它用于循环生成重复性的内容,如getters和setters,toString中属性的拼接等。如:

#foreach ($attr in ${attrs})

public ${attr[0]} get${attr[2]}() {

    return this.${attr[1]};

}


Velocity引擎会讲attrs中的值循环赋值给attr变量,attrs的值同样来源于VelocityContext。


五、使用Velocity,生成指定名字和字段的单个文件


这里主要是Velocity的使用,详细语法请参考代码注释,如下:


/**

* 根据类名和字段信息生成实体类

@param className 类名

@param attrs 字段信息,包括字段的类型信息和字段名

*/

public static void generateClass(String className,String[][] attrs){

   // 创建Velocity引擎

   VelocityEngine ve = new VelocityEngine();

   // 初始化环境

   ve.setProperty(RuntimeConstants.RESOURCE_LOADER"classpath");

   ve.setProperty("classpath.resource.loader.class", ClasspathResourceLoader.class.getName());

   ve.init();

   // 加载模板

   Template actionTpt = ve.getTemplate("BeanTemplate.vm");

   // 创建用于携带数据的VelocityContext;

   VelocityContext ctx = new VelocityContext();

   // 设置类名到模板


   ctx.put("classNameUpCase"className);

   // 设置全参构造参数名列表到模板

   String result = "";

   for(int i=0;i<attrs.length;i++){

       result += attrs[i][0]+" "+attrs[i][1]+",";

   }

   ctx.put("allargs"result.substring(0,result.length()-1));

   // 设置attrs数组到模板

   ctx.put("attrs"attrs);

   PrintWriter pw;

   try {

       pw = new PrintWriter(newFile("src/cn/ucai/pojo/"+className+".java"));

       // 根据模板,将数据模板化之后转为Writer流。

       actionTpt.merge(ctxpw);

       pw.flush();

       pw.close();

   } catch (FileNotFoundException e) {

       e.printStackTrace();

   }

}



六、定义main方法,通过第三步得到的数据,根据第四步准备的vm模板,调用第五步生成单个文件的方法,将整个数据库对应的实体类生成


public static void main(String[] args) {

   List<Classes> list = getClassesData();

   for(Classes cal : list){

       generateClass(cal.getClassName(),cal.getStrArr());

   }

}


运行程序,可以发现,实体类已经生成到指定包中,如下(以user表为例,生成了对应的User.java类)


package cn.ucai.pojo;


import java.io.Serializable;


public class User implements Serializable {


   private static final long serialVersionUID = 1L;

   private String muserName;

   private String muserPassword;

   private String muserNick;

   private Integer muserUnreadMsgCount;

   public User(){

       super();

   }

   public User(String muserName,String muserPassword,StringmuserNick,Integer muserUnreadMsgCount){

       this.muserName = muserName;

       this.muserPassword = muserPassword;

       this.muserNick = muserNick;

       this.muserUnreadMsgCount = muserUnreadMsgCount;

   }

   

   public String getM_user_name() {

        return this.muserName;

    }

    

   public void setM_user_name(String muserName){

       this.muserName = muserName;

   }

    

    public String getM_user_password() {

        return this.muserPassword;

    }

    

   public void setM_user_password(String muserPassword){

       this.muserPassword = muserPassword;

   }

    

    public String getM_user_nick() {

        return this.muserNick;

    }

    

   public void setM_user_nick(String muserNick){


       this.muserNick = muserNick;

   }

    

    public Integer getM_user_unread_msg_count() {

        return this.muserUnreadMsgCount;

    }

    

   public void setM_user_unread_msg_count(Integer muserUnreadMsgCount){

       this.muserUnreadMsgCount = muserUnreadMsgCount;

   }

    

         @Override

    public String toString() {

        return "User ["

         + "this.muserName=" + muserName

        + "this.muserPassword=" + muserPassword

        + "this.muserNick=" + muserNick

        + "this.muserUnreadMsgCount=" + muserUnreadMsgCount

       ;

    }


}


本文章中项目源代码:https://github.com/MyCloudream/DB2POJO

参考资料:http://www.ibm.com/developerworks/cn/java/j-lo-velocity1/

来自:https://mp.weixin.qq.com/s/wbchSN2QAuUPuoXQWav5Wg

相关文章