自动生成MVC模式下的POJO类及hbm.xml文件

自动生成MVC模式下的POJO类及hbm.xml文件

一、引言

        这个想法在我上学的时候就已经产生了,但是一直没有动手实现,前两天终于忍不住了,磨刀不误砍柴工嘛。
       传统的基于MVC模式开发信息系统的流程为:数据库表属性定义-->基于此表的POJO类-->基于此表的持久化层配置文件(如Hibernate需要编写hbm.xml文件);但是,POJO类文件和hbm.xml配置文件的大小依赖于表的属性多少。如果表的属性很多,我们就会非常烦躁(你需要不停地Ctrl+C,Ctrl+V)。这种重复的机械性的劳动不仅浪费时间而且还容易出错。其实,我们只需要简单写个小程序就能帮我们自动搞定POJO和hbm.xml,毕竟我们程序猿就是干这个的。下面我们就来看看一个简单的程序实现。

二、数据库表结构定义表

       在前面的博客《数据库设计时的一张表格中,我向大家介绍了在日常工作中用到的数据库设计时的一张表格,它可以帮助我们很好的定义表属性,又很容易进行后期维护。当我们完成了这样一张表格后,也即意味着我们完成了一张数据库表的设计。                           

                                          

        程序的基本思路是:有了上面这张表,我们可以轻松地将其前三列(不包括表头)拷贝到Excel中,然后利用POI读取此Excel中的数据,再利用Java文件操作自动生成POJO类和hbm.xml配置文件。

