当前位置: 移动技术网 > IT编程>开发语言>Java > 手把手教你从数据库生成实体类(四)

手把手教你从数据库生成实体类(四)

2019年01月19日  | 移动技术网IT编程  | 我要评论

根据上面获取的数据开始创建java文件

终于开始要创建java文件了。

但是~在创建java文件的时候要先吧之前获取的数稍微处理一下,将sql中的格式转换为java中的格式。比如属性名称,数据类型,class名称之类的,现在开始~

将表名称转换为合适的class名称

就是首字母大写,驼峰式的命名规范。例如将user_log或者user_log转换为userlog。

我们可以这么写:

    /**
     * 类名称转换
     *
     * @param tablename
     * @return
     */
    public static string entityname(string tablename) {
        string lowercasename = tablename.tolowercase();
        stringbuilder newname = new stringbuilder();
        char[] chars = lowercasename.tochararray();
        boolean change = false;
        for (int i = 0; i < chars.length; i++) {
            char achar = chars[i];
            if (achar == '_' && !change) {
                change = true;
                continue;
            }
            //首字母大写
            if (i == 0) {
                achar = character.touppercase(achar);
            }
            if (change) {
                achar = character.touppercase(achar);
                change = false;
            }
            newname.append(achar);
        }
        return newname.tostring();
    }

这样就得到了我们需要的class的名称了。

将字段名称转换为java中的属性名称

这里就是将上一步操作的首字母大写去掉就好了,下面是代码:

    /**
     * 属性名称转换
     *
     * @param name
     * @return
     */
    public static string fieldname(string name) {
        name = name.tolowercase();
        stringbuilder newname = new stringbuilder();
        char[] chars = name.tochararray();
        boolean change = false;
        for (int i = 0; i < chars.length; i++) {
            char achar = chars[i];
            if (achar == '_' && !change) {
                change = true;
                continue;
            }
            if (change) {
                achar = character.touppercase(achar);
                change = false;
            }
            newname.append(achar);
        }
        return newname.tostring();
    }

接下来是将sql中的数据类型转换为java中的数据类型。

sql数据类型转换

这里用map做了一个映射,有自己特定要求的可以自己修改。

public class columnfieldtypemapping {

    private map<string, class> sqlfieldtypemapping = new hashmap<>();

    {
        sqlfieldtypemapping.put("varchar", string.class);
        sqlfieldtypemapping.put("char", string.class);
        sqlfieldtypemapping.put("text", string.class);
        sqlfieldtypemapping.put("mediumtext", string.class);
        sqlfieldtypemapping.put("longtext", string.class);
        sqlfieldtypemapping.put("tinytext", string.class);
        sqlfieldtypemapping.put("bit", boolean.class);

        sqlfieldtypemapping.put("int", int.class);
        sqlfieldtypemapping.put("bigint", long.class);
        sqlfieldtypemapping.put("double", double.class);
        sqlfieldtypemapping.put("tinyint", int.class);
        sqlfieldtypemapping.put("float", float.class);
        sqlfieldtypemapping.put("decimal", bigdecimal.class);

        sqlfieldtypemapping.put("int unsigned", int.class);
        sqlfieldtypemapping.put("bigint unsigned", int.class);
        sqlfieldtypemapping.put("decimal unsigned", bigdecimal.class);

        sqlfieldtypemapping.put("datetime", date.class);
        sqlfieldtypemapping.put("time", date.class);
        sqlfieldtypemapping.put("date", date.class);
        sqlfieldtypemapping.put("timestamp", date.class);
    }

    /**
     * 根据sql数据类型获取java数据类型
     *
     * @param columntype
     * @return
     */
    public class getfieldtype(string columntype) {
        class aclass = sqlfieldtypemapping.get(columntype);
        if (aclass == null) {
            return sqlfieldtypemapping.get(columntype.touppercase());
        }
        return null;
    }
}

写到这里,所有参与生成java文件的信息就已经获取完成了。

这时候我们需要把他们组装起来,用来放进freemarker中来解析并生成java文件中的内容。

组装参数

