java反射查询数据库_java反射与注解结合使用(根据传入对象输出查询sql)
我们在项目开发中有很多地方使用到了注解,关于注解的定义与创建小伙伴可以参考我的文章《java注解》。有任何问题的小伙伴们可以在评论区指出哦,欢迎各位大佬指出问题。
今天我要说的是使用注解与反射结合使用,来使我们代码根据优雅,更加高大上(咳,装逼神器啊)。
注解使用@interface 来定义,辣么我们自定义的注解,该使用获取到并且指明该注解的作用呢?java提供了反射机制,通过类的类类型我们可以根据自己需要老操作该类。有管反射的知识,可以参考我的上两章博客。好了,废话不多说,我们上代码:
需求:创建一个与数据库表对应的实体类,通过使用注解的方式,来生成该实体类的查询sql语句。
1.创建Table类注解,用于标明该类对应数据库的表名称
importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)public @interfaceTable {
String value();
}
2.创建Column字段注解,用于标明该类中属性与数据库表字段的映射
importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)public @interfaceColumn {
String value();
}
3.创建实体类,并使用注解Table、Column
/*** 数据库 user表,对应表字段为 userid/username/age/addredd*/@Table("user")public classUser {
@Column("userid")privateString userid;
@Column("username")privateString username;
@Column("age")private intage;
@Column("sl")private doublesl;
@Column("address")privateString address;//添加一个不是数据库的字段: 用于测试
privateString noField;public doublegetSl() {returnsl;
}public void setSl(doublesl) {this.sl =sl;
}publicString getNoField() {returnnoField;
}public voidsetNoField(String noField) {this.noField =noField;
}publicString getUserid() {returnuserid;
}public voidsetUserid(String userid) {this.userid =userid;
}publicString getUsername() {returnusername;
}public voidsetUsername(String username) {this.username =username;
}public intgetAge() {returnage;
}public void setAge(intage) {this.age =age;
}publicString getAddress() {returnaddress;
}public voidsetAddress(String address) {this.address =address;
}
}
4.创建工具类,根据传入该对象,来生成对应的查询sql
importjava.lang.annotation.Annotation;importjava.lang.reflect.Field;importjava.lang.reflect.Method;importjava.util.Objects;/*** 注解*/
public classAnnotationUtil {/*** 根据传入的对象 来生成query sql
*
*@paramobject
*@return
*/
public static String getSqlByAnnotation(Object object) throwsException {//使用StringBuilder 线程安全
StringBuilder sb = newStringBuilder();//检查参数是否为空
Objects.requireNonNull(object, "该对象不能为空!");//1.通过反射获取该对象的类类型
Class c =object.getClass();//2.获取该对象的 类注解: 标明表名
boolean table_flag = c.isAnnotationPresent(Table.class);if (!table_flag) {throw newNullPointerException();
}
Table table= (Table) c.getDeclaredAnnotation(Table.class);
sb.append("SELECT * FROM ").append(table.value()).append(" WHERE 1 = 1");//3.获取该对象的 字段注解:显示查询字段
Field[] fields =c.getDeclaredFields();booleanfield_flag;
Column column;
String field_name;
Method menthod;
Object val;for(Field field : fields) {//首先得拿到字段名称:通过字段上的注解标明该指定是数据库表对应的字段
field_flag = field.isAnnotationPresent(Column.class);if (!field_flag) {continue;
}
column= field.getDeclaredAnnotation(Column.class);//其次得拿到字段值 : 通过反射调用类的getXxxx方法
field_name =field.getName();
menthod= c.getDeclaredMethod("get" + Character.toUpperCase(field_name.charAt(0)) + field_name.substring(1));
val=menthod.invoke(object);//判断该字段是否为空,不为空,才进行append//这里要注意:有些属性不赋值时候,java会自动生成默认值,如Double默认为0.0//还有其他类型,小伙伴们可以自行测试
if (!Objects.isNull(val)) {if((val instanceof Double) && (double) val == 0.0){continue;
}
sb.append(" AND ").append(column.value()).append(" = ");
sb.append(val);
}
}returnsb.toString();
}public static voidmain(String[] args) {
User user= newUser();
user.setUserid("0001");
user.setAge(23);//用于测试没有带Column注解的字段
user.setNoField("field");try{
System.out.println(AnnotationUtil.getSqlByAnnotation(user));
}catch(Exception e) {
e.printStackTrace();
}
}
}