初入 java 註解(三)拼裝SQL語句

來源

本篇代碼抽取自一個公司的持久層框架,用來代替 Hibernate 的解決方案,核心代碼是通過註解來實現的。


需求

1、有一張學生表,字段包括學號、學生名字、性別、手機號碼、所在城市。
2、便捷地對每個字段或字段的組合條件進行檢索,並打印出SQL語句。


編碼

1、編寫 Student 類

public class Student {

    private int ID;
    private String name;
    private boolean sex;
    private String phone;
    private String address;

    //省略getter和setter
}

2、編寫 Test 類

public class Test {

    public static void main(String[] args) {

        Student stu1 = new Student();
        stu1.setID(20143788);//查詢學號爲20142203788的學生
        Student stu2 = new Student();
        stu2.setName("郭峯");//查詢學生名爲郭峯的學生
        Student stu3 = new Student();
        stu3.setAddress("青島市,煙臺市");//查詢地址爲任意其中一個的學生

        String sql1 = query(stu1);
        String sql2 = query(stu2);
        String sql3 = query(stu3);

        System.out.println(sql1);
        System.out.println(sql2);
        System.out.println(sql3);
    }

    private static String query(Student stu) {

        return null;
    }
}

3、考慮代碼怎麼樣與數據庫進行映射,利用 Student 類最合適不過,我們進行修改:

@Table("student")
public class Student {

    @Column("id")
    private int ID;

    @Column("name")
    private String name;

    @Column("sex")
    private boolean sex;

    @Column("phone")
    private String phone;

    @Column("address")
    private String address;

    //省略getter和setter
}

這裏使用到了 Table 和 Column 兩個自定義註解,要注意作用域不同:

Table

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

Column

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String value();
}

4、考慮實現測試類的 query 方法

private static String query(Object object) {
        StringBuilder sb = new StringBuilder();

        Class mClass = object.getClass();
        boolean isExist = mClass.isAnnotationPresent(Table.class);
        if (!isExist)
            return null;
        Table table = (Table) mClass.getAnnotation(Table.class);
        String tabName = table.value();
        //拼裝SQL表名
        sb.append("select * from ").append(tabName).append(" where 1=1");

        //獲取類的所有字段
        Field[] fields = mClass.getDeclaredFields();
        for (Field f : fields) {
            //下面代碼獲取字段註解
            boolean isFExist = f.isAnnotationPresent(Column.class);
            if (!isFExist) {
                continue;
            }
            Column column = f.getAnnotation(Column.class);
            String columnName = column.value();

            //下面代碼獲取字段值
            Object filedValue = null;
            try {
                //PropertyDescriptor 類表示JavaBean類通過存儲器導出一個屬性
                PropertyDescriptor pd = new PropertyDescriptor(f.getName(), mClass);
                //getReadMethod() 獲得用於讀取屬性值的方法,即getter方法
                Method method = pd.getReadMethod();
                //通過反射調用getter方法
                filedValue = method.invoke(object);
            } catch (Exception e) {
                e.printStackTrace();
            }

            //拼裝SQL條件
            if (filedValue == null || (filedValue instanceof Integer && (Integer) filedValue == 0)) {
                continue;
            }
            sb.append(" and ").append(columnName);
            if (filedValue instanceof String) {
                //包含多段
                if (((String) filedValue).contains(",")) {
                    String[] arr = ((String) filedValue).split(",");
                    sb.append(" in(");
                    for (String str : arr) {
                        sb.append("'").append(str).append("'").append(",");
                    }
                    sb.deleteCharAt(sb.length() - 1).append(")");
                } else {
                    sb.append("=").append("'").append(filedValue).append("'");
                }
            } else if (filedValue instanceof Boolean) {
                sb.append("=").append("'").append(filedValue).append("'");
            } else if (filedValue instanceof Integer) {
                sb.append("=").append(filedValue);
            }
        }//end for
        return sb.toString();
    }//end query

打印:

select * from student where 1=1 and s_id=20143788 and s_sex='false'
select * from student where 1=1 and s_name='郭峯' and s_sex='false'
select * from student where 1=1 and s_sex='false' and s_address in('青島市','煙臺市')

小結

此例子是將實體類類名註解映射成數據庫的表名,將實體類的字段名註解映射成數據庫的字段名。從而進行解析實體類的註解,達到快速拼裝SQL語句的效果。


代碼

點我

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章