利用反射机制设计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;    }}
0 0