来源
本篇代码抽取自一个公司的持久层框架,用来代替 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(12345678);//查询学号为12345678的学生
Student stu2 = new Student();
stu2.setName("pm");//查询学生名为pm的学生
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=12345678 and s_sex='false'
select * from student where 1=1 and s_name='pm' and s_sex='false'
select * from student where 1=1 and s_sex='false' and s_address in('青岛市','北京市')
小结
此例子是将实体类类名注解映射成数据库的表名,将实体类的字段名注解映射成数据库的字段名。从而进行解析实体类的注解,达到快速拼装SQL语句的效果。