來源
本篇代碼抽取自一個公司的持久層框架,用來代替 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語句的效果。
代碼