三、程序实现

        0.引用及变量声明 

    import org.apache.poi.hssf.usermodel.HSSFWorkbook;
    import org.apache.poi.poifs.filesystem.POIFSFileSystem;
    import org.apache.poi.ss.usermodel.*;
    import java.io.*;
    import java.util.Date;

    public static String classPath = <放置生成的POJO路径>;
    public static String hbmPath = <放置生成的hbm路径>;
    public static String excelPath = "D:\\test.xls";

    public static String tableName = <数据库中对应的表名>;
    public static String[] tableAttrs = new String[50]; //属性名数组
    public static String[] tableAttrsType = new String[50]; //类型数组
    public static String[] tableAttrsNotes = new String[50]; //注释数组
    public static int length = 0; //用来存放此表中有多少属性

        1.读取Excel文件方法
    public void getTableAttr() throws Exception {
        int i = 0; //用来记录共有多少属性

        //声明一下输入流及Excel的Sheet对象
        InputStream inp = new FileInputStream(excelPath);
        HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(inp));

        Sheet sheet1 = wb.getSheetAt(0);
        for (Row row : sheet1) {
            //获取注释信息
            Cell note = row.getCell(0);
            //获取属性名称
            Cell attr = row.getCell(1);
            //获取属性对应的类型
            Cell type = row.getCell(2);

            //需要非空判断,否则会产生空指针异常
            if( (note!=null) && (attr!=null) && (type!=null) &&
                (!note.getRichStringCellValue().getString().isEmpty())&&
                (note.getRichStringCellValue().getString()!=null)) {
                tableAttrsNotes[i] = note.getRichStringCellValue().getString();
                tableAttrs[i] = attr.getRichStringCellValue().getString();
                tableAttrsType[i] = type.getRichStringCellValue().getString();

                i++;
            }
        }
        //关闭它,否则会有内存泄露
        inp.close();
        length = i; //将统计的属性赋给length
    }

         2.类型转换
         由于定义数据库表属性的类型和程序中的类型可能不完全一致,需要我们进行转换,方法如下,大家可以根据自己的需要添加需要转换的类型:
     private void convertType() {
        for(int i=0;i<tableAttrsType.length;i++){
            if (tableAttrsType[i]!=null)
                if (tableAttrsType[i].equals("NUMBER"))
                    tableAttrsType[i] = "Integer";
                else if (tableAttrsType[i].equals("DATE"))
                    tableAttrsType[i] = "Date";
                else if (tableAttrsType[i].startsWith("VARCHAR"))
                    tableAttrsType[i] = "String";
        }
     }
          3.属性的标准化处理
        由于我们输入的属性并不是我们最终想要的属性,例如serial_no是数据库中的属性名,那么在程序中,我们需要的是serialNo这个字段。因此,我们需要提前做一些标准化的处理工作。
   /**
     * 将单词首字母大写
     * @param letter
     * @return 转换后的单词
     */
    private String firstLetterUpper(String letter){
        return str.replaceFirst(str.substring(0,1),str.substring(0,1).toUpperCase());
    }

    /**
     * 将属性从下划线拆成单词链接并将除第一个以外的单词首字母大写
     * 例如:fund_id=>fundId
     * @param str
     * @return 转换后的单词
     */
    public String standardization(String str){
        String newStr = "";
        String li[] = str.toLowerCase().split("_");

        for(int i=0;i<li.length;i++){
            if(i==0)
                newStr = newStr.concat(li[i]);
            else{
                //首字母大写
                String b = firstLetterUpper(li[i]);
                newStr = newStr.concat(b);
            }
        }

        return newStr;
    }
        4.文件操作

        除了属性的标准化处理外,我们还需要文件的操作--创建和写入。方法如下:

    public boolean createFile(String filePath,String fileName) throws IOException {
        boolean result = false;
        File file = new File(filePath,fileName);
        if(file.exists()){
            if(file.isFile()) {
                result = true;
                System.out.println("文件已存在!");
            }else {
                System.out.println("对不起,该路径为目录!");
            }
        } else{
            file.createNewFile();
            result = true;
            System.out.println("文件创建成功!");
        }
        return result;
    }
    
    public void writeFile(String filePath,String fileName,String args) throws IOException {
        FileWriter fw = new FileWriter(filePath+fileName,true);
        fw.write(args);
        fw.close();
    }
        5.POJO生成方法
        终于到了POJO生成方法了,其实很简单,我们只需要写入创建的文件即可:
    public void generatePOJO(){
        try{
            //创建类文件
            String className = standardization(tableName);
            String fileName = firstLetterUpper(className) + ".java";
            createFile(classPath, fileName);

            //head information
            writeFile(classPath,fileName," import java.io.Serializable;\n "+
                "import java.util.Date;\n\n" +
                "public class "+ firstLetterUpper(className) + "implements Serializable"+
                " {\n");
 
            //循环声明此表的各个属性
            for(int i=0;i<length;i++){
                String temp = standardization(tableAttrs[i]);
                writeFile(classPath,fileName,"private "+tableAttrsType[i]+ " "+ temp + "; "+
                    "//"+tableAttrsNotes[i]+"\n");
            }
            //循环生成各个属性的Setter和Getter方法
            for(int i=0;i<length;i++){
                String tem = standardization(tableAttrs[i]);
                String temCon = "public "+tableAttrsType[i]+ " get"+firstLetterUpper(tem)+
                    "() {\n" +
                    "        return "+tem+";\n" +
                    "    }\n\n" +
                    "    public void set"+firstLetterUpper(tem)+"("+tableAttrsType[i]+ 
                    " "+tem+") {\n" +
                    "        this."+tem+" = "+tem+";\n" +
                    "    }\n";
                writeFile(classPath,fileName,temCon);
            }
            writeFile(classPath,fileName,"}\n");
        }catch(Exception e){
            System.out.print(e.toString());
        }
     }
         6.hbm.xml生成方法

        同理我们可以很容易的生成hbm.xml方法

    public void generateHBM(){
        try{
            //创建类文件
            String hbmName = standardization(tableName);
            String standHBM = firstLetterUpper(hbmName);
            String fileName = standHBM + ".hbm.xml";
            createFile(hbmPath, fileName);
 
            //head information
            writeFile(hbmPath,fileName,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<!DOCTYPE hibernate-mapping PUBLIC\n" +
                " \"-//Hibernate/Hibernate Mapping DTD//EN\"\n" +
                " \"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd\">\n" +
                "<hibernate-mapping>\n");

            //body information
            writeFile(hbmPath,fileName,"<class lazy=\"false\" name=\""+standHBM+"\" +
                table=\""+tableName.toUpperCase()+"\">\n" +"<id column=\"OBJID\" + 
                name=\"id\" type=\"java.lang.Integer\">\n"+"<param name=\"name\">" + 
                tableName.toUpperCase() + "</param>\n"  + "</generator>\n"  +
                " </id>\n");

            //循环写入各个属性的信息
            for(int i=1;i<length;i++){
                String temp = standardization(tableAttrs[i]);
                if(tableAttrsType[i].equals("Date"))
                    writeFile(hbmPath,fileName,"<property column=\""
                         +tableAttrs[i].toUpperCase()+
                         "\" name=\""+temp+"\"  type=\"java.util.Date\"/>\n");
                else
                    writeFile(hbmPath,fileName,"<property column=\""
                         +tableAttrs[i].toUpperCase()+
                         "\" name=\""+temp+"\"  type=\"java.lang."
                         +tableAttrsType[i]+"\"/>\n");
            }

            //tail information
            writeFile(hbmPath,fileName,"</class>\n" + "</hibernate-mapping>\n");
        }catch(Exception e){
             System.out.print(e.toString());
        }
    }

四、结语

        大家可以根据自己的实际需要定制这些方法,另外也可以将Excel中的每个Sheet当成一张表,然后一次性生成所有表的POJO类和hbm.xml配置文件。