这里可能我以后用这个代码干别的事情所以我建了两个类,一个是classmodel.java,一个是entitymodel.java

entitymodel继承了classmodel。我们主要用的是entitymodel.java。下面是代码:

import java.util.*;

/**
 * 用于生成java entity文件的类
 */
public class classmodel {

    /**
     * java 中不需要引包的类型
     */
    private static list<class> baseclass = arrays.aslist(
            int.class,
            double.class,
            float.class,
            long.class,
            short.class,
            byte.class,
            char.class,
            boolean.class,
            string.class
    );

    /**
     * 类注释
     */
    private string classdoc;

    /**
     * 类名
     */
    private string classname;

    /**
     * 类 包名
     */
    private string packagename;

    /**
     * k:属性名称
     * v:属性类型
     */
    private map<string, class> fields = new hashmap<>();

    /**
     * 属性的注释
     */
    private map<string, string> fielddoc = new hashmap<>();
    ;

    private list<class> imports = new arraylist<>();

    /**
     * 添加需要导入的包
     *
     * @param importclass
     */
    public void addimport(class importclass) {
        if (baseclass.indexof(importclass) != -1) {
            return;
        }
        if (imports.indexof(importclass) == -1) {
            imports.add(importclass);
        }
    }

    /**
     * 添加属性
     *
     * @param fieldname  属性名称
     * @param fieldclass 属性类型
     */
    public void addfield(string fieldname, class fieldclass) {
        if (!fields.containskey(fieldname)) {
            fields.put(fieldname, fieldclass);
        }
    }

    /**
     * 添加属性注释
     *
     * @param fieldname 属性名称
     * @param fielddoc  属性注释
     */
    public void addfielddoc(string fieldname, string fielddoc) {
        if (!this.fielddoc.containskey(fieldname)) {
            this.fielddoc.put(fieldname, fielddoc);
        }
    }

    public list<class> getimports() {
        return imports;
    }

    public void setimports(list<class> imports) {
        this.imports = imports;
    }

    public string getclassdoc() {
        return classdoc;
    }

    public void setclassdoc(string classdoc) {
        this.classdoc = classdoc;
    }

    public string getclassname() {
        return classname;
    }

    public void setclassname(string classname) {
        this.classname = classname;
    }

    public string getpackagename() {
        return packagename;
    }

    public void setpackagename(string packagename) {
        this.packagename = packagename;
    }

    public map<string, class> getfields() {
        return fields;
    }

    public void setfields(map<string, class> fields) {
        this.fields = fields;
    }

    public map<string, string> getfielddoc() {
        return fielddoc;
    }

    public void setfielddoc(map<string, string> fielddoc) {
        this.fielddoc = fielddoc;
    }

    @override
    public string tostring() {
        final stringbuilder sb = new stringbuilder("{");
        sb.append("            \"classdoc\"=\"").append(classdoc).append('\"');
        sb.append(",             \"classname\"=\"").append(classname).append('\"');
        sb.append(",             \"packagename\"=\"").append(packagename).append('\"');
        sb.append(",             \"fields\"=").append(fields);
        sb.append(",             \"fielddoc\"=").append(fielddoc);
        sb.append(",             \"imports\"=").append(imports);
        sb.append('}');
        return sb.tostring();
    }
}
import java.util.arraylist;
import java.util.hashmap;
import java.util.list;
import java.util.map;

/**
 * 数据库映射
 */
public class entitymodel extends classmodel {

    /**
     * 数据库名称
     */
    private string tablename;

    /**
     * 数据库中的id字段名称
     */
    private list<string> idcolumnnames = new arraylist<>();

    /**
     * 类属性名对应数据库字段映射
     * key: class 属性名称
     * value:数据库字段名
     */
    private map<string, string> fieldsqlname = new hashmap<>();

    /**
     * 添加class 属性映射和 数据库 字段映射
     *
     * @param fieldname
     * @param sqlname
     */
    public void addfieldsqlname(string fieldname, string sqlname) {
        if (!fieldsqlname.containskey(fieldname)) {
            fieldsqlname.put(fieldname, sqlname);
        }
    }

