Java

用注解和反射建个表

2020-05-21  本文已影响0人  GG_lyf

前言

        在大一上学期的寒假和大一下学期的一个月时间里,学完了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.结果


上一篇 下一篇

猜你喜欢

热点阅读