POJOGenerator(POJO代码生成器 v1.3.3) 本POJO代码生成器采用Java的Swing技术编码实现,是绿色免费工具,可以自由传播。 由于本工具的内部实现较烂,所以还请反编译高手手下留情,让我留几分颜面。^_^ 由于本人只用过Oracle、DB2、MySQL、MS SQL Server这四款数据库产品,所以制作 成exe可执行文件时只添入了这四款数据库的驱动支持。如果您需要使用这款工具从 其它数据库生成POJO,那么您可以联系我(Email:CodingMouse@gmail.com), 我会添加其它数据库的驱动支持后通过电子邮件发送给您。 简单的使用说明: 1、先将压缩档解压到任意文件夹,必须保留配置文件cmsdk4j.cfg.xml和generator .cfg.xml与可执行文件POJOGenerator.exe在同一目录,否则无法运行。 2、可以预先在配置档cmsdk4j.cfg.xml中设定您的数据库服务器配置,配置档中已经 提供了默认的配置信息,您仅需在此基础上修改部分参数(如:IP地址、端口号、 用户名、密码、数据库名等),这些参数将作为生成器的预设数据库连接配置参数。 3、可以预先在配置档generator.cfg.xml中设定您的数据类型映射方案,配置档中已经 提供了MS SQL Server/MySQL/DB2和Oracle两种映射方案,当然,可能有不太完整的地方 ,您可以根据实际情况稍作修改即可。需要注意的一点是ref属性表示引用同一映射方案 的另一映射,这样您便可以简化同一映射数据类型的配置;而import属性是指定需要在 最终生成的源代码中作为类最开始的package类型导入声明部分的导入类型名称,因此, 这个名称是完整带包名的类名称,否则不能正确生成最终代码。配置档中提供的默认配 置如果不能满足你的需要,也可以自行根据实际情况进行修改。最后,需要大家注意的 一点就是由于最终生成的代码要调用包装类型的equals和hashCode方法,因此,配置的 数据类型必须是包装类型,如果用基本类型生成POJO代码是无法通过编译的。 4、所有配置档仅在工具启动初始读取一次并缓存到内存中,因此,如果您是在工具运行 时修改的配置档,请重新启动本工具以使新的配置生效。并且,所有配置档的XML结构均 不能修改,只能修改其节点间的文本值或属性值,以及添加新的标签组,否则会导致本 工具无法工作。选择“界面皮肤方案”后,默认会在当前目录生成名为skin.dat的文件, 这是一个Properties属性文件,用于保存您最后选择的皮肤名称,以便下次打开此工具 时加载您所选择的皮肤来渲染工具UI界面。 5、所有最终代码生成效果都可以在左边的代码预览区域中查看,可点击滑动箭头显示出 被隐藏的POJO代码卡片。点击“写入磁盘文件”按钮即可将POJO代码的Java源码文件写入 到指定文件夹中。POJO代码的equals方法重写完全符合《Core Java》所述规范,同时, 其中的hashCode方法重写则参考了Netbeans中JavaBean转换器的写法。为保障原有代码安 全,通常更好的做法是将最终代码生成后拷贝到您的项目对应文件夹中。最好不要直接指 向您的项目文件夹,因为本工具会直接覆盖掉指定目录中同名的文件。最终生成的代码文 件以.java为扩展名。 6、从1.3版开始生成POJO代码目录中可自动添加一个名为pojo.ntf.xml的POJO映射通 知档,其中,ID列名默认使用主键名称(若为复合主键则采用次序排首位的主键列名) ,而Oracle环境下的sequence对象名称则为“seq_表名_id”格式的默认名称,请根据 实际情况修改。该配置档用于CmSdk4j-Core框架的ORM映射,不需要则请不要勾选此项或 在生成后直接删除即可。 7、目前1.3.3版与1.3版差异不大,仅修改了POJO类名与成员变量名的大小写处理策略。 即目标数据库服务器为Oracle时,才将表名除首字母外全部小写处理成POJO类名,同理, 成员变量名也只在Oracle数据库情况下才全小写处理。其余数据库如:DB2、MySQL、 MS SQL Server则直接处理为除首字母大写外,其余全部保留原始大小写。其中,对于 表名的处理还直接去掉了空格符和下划线,并且若为Oracle数据库时,下划线亦作为首 字母大写的分隔标志,如:HRM_HUMAN_RESOURCE,最终生成POJO类名将直接去掉串中 的下划线,并以下划线作为首字母大写的起始,即:HrmHumanResource + POJO类名后缀。 同理,成员变量名的处理也是采用了相同的处理策略。最终处理效果详见生成写入到磁盘 的pojo.ntf.xml配置档。 8、此小工具一直均只写来自用,以便与自己的O/R Mapping简易版工具配套使用,目前 1.3.3这个版本已经能满足自己的需要,同时为了方便预览POJO代码生成的效果,特意添 加了语法着色功能,其着色色调搭配和关键字字典数据来源于EmEditor这款带语法着色的 纯文本编辑器,并且该色调搭配方案也被多款JS版本的语法着色器采用,色调可读性较高。 此小工具虽然GUI、功能这些都相对较弱,但自用已经足够。因此,后期可能就不再考虑 功能更新了,请见谅! 如果您有好的建议,请发送留言到作者博客:http://blog.csdn.net/CodingMouse 或发送邮件到:CodingMouse@gmail.com 本工具已经打包成exe可执行文件,便于在Window环境下运行,但仍需要你的机器上 安装至少1.6版本的jre环境(受打包工具的jre版本不兼容限制影响)。 By CodingMouse 2010年5月22日
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值