    /**
     * 添加id字段名
     *
     * @param idcolumnname
     */
    public void addidcolumnname(string idcolumnname) {
        idcolumnnames.add(idcolumnname);
    }

    public string gettablename() {
        return tablename;
    }

    public void settablename(string tablename) {
        this.tablename = tablename;
    }

    public map<string, string> getfieldsqlname() {
        return fieldsqlname;
    }

    public void setfieldsqlname(map<string, string> fieldsqlname) {
        this.fieldsqlname = fieldsqlname;
    }

    public list<string> getidcolumnnames() {
        return idcolumnnames;
    }

    public void setidcolumnnames(list<string> idcolumnnames) {
        this.idcolumnnames = idcolumnnames;
    }
}

在这里将从数据库中得到的数据都组装好,就可以使用freemarker来生成java文件的内容了。下面是代码:

/**
 * 根据建表语句组装entitymodel
 *
 * @param createtablesql
 * @return
 */
entitymodel makemodelbysql(string createtablesql) {
    formatter formatter = new formatter();
    entitymodel model = new entitymodel();
    string tablecomment = sqlutils.gettablecomment(createtablesql);
    string tablename = sqlutils.gettablename(createtablesql);
    string id = sqlutils.getid(createtablesql);
    model.addidcolumnname(id);
    model.setclassname(nameconvert.entityname(tablename));
    model.settablename(tablename);
    //注释是null的时候用数据库表名作为注释
    model.setclassdoc(tablecomment == null ? tablename : tablecomment);
    list<string> line = sqlutils.getcolumnsqls(createtablesql);
    for (string oneline : line) {
        string columnname = sqlutils.getbypattern(oneline, "`(.*)`", 1);
        string comment = sqlutils.getbypattern(oneline, "comment '(.*)'", 1);
        string columntype = sqlutils.getbypattern(oneline, "`" + columnname + "` ([a-za-z]*)", 1);
        string fieldname = nameconvert.fieldname(columnname);
        class fieldclass = columnfieldtypemapping.getfieldtype(columntype);
        if (fieldclass == null) {
            formatter.format("table:%s columnname:%s sql类型:%s 没有映射类型", tablename, columnname, columntype);
            throw new unsupportedoperationexception(formatter.tostring());
        }
        model.addfield(fieldname, fieldclass);
        //字段注释是null的时候用数据库字段名作为注释
        model.addfielddoc(fieldname, comment == null ? columnname : comment);
        model.addfieldsqlname(fieldname, columnname);
        model.addimport(fieldclass);
    }
    return model;
}

这样一个我们需要的参数就组装好了。现在开始编写freemarker用的代码。

freemarker工具类

用来加载freemarker模板和处理模板中的参数。freemarkerutils.java,代码如下:

import freemarker.cache.stringtemplateloader;
import freemarker.template.configuration;
import freemarker.template.defaultobjectwrapper;
import freemarker.template.template;

import java.io.stringwriter;
import java.io.writer;
import java.util.locale;
import java.util.scanner;

public class freemarkerutils {

    /**
     * freemarker工具,
     *
     * @param subjectparams
     * @param templetpath
     * @return
     * @throws exception
     */
    public static string getjavaclass(object subjectparams, string templetpath) throws exception {
        stringtemplateloader loader = new stringtemplateloader();
        scanner scanner = new scanner(thread.currentthread().getcontextclassloader().getresourceasstream(templetpath));
        stringbuilder builder = new stringbuilder();
        while (scanner.hasnext()) {
            builder.append(scanner.nextline()).append("\n");
        }
        string name = system.currenttimemillis() + "";
        loader.puttemplate(name, builder.tostring());
        //第一步:实例化freemarker的配置类
        configuration conf = new configuration();
        conf.setobjectwrapper(new defaultobjectwrapper());
        conf.setlocale(locale.china);
        conf.setdefaultencoding("utf-8");
        conf.settemplateloader(loader);
        //处理空值为空字符串
        conf.setclassiccompatible(true);
        template template = conf.gettemplate(name);
        writer out = new stringwriter(2048);
        template.process(subjectparams, out);
        string javaclass = out.tostring();
        return javaclass;
    }
}

