利用反射机制设计Dao
来源:互联网 发布:商标设计软件生成器 编辑:程序博客网 时间:2024/06/06 03:49
本文主要介绍如何通过Java反射机制设计通用Dao,针对中间使用到的方法进行介绍,不对反射做全面的介绍。
测试方法大家可以直接拷贝去试一下,特地写成比较通用的,注意参数就好了,当然最后还是会附上完整的测试代码。
先写一个普通类:
//请将get、set方法补齐 class Person { private String name; private int age; }
通过Java字段拼接SQL语句
可能理解上有差别,我所说的字段就是Java的全部的参数,并不是属性。Java中的属性:可以理解为其属名性时根据get和set方法名得出的,当一个类中拥有这样一对方法时,我们可以说,这个类中拥有一个可读写的a属性。
获取类名和全部字段所需的方法
getSimpleName()和getDeclaredFields()方法,获取类名和全部字段,先测试一下这两个方法:
/** * 获取一个类所有字段的名称、类型、值 * * @param object * @throws IllegalArgumentException * @throws IllegalAccessException */ public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException { Class<?> clazz = object.getClass(); // 获取类名 System.out.println(clazz.getSimpleName()); // 获取所有字段 Field[] fields = clazz.getDeclaredFields(); // 获取字段的信息 for (Field field : fields) { System.out.println("++++++++++++++++++++++++"); System.out.println("name:" + field.getName()); System.out.println("type:" + field.getType()); field.setAccessible(true); System.out.println("value:" + field.get(object).toString()); } }
控制台打印结果:
Person
++++++++++++++++++++++++
name:name
type:class java.lang.String
value:小明
++++++++++++++++++++++++
name:age
type:int
value:30
结果分析:
由上面结果,我们可以想象,假设有一张Person表,然后Person表有name和age字段,然后有一条记录,name=”小明”,age=”30”,这样就基本跟Java类对应了。
也就是说:我们有这样一个Person类,然后我们的数据库有一个Person表,我们想把Person类中的属性存储到数据库中的时候,想要获取表名,只要只要getSimpleName()就好了;要获取字段值通过getDeclaredFields()也能做到,然后只要想办法把这些东西拼成SQL语句就好了。
SQL语句拼接思路
我们写Sql语句应该是这样:
INSERT INTO PERSON (name
,age
) VALUES (小明
,30
);
通过Java反射就可以这样拼出一条Sql语句:
"INSERT INTO "+clazz.getSimpleName()+" (`name`,`age`) VALUES (`"+fields[0].getName()+"`,`"+fields[1].getName()+"`)";
从Javabean拼接出Insert语句
//代码具体实现 public static void createSql(Object object) throws Exception { Class<?> clazz = object.getClass(); StringBuilder sb=new StringBuilder(120); sb.append("INSERT INTO "); // 获取类名 sb.append(clazz.getSimpleName()); // 获取全部字段 Field[] fields = clazz.getDeclaredFields(); sb.append(" ("); for (Field field : fields) { sb.append("`"); //获取字段名 sb.append(field.getName()); sb.append("`,"); } sb.replace(sb.length()-1, sb.length(),") VALUES ("); for (Field field : fields) { field.setAccessible(true); sb.append("`"); //获取字段值 sb.append(field.get(object).toString()); sb.append("`,"); } sb.replace(sb.length()-1, sb.length(), ")"); System.out.println(sb.toString()); }
控制台打印结果
INSERT INTO Person (`name`,`age`) VALUES (`小明`,`30`)
看着似乎很不错,基本可以满足我们的需求了,把增删改查都写一下基本能满足需求了。
Select查询结果封装Javabean
可能还有个疑问,那查找数据怎么存到Java属性中?只要调用:field.set(object, value)就好了,第一个参数Object类型,你要把数据存储到哪一个Java对象,就传那一个对象,第二个是就是查找到的具体数值了。
假设数据库查询结果是:new Object[] { “小东”, 50 },然后把它转成对象。
Object[] objects = new Object[] { "小东", 50 }; Person per = (Person) usingFields(person.getClass(), objects); System.out.println(per.getAge()); System.out.println(per.getName());
/** * 字段值注入的方式 * * @param clazz * @param params * @return * @throws Exception */ public static Object usingFields(Class<?> clazz, Object params[]) throws Exception { Object object = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); fields[i].set(object, params[i]); } return object; }
控制台打印结果
50
小东
通过Set、Get方法获取、注入属性值
通过Java字段拼接SQL语句,这是一个很好的思路,但是难免会有一些奇奇怪怪的需求,比如说我们的Javabean有个序列化ID,这时候getDeclaredFields()也会获取到序列化ID,而数据库肯定不会有这些字段的。
这时候可以考虑通过Set()和Get()方法,因为有这两个方法,肯定是希望其他人去调用这些方法,就比如JSP用到的EL表达式,他就是通过Get()方法查找的。
获取Javabean全部方法
getDeclaredMethods()和getMethods()
getDeclaredMethods()获取的是类自身声明的所有方法,包含public、protected和private方法;
getMethods()获取的是类的所有共有方法,这就包括自身的所有public方法,和从基类继承的、从接口实现的所有public方法。
/** * 获取全部方法 * * @param clazz */ public static void testMethod(Class<?> clazz) { // 获取参数 Method[] fields = clazz.getMethods(); for (Method method : fields) { System.out.println("==================================="); // 方法名 System.out.println(method.getName()); // 返回值类型 System.out.println(method.getReturnType()); // 获取方法所在类的 System.out.println(method.getDeclaringClass()); System.out.println("==================================="); } }
控制台打印结果
getName
class java.lang.String
class com.Person
setName
void
class com.Person
getAge
int
class com.Person
setAge
void
class com.Person
………………
由于编辑器不支持使用“====”这里就删除掉了,类的方法即使一个不写也是非常多的,这里仅作局部展示,只知道我们确实可以通过这种方式找到我们需要的方法,剩下的就是再明确定位到我们所需的就好了。
准确超找Get和Set方法
Field[] fields=person.getClass().getDeclaredFields(); for (Field field : fields) { findGetMethodByField(field, person.getClass()); findSetMethodByField(field, person.getClass()); }
/** * 查找所有Get方法 * * @param field * @param clazz * @return * @throws Exception */ public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception { String fieldName = field.getName(); // get方法名 String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); System.out.println(methodName); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (methodName.equals(method.getName())) { return method; } } return null; } /** * 查找所有Set方法 * * @param field * @param clazz * @return * @throws Exception */ public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception { String fieldName = field.getName(); // get方法名 String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); System.out.println(methodName); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (methodName.equals(method.getName())) { return method; } } return null; }
结果如下:
getName
setName
getAge
setAge
很好,这样基本就能找到了,找不到会返回null,判断一下就好。
通过Get方法获取返回值
先假设我们方法的返回值类型是”java.lang.String”,我们就可以使用Class.forName()创建一个这样的对象,然后直接调用Get方法即可,这里假设调用Get结果是str。
/** * 获取返回值 * * @throws ClassNotFoundException */ public static void testReturnType() throws ClassNotFoundException { // method.getReturnType() String str = "假设某个方法返回这个字符串"; Object object = Class.forName("java.lang.String"); object = str; System.out.println(object); }
结果控制台就输出:
假设某个方法返回这个字符串
使用method.getReturnType()获取返回值,这个实际上返回的是:class java.lang.String,所以要SubString一下,删除不必要的字符串,然后使用method.invoke(obj)调用方法,这个方法的参数为Object,指明要调用的是哪一类的这个方法。
Field[] fields = person.getClass().getDeclaredFields(); for (Field field : fields) { System.out.println(usingReturnType(field, person).toString()); }
/** * 获取返回值 * * @param field * 属性 * @param obj * 对象 * @return * @throws Exception */ public static Object usingReturnType(Field field, Object obj) throws Exception { Method method = findGetMethodByField(field, obj.getClass()); String returntype = method.getReturnType().getClass().toString(); Object object = Class.forName(returntype.substring(6)); object = method.invoke(obj); return object; }
控制台打印结果:
·
getName
小明
getAge
30
通过Set方法为Javabean设值
method.invoke(object, params[i])
第一个参数使我们要设值的对象,第二个参数是Object类型的集合,封装了method方法的参数值。
下面的简单地调用method.invoke(object, params[i])方法,param是我们要传的参数,假设数据库查询结果是:new Object[] { “小东”, 50 },然后把它转成对象。
Object[] objects = new Object[] { "小东", 50 }; Person per = (Person) usingMethods(person.getClass(), objects); System.out.println(per.getAge()); System.out.println(per.getName());
/** * Set方式注入 * * @param clazz * @param params * @return * @throws Exception */ public static Object usingMethods(Class<?> clazz, Object params[]) throws Exception { Object object = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Method method = findSetMethodByField(fields[i], clazz); method.invoke(object, params[i]); }
控制台打印结果:
setName
setAge
50
小东
到这里,我们已经讲了Sql语句的拼接,还有数据库返回结果的处理,基本可以应付一些简单的增删改查,至于复杂的查询,还要做进一步的研究。
扩展:
其实还可以通过注解来设计Dao,为Javabean设置类注解,注解指明数据库对应的表名,然后为每个属性设置字段注解,注解指明数据库中对应的字段名,然后通过注解拼接Sql语句。
源码:
import java.lang.reflect.Field;import java.lang.reflect.Method;class Person { private String name; private int age; public Person() { } public Person(String name, int age) { super(); this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }}public class Test { public static void main(String[] args) throws Exception { Person person = new Person("小明", 30); //获取字段 // testFields(person); //Sql语句拼接 // createSql(person); //获取方法 // testMethod(Person.class); //获取Get和Set方法 // Field[] fields=person.getClass().getDeclaredFields(); // for (Field field : fields) { // findGetMethodByField(field, person.getClass()); // findSetMethodByField(field, person.getClass()); // } //测试返回值 // testReturnType(); //使用返回值 // Field[] fields = person.getClass().getDeclaredFields(); // for (Field field : fields) { // System.out.println(usingReturnType(field, person).toString()); // } //Set方式注入 Object[] objects = new Object[] { "小东", 50 }; Person per = (Person) usingMethods(person.getClass(), objects); System.out.println(per.getAge()); System.out.println(per.getName()); //参数入住 // Object[] objects = new Object[] { "小东", 50 }; // Person per = (Person) usingFields(person.getClass(), objects); // System.out.println(per.getAge()); // System.out.println(per.getName()); } /** * 获取一个类所有属性的名称、类型、值 * * @param object * @throws IllegalArgumentException * @throws IllegalAccessException */ public static void testFields(Object object) throws IllegalArgumentException, IllegalAccessException { Class<?> clazz = object.getClass(); // 获取类名 System.out.println(clazz.getSimpleName()); // 获取参数 Field[] fields = clazz.getDeclaredFields(); // 获取参数内容和类型 for (Field field : fields) { System.out.println("++++++++++++++++++++++++"); System.out.println("name:" + field.getName()); System.out.println("type:" + field.getType()); field.setAccessible(true); System.out.println("value:" + field.get(object).toString()); } } public static void createSql(Object object) throws Exception { Class<?> clazz = object.getClass(); StringBuilder sb = new StringBuilder(120); sb.append("INSERT INTO "); // 获取类名 sb.append(clazz.getSimpleName()); // 获取全部属性 Field[] fields = clazz.getDeclaredFields(); sb.append(" ("); for (Field field : fields) { sb.append("`"); // 获取属性名 sb.append(field.getName()); sb.append("`,"); } sb.replace(sb.length() - 1, sb.length(), ") VALUES ("); for (Field field : fields) { field.setAccessible(true); sb.append("`"); // 获取属性值 sb.append(field.get(object).toString()); sb.append("`,"); } sb.replace(sb.length() - 1, sb.length(), ")"); System.out.println(sb.toString()); } /** * 获取全部方法 * * @param clazz */ public static void testMethod(Class<?> clazz) { // 获取参数 Method[] fields = clazz.getMethods(); for (Method method : fields) { System.out.println("==================================="); // 方法名 System.out.println(method.getName()); // 返回值类型 System.out.println(method.getReturnType()); // 获取方法所在类的 System.out.println(method.getDeclaringClass()); System.out.println("==================================="); } } /** * 获取返回值 * * @throws ClassNotFoundException */ public static void testReturnType() throws ClassNotFoundException { // method.getReturnType() String str = "假设某个方法返回这个字符串"; Object object = Class.forName("java.lang.String"); object = str; System.out.println(object); } /** * 查找所有Get方法 * * @param field * @param clazz * @return * @throws Exception */ public static Method findGetMethodByField(Field field, Class<?> clazz) throws Exception { String fieldName = field.getName(); // get方法名 String methodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); System.out.println(methodName); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (methodName.equals(method.getName())) { return method; } } return null; } /** * 查找所有Set方法 * * @param field * @param clazz * @return * @throws Exception */ public static Method findSetMethodByField(Field field, Class<?> clazz) throws Exception { String fieldName = field.getName(); // get方法名 String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1); System.out.println(methodName); Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if (methodName.equals(method.getName())) { return method; } } return null; } /** * 获取返回值 * * @param field * 属性 * @param obj * 对象 * @return * @throws Exception */ public static Object usingReturnType(Field field, Object obj) throws Exception { Method method = findGetMethodByField(field, obj.getClass()); String returntype = method.getReturnType().getClass().toString(); Object object = Class.forName(returntype.substring(6)); object = method.invoke(obj); return object; } /** * Set方式注入 * * @param clazz * @param params * @return * @throws Exception */ public static Object usingMethods(Class<?> clazz, Object params[]) throws Exception { Object object = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Method method = findSetMethodByField(fields[i], clazz); method.invoke(object, params[i]); } return object; } /** * 字段值注入的方式 * * @param clazz * @param params * @return * @throws Exception */ public static Object usingFields(Class<?> clazz, Object params[]) throws Exception { Object object = clazz.newInstance(); Field[] fields = clazz.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { fields[i].setAccessible(true); fields[i].set(object, params[i]); } return object; }}
- 利用反射机制设计Dao
- 利用泛型和反射机制抽象DAO
- 利用java的反射机制实现通用dao
- 反射机制实现DAO的泛型
- 反射机制简化Dao层开发
- 利用反射泛型编写一个通用Dao
- 利用反射泛型编写通用的Dao
- Java反射机制在DAO层的应用实例
- java反射机制编写简单万能DAO类
- Java反射机制在dao类的应用
- Android基于Java反射机制的简单ORM-Dao层
- 利用反射来设计BaseDao
- 设计模式之反射机制
- 反射(DAO层的设计)<学习随笔>
- 利用反射机制实现XML-RPC
- 利用反射机制实现XML-RPC
- 利用java反射机制进行对象操作
- 一个利用java反射机制的例子
- 25属性动画
- 学习iOS开发必看的一些资料
- Tiling (poj-2506)
- OPENGL ES 学习网站
- leetcode:3Sum问题
- 利用反射机制设计Dao
- 最近感想
- python学习之 json
- PHP垃圾收集
- 25动画的小结
- 倍增Floyd
- this指针
- C++——算法基础之最小生成树(Prim 和 Kruskal)
- 例题:四分树(UVa 297)