美文网首页Java
用注解和反射建个表

用注解和反射建个表

作者: GG_lyf | 来源:发表于2020-05-21 17:43 被阅读0次

    前言

            在大一上学期的寒假和大一下学期的一个月时间里,学完了java基础的我只知道java基础中的基础,对于集合等容器也是只会用,而多线程和反射更是只知道有这东西,不会用啊.学完了mybatis和hibernate,依旧菜鸟的我发出了感叹:逆向工程真的好强大啊,只要有个库名就可以自动生成表.并且经常写crud也没意思,于是我感觉我似乎可以试试.因此我就自己写了一个简陋的建表逆向工程,这东西浪费了我4个小时.不多说,


    开搞

    用到的包


    项目结构


    1.首先要在数据库中建个库

    2.连接数据库(这里可以用连接池,也可以不用,我用的Druid连接池)

    3.DBSource用于解析配置文件并返回一个Connection

    import java.io.InputStream;
    import java.sql.Connection;
    import java.util.Properties;
    
    import javax.sql.DataSource;
    
    import com.alibaba.druid.pool.DruidDataSourceFactory;
    
    public class DBSource {
    
        public Connection getConnection(Properties pp) {
            try {
                pp = new Properties(); 
                InputStream is = ClassLoader.getSystemResourceAsStream("druid.properties");
                pp.load(is);
                DataSource createDataSource = DruidDataSourceFactory.createDataSource(pp);
                return createDataSource.getConnection();
            } catch (Exception e) {
                e.getStackTrace();
            }
            return null;
        }
    
    }
    

    4.写Table和Colume注解类

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target({ElementType.FIELD,ElementType.LOCAL_VARIABLE,ElementType.TYPE})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Table {
    
        String name() default "";//表名
    }
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.FIELD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Colume {
    
        String columeName() default "";//字段名字
        boolean isId() default false;//是否是id
        boolean isNull() default true;//是否为空
        boolean isKey()  default false;//是否是主键
        boolean isAutoIncrement() default false;//是否自增
        int howBig() default 0;//大小
    }
    

    5.写两个实体类,并将要用的注解标注上去

    import org.vector.annotation.Colume;
    import org.vector.annotation.Table;
    
    @Table(name = "mytest")
    public class MyTest {
    
        @Colume(columeName = "tid", isAutoIncrement = true, howBig = 10, isKey = true, isId = true, isNull = false)
        private int tid;
        @Colume(columeName = "tname", isAutoIncrement = false, howBig = 255, isKey = false, isId = false, isNull = true)
        private String tname;
        @Colume(columeName = "tsex", isAutoIncrement = false, howBig = 2, isKey = false, isId = false, isNull = true)
        private String tsex;
    
        public MyTest() {
            super(); 
        }
    
        public MyTest(int tid, String tname, String tsex) { 
            this.tid = tid;
            this.tname = tname;
            this.tsex = tsex;
        }
    
    /*对应的get和set方法,toString方法*/
    }
    
    import org.vector.annotation.Colume;
    import org.vector.annotation.Table;
    
    @Table(name = "test")
    public class Test {
    
        @Colume(columeName = "tid", isAutoIncrement = true, howBig = 10, isKey = true, isId = true, isNull = false)
        private int tid;
        @Colume(columeName = "tname", isAutoIncrement = false, howBig = 255, isKey = false, isId = false, isNull = true)
        private String tname;
        @Colume(columeName = "tsex", isAutoIncrement = false, howBig = 2, isKey = false, isId = false, isNull = true)
        private String tsex;
    
        public Test() {
            super(); 
        }
    
        public Test(int tid, String tname, String tsex) { 
            this.tid = tid;
            this.tname = tname;
            this.tsex = tsex;
        }
    /*对应的get和set方法,toString方法*/
    }
    

    6.写一个表的字段对应的各种属性的实体类

    public class ColumeDomain {
        private String columeName;//表名
        private boolean isAutoIncrement;//是否自增
        private int howBig;//大小
        private boolean isKey;//是否为主键
        private boolean isId;//是否为id
        private boolean isNull;//是否为空
        private String type;//数据类型
    
        public ColumeDomain() {
            super();
        }
    
        public ColumeDomain(String columeName, boolean isAutoIncrement, int howBig, boolean isKey, boolean isId,
                boolean isNull, String type) {
            this.columeName = columeName; 
            this.isAutoIncrement = isAutoIncrement;
            this.howBig = howBig;
            this.isKey = isKey;
            this.isId = isId;
            this.isNull = isNull;
            this.type = type;
        }
    /*对应的get和set方法,toString方法*/
    }
    

    7.要创建一个表,肯定要用到表头和各个字段,创建一个工具类AnnotationUtils

    7.1写一个获取表头的方法

        public static String getTableName(Class<?> clazz) {//反射获取标注注解的实体类
            Table table = clazz.getAnnotation(Table.class);//获取实体类上的注解
            if (table != null) {//如果有注解
                return table.name().toLowerCase();//获取表名并小写
            } else {
                return clazz.getSimpleName().toLowerCase();//如果没注解就获取实体类名并小写
            }
        }
    

    7.2写一个获取各个字段的方法

        public static Map<String, ColumeDomain> getFieldName(Class<?> clazz) {//返回是一个map集合
            Field[] fields = clazz.getDeclaredFields();//通过反射获取所有字段
            Map<String, ColumeDomain> list = new HashMap<String, ColumeDomain>();//键为字段名,值是封装的字段的属性类
    
            for (Field field : fields) {//遍历每一个字段
                Class<?> type = field.getType();//获取字段的类型
    
                String n_name, n_type;
                boolean n_isAutoIncrement, n_isKey, n_isId, n_isNull;
                int n_howBig;
    
                ColumeDomain cd = new ColumeDomain();//创建字段的属性类
                field.setAccessible(true);//为了防止需要更改字段的值,设置字段可更改
                String substring = String.valueOf(field)
                        .substring(String.valueOf(field).lastIndexOf("."), String.valueOf(field).length()).replace(".", "");//截取字段,让他是一个需要的字符串,不然带着数据类型很麻烦
    //          System.out.println("substring --> " +substring);
                Colume colum = field.getAnnotation(Colume.class);//获取字段上的注解
    
                //判断字段的数据类型,封装到属性类的Type字段中
                if (type == int.class || type == Integer.class) {
                    cd.setType("int");
                } else if (type == Long.class || type == long.class) {
                    cd.setType("bigint");
                } else if (type == float.class || type == Float.class) {
                    cd.setType("float");
                } else if (type == double.class || type == Double.class) {
                    cd.setType("double");
                } else if (type == String.class) {
                    cd.setType("varchar");
                } else if (type == Date.class) {
                    cd.setType("datetime");
                }
    
                //如果colum注解类的columeName没写
                if (colum.columeName() == "") {
                    n_name = field.getName();//就获取字段名
                } else {
                    n_name = colum.columeName().toLowerCase();//写了就获取columeName的小写作为字段名
                }
    
                if (String.valueOf(colum.isAutoIncrement()) == "") {
                    n_isAutoIncrement = false;
                } else {
                    n_isAutoIncrement = colum.isAutoIncrement();
                }
    
                if (colum.howBig() == 0) {
                    n_howBig = 255;
                } else {
                    n_howBig = colum.howBig();
                }
    
                if (String.valueOf(colum.isKey()) == "") {
                    n_isKey = false;
                } else {
                    n_isKey = colum.isKey();
                }
    
                if (String.valueOf(colum.isId()) == "") {
                    n_isId = false;
                } else {
                    n_isId = colum.isId();
                }
    
                if (String.valueOf(colum.isNull()) == "") {
                    n_isNull = false;
                } else {
                    n_isNull = colum.isNull();
                }
    
                //集体封装到属性类中
                cd.setAutoIncrement(n_isAutoIncrement);
                cd.setColumeName(n_name);
                cd.setHowBig(n_howBig);
                cd.setId(n_isId);
                cd.setKey(n_isKey);
                cd.setNull(n_isNull);
    
                //把每一个字段和属性类放到map集合中
                list.put(substring, cd);
            }
            return list;
        }
    

    8.写个工厂类DBSourceFactory,并在工厂类中写一个表示缓存(实际上就是一个名字)的类DBSession,

    8.1在工厂类刚创建的时候就获取数据库的连接,就是构造函数

        private Connection connection;
    
        public DBSourceFactory() {
            DBSource dbSource = new DBSource();
            Properties pp = new Properties();
            connection = dbSource.getConnection(pp);
        }
    

    8.2创建DBSession类的时候就要在他加载的时候获取数据库连接,就是构造函数

            private Connection conn;
    
            public DBSession(Connection connection) {
                this.conn = connection;
            }
    

    8.3要想使用DBSession,那么就要new这个DBSession对象,有了工厂类,并且DBSession类还在工厂类中,那么就可以用一个方法返回带数据库连接的DBSession对象,就像这样

    public class DBSourceFactory {
        private Connection connection;
    
        public DBSourceFactory() {
            DBSource dbSource = new DBSource();
            Properties pp = new Properties();
            connection = dbSource.getConnection(pp);
        }
    
        public DBSession opSession() {
            return new DBSession(connection);
        }
    
        public class DBSession {
            private Connection conn;
    
            public DBSession(Connection connection) {
                this.conn = connection;
            }
        }
    }
    

    8.4在DBSession中写用于创建表的方法create(Class<?> clazz),传入的是一个类

    8.4.1写大概的SQL语句
    String sql = "create table %s (%s)engine=innodb;";
    
    8.4.2获取表名
    String tableName = AnnotationUtils.getTableName(clazz);
    
    8.4.3获取字段集合
    Map<String, ColumeDomain> fieldName = AnnotationUtils.getFieldName(clazz);
    
    8.4.4遍历每一个字段集合
                    int i = 0;
                    String parame = "";
                    for (String str : fieldName.keySet()) {//map集合遍历
                        String key, isNull, isAutoIncrement;
                        ColumeDomain columeDomain = fieldName.get(str);//通过字段获取字段的属性类
    //                  System.out.println(str + " ---> " + columeDomain);
                        if (columeDomain.isKey()) {//如果isKey是true
                            key = "primary key";//主键
                            isAutoIncrement = "auto_increment";//自增
                        } else {//不是得话就
                            key = "";
                            isAutoIncrement = "";
                        }
                        if (!columeDomain.isNull()) {//如果isNull是false
                            isNull = "not null";
                        } else {//如果isNull是true
                            isNull = "";
                        }
                        //字段名+数据类型+大小+是否为主键+是否空+是否自增
                        parame += columeDomain.getColumeName() + " " + columeDomain.getType() + "("
                                + columeDomain.getHowBig() + ") " + key + " " + isNull + " " + isAutoIncrement;
                        if (i <= fieldName.keySet().size()) {//拼接逗号
                            parame += ",";
                        }
                        i++;
                    }
                    parame = (String) parame.subSequence(0, parame.length() - 1);//最后拼接的语句会有一个逗号,这个用于截取
                    sql = String.format(sql, tableName, parame);//将SQL语句拼接完整
                    PreparedStatement prepareStatement = conn.prepareStatement(sql);//预处理类处理
                    int executeUpdate = prepareStatement.executeUpdate();//开始执行
                    System.out.println(executeUpdate);//打印结果
    
    整个方法
            public void create(Class<?> clazz) {
                try {
                    String sql = "create table %s (%s)engine=innodb;";
                    String tableName = AnnotationUtils.getTableName(clazz);
    //              System.out.println(tableName);
                    Map<String, ColumeDomain> fieldName = AnnotationUtils.getFieldName(clazz);
                    int i = 0;
                    String parame = "";
                    for (String str : fieldName.keySet()) {//map集合遍历
                        String key, isNull, isAutoIncrement;
                        ColumeDomain columeDomain = fieldName.get(str);//通过字段获取字段的属性类
    //                  System.out.println(str + " ---> " + columeDomain);
                        if (columeDomain.isKey()) {//如果isKey是true
                            key = "primary key";//主键
                            isAutoIncrement = "auto_increment";//自增
                        } else {//不是得话就
                            key = "";
                            isAutoIncrement = "";
                        }
                        if (!columeDomain.isNull()) {//如果isNull是false
                            isNull = "not null";
                        } else {//如果isNull是true
                            isNull = "";
                        }
                        //字段名+数据类型+大小+是否为主键+是否空+是否自增
                        parame += columeDomain.getColumeName() + " " + columeDomain.getType() + "("
                                + columeDomain.getHowBig() + ") " + key + " " + isNull + " " + isAutoIncrement;
                        if (i <= fieldName.keySet().size()) {//拼接逗号
                            parame += ",";
                        }
                        i++;
                    }
                    parame = (String) parame.subSequence(0, parame.length() - 1);//最后拼接的语句会有一个逗号,这个用于截取
                    sql = String.format(sql, tableName, parame);//将SQL语句拼接完整
                    PreparedStatement prepareStatement = conn.prepareStatement(sql);//预处理类处理
                    int executeUpdate = prepareStatement.executeUpdate();//开始执行
                    System.out.println(executeUpdate);//打印结果
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    

    9.测试类

        public static void main(String[] args) {
            DBSourceFactory dbs = new DBSourceFactory();
            DBSession opSession = dbs.opSession();
            opSession.create(Test.class);
            opSession.create(MyTest.class);
        }
    

    10.结果


    相关文章

      网友评论

        本文标题:用注解和反射建个表

        本文链接:https://www.haomeiwen.com/subject/jrktahtx.html