现在有了工具类之后,还不能立即开始生成java文件,因为还要继续设置java的package和生成文件的路径,这时候我们可以修改之前写的config.xml

修改config.xml

<xml>
    <jdbc.url></jdbc.url>
    <jdbc.username></jdbc.username>
    <jdbc.password></jdbc.password>
    <basepath>/home/hjx/work/demo/src/main/java</basepath>
    <entitypackage>top.hejiaxuan.demo.entity</entitypackage>
</xml>

这里添加了两个参数:basepathentitypackage。一个是要生成java的文件的路径,一个是java文件的包名。

然后我们再写一个写出文件的工具类fileutils.java

编写fileutils.java

import java.io.*;

public class fileutils {

    /**
     * 写入文件
     *
     * @param path    文件路径
     * @param content 文件内容
     */
    public static void write(string path, string content) {
        file file = new file(path);
        file parentfile = file.getparentfile();
        try {
            if (!parentfile.exists()) {
                parentfile.mkdirs();
            }
            if (!file.exists()) {
                file.createnewfile();
            }
            filewriter filewriter = new filewriter(file);
            filewriter.write(content);
            filewriter.close();
        } catch (filenotfoundexception e) {
            e.printstacktrace();
        } catch (ioexception e) {
            e.printstacktrace();
        }
    }
}

这样就万事具备,就差生成文件啦。下面就开始啦~~~

开始生成java文件

在生成文件前,我们还需要把basepathentitypackage从配置文件里取出来,这一步我就不写了~~

static final string dot = ".";

static final string file_type = ".java";

static final string entity_templet_path = "entitytemp.ftl";

/**
 * 用于生成一个类文件
 *
 * @param entitymodel
 * @return
 */
boolean makeoneclass(entitymodel entitymodel) {
    entitymodel.setpackagename(entitypackage);
    string filepath = basepath + "/" + entitypackage.replace(dot, "/") + "/" + entitymodel.getclassname() + file_type;
    try {
        string javaclassstring = freemarkerutils.getjavaclass(entitymodel, entity_templet_path);
        fileutils.write(filepath, javaclassstring);
        return true;
    } catch (exception e) {
        e.printstacktrace();
    }
    return false;
}

好啦~~~大功告成。

额~~~

好像少点啥~~~

模板文件没有放出来~~~

编写entitytemp.ftl

package ${packagename};

<#--导入的包-->
<#list imports as import>
import ${import.name};
</#list>

<#--类名-->
<#if classdoc?length gt 0>
/**
 * ${classdoc}
 * @author hejiaxuan
 */
</#if>
public class ${classname} {

<#--属性名称-->
<#list fields?keys as key>
    <#assign  fielddocstr = fielddoc[key]>
    <#if fielddocstr?length gt 0>
    /**${fielddocstr}*/
    </#if>
    <#if idcolumnnames?seq_contains(fieldsqlname[key])>
    </#if>
    private ${fields[key].simplename} ${key};

</#list>
<#list fields?keys as key>
    <#assign  fieldclass = fields[key].simplename>
<#--setter-->
    public void set${key?cap_first}(${fieldclass} ${key}) {
        this.${key} = ${key};
    }

<#--getter-->
    public ${fieldclass} <#if fieldclass="boolean">is<#else>get</#if>${key?cap_first}() {
        return this.${key};
    }

</#list>

    @override
    public string tostring() {
        final stringbuilder sb = new stringbuilder("[");
<#list fields?keys as key>
        sb.append("${key}:").append(${key}).append(";    ");
</#list>
        sb.append("]");
        return sb.tostring();
    }
}

最后

​ 这里面我只是贴出来了一些要用到的代码片段,没有将所有的代码全部写出来。其实写工具就是一个慢慢实现自己思路的过程,有思路的话一切都很简单。

​ 如果有人需要项目全部代码的话请到https://github.com/hjx601496320/entitymaker自行查看。

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网