[04] 利用注解生成实体类对应的建表sql语句

1、实现功能

我们已经对注解有了基本的认识,知道了如何自定义注解,如何使用和最基本的处理注解。

本篇主要介绍,如何使用运行时级别的注解,配合反射来自动生成建表的sql语句。如下例:

我们有实体类Student,并添加相应的注解 @Table、@Column,最终可以获取到创建对应表的sql语句
@Table(name = "t_student") 
public class Student {

    @Column(name = "c_name")
    public String name;

    @Column(name = "c_sex")
    public String sex;

    ...
}

2、自定义注解

@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    //设置表名
    String name();
}

@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    //设置字段名
    String name();
}

3、对实体类使用注解

/**
 * 学生类
 */
@Table(name = "t_student")
public class Student {

    @Column(name = "c_name")
    public String name;

    @Column(name = "c_sex")
    public String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

4、运行时获取注解并转化

4.1 获取表名

private static String getTableName(Class<?> clazz) {
    String name = null;
    //如果有@Table注解
    if (clazz.isAnnotationPresent(Table.class)) {
        Table table = clazz.getAnnotation(Table.class);
        name = table.name();
    }
    
    return name;
}

4.2 获取字段名和类型

4.2.1 建立NameAndType类用来封装获取到的字段名和类型
public class NameAndType {
    
    String name;
    
    String type;

    public NameAndType(String name, String type) {
        this.name = name;
        this.type = type;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

4.2.2 获取字段名和类型
private static List<NameAndType> getColumns(Class<?> clazz) throws Exception {
    List<NameAndType> colums = new ArrayList<NameAndType>();
    Field[] fields = clazz.getDeclaredFields();
    if (fields != null) {
        //分析clazz中变量是否需要生成sql字段
        for (Field field : fields) {
            if (field.isAnnotationPresent(Column.class)) {
                //生成sql字段的字段名
                Column column = field.getAnnotation(Column.class);
                String name = column.name();
                //生成sql字段的字段类型
                String type;
                if (int.class.isAssignableFrom(field.getType())) {
                    type = "integer";
                }
                else if (String.class.isAssignableFrom(field.getType())) {
                    type = "text";
                }
                else {
                    throw new Exception("unsupported type");
                }
                colums.add(new NameAndType(name, type));
            }
        }
    }

    return colums;
}

注意Class类的isAssignableFrom方法可以判断两个类是不是存在父子关系。

4.3 生成建表sql

public static String createTable(Class<?> clazz) throws Exception {
    String sql = null;
    String tableName = getTableName(clazz);
    List<NameAndType> columns = getColumns(clazz);

    if (tableName != null && !tableName.equals("") && !columns.isEmpty()) {
        StringBuffer strBuffer = new StringBuffer("CREATE TABLE " + tableName + "( ");
        for (NameAndType column : columns) {
            String bean = column.getName() + " " + column.getType() + ", ";
            strBuffer.append(bean);
        }
        //删除最后多余的一个逗号
        strBuffer.deleteCharAt(strBuffer.length() - 2);
        strBuffer.append(");");
        sql = strBuffer.toString();
    }

    return sql;
}

4.4 测试和结果

public class TestAnnotation {
    public static void main(String[] args) throws Exception {
        String sql = TableAnnotationUtil.createTable(Student.class);
        System.out.println(sql);
    }
}

//结果输出
CREATE TABLE t_student( c_name text, c_sex text );

5、参考链接

附件列表

     

    posted @ 2017-09-01 11:54  Dulk  阅读(1515)  评论(0编辑  收藏  举报