初学反射,实现数据库到对象的关系映射,简陋版!

    • 前段时间学习了java的反射机制,感觉很有用,恰逢今天在学习JDBC技术,通过JDBC从数据库中查询的数据在转成自己需要的实体对象,虽然并不难,但是会比较麻烦,而且实体较多的情况下会写大量重复性的代码,很没有效率。所以就想到了反射技术,所以就利用反射技术实现了一个非常简陋的对象关系映射。 

  • 1. 首先是实体类,一个非常简单实体(目前只支持String类型的字段),不过字段的名称要和数据库的表中定义的字段名一致!!
    • //城市实体类 public class city { //城市简称 private String short_name; //城市名称 private String city_name; //创建人名称 private String create_name; public String getShort_name() { return short_name; } public void setShort_name(String short_name) { this.short_name = short_name; } public String getCity_name() { return city_name; } public void setCity_name(String city_name) { this.city_name = city_name; } public String getCreate_name() { return create_name; } public void setCreate_name(String create_name) { this.create_name = create_name; } }
  • 2.接下来是加载JDBC驱动,因为JDBC相关的相关的API会重复的用到,就单独封装到了一个工具类。
  • public class DBConnection {
        private static Connection connection = null;
        //加载JDBC驱动并获取连接对象
        public static Connection getConnection() {
            if (connection == null) {
                synchronized (DBTest.class) {
                    if (connection == null) {
                        try {
                            com.mysql.jdbc.Driver driver = new com.mysql.jdbc.Driver();
                            connection = DriverManager.getConnection("jdbc:mysql://localhost/jeecg", "root", "chielec");
                            // connection.setAutoCommit(false);
                        } catch (SQLException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
            return connection;
        }
        //关闭操作
        public static void closeAll(Connection connection, Statement statement, ResultSet resultSet) {
            try {
                if (connection != null) {
                    connection.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (resultSet != null) {
                    resultSet.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } finally {
                try {
                    if (connection != null) {
                        connection.close();
                    }
                    if (statement != null) {
                        statement.close();
                    }
                    if (resultSet != null) {
                        resultSet.close();
                    }
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        } }
  • 3.然后就开始通过反射来实现对象的映射了
  • 在该工具类中声明了3个变量,第一个是映射实体类,第二个是与实体类对应的SQL查询语句,第三个就是字节码了。前两个变量通过构造函数传递进来,然后泛型T就确定了,即传递进来的实体类。这里必须使用泛型,因为实体类是不确定的,同时使用泛型的话就回适用更多的实体类。然后调用实体类的getClass()得到字节码。
    
  •  
    public class ORMUtil<T> {
    
        //映射实体类
        private T entity;
        //查询的Sql语句
        private String selectSql;
    
        private Class clazz;
    
    
        public ORMUtil(T entity, String selectSql) {
            this.entity = entity;
            this.selectSql = selectSql;
            loadClass();
        }
    
        protected void loadClass() {
            clazz = entity.getClass();
    

       通过clazz调用getDeclaredFields()方法获取实体类中自己定义的所有字段,得到是一个数组,便利数组,调用字段的getName()方法得到字段的名称,保存到集合中并返回。
    protected List<String> getFiled() {
        ArrayList<String> list = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();
        for (Field filter : fields) {
            String filedName = filter.getName();
            list.add(filedName);
        }
        return list;
    }
      然后开始查询数据,JDK1.5之后可以使用静态导入,调用getConnection()得到数据库连接对像之后,再调用prepareStatement()执行Sql语句,遍历得到的ResultSet
    集合。这里将每一个对象的字段 以字段的值保存到Map集合中,key对应字段,value对应字段的值,最后在将Map集合保存的List集合中,每一个Map都相当于一个对象。
  • protected List<Map<String, String>> selectData(List<String> filedNames) {
    
        ArrayList<Map<String, String>> list = new ArrayList<>();
        try {
            PreparedStatement preparedStatement = getConnection().prepareStatement(selectSql);
            ResultSet resultSet = preparedStatement.executeQuery();
            while (resultSet.next()) {
                Map<String, String> map = new Hashtable<>();
                for (String fileName : filedNames) {
                    map.put(fileName, resultSet.getString(fileName));
                }
                list.add(map);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
        }
        return list;
    }
  • 最后通过反射实体类的方法,对实体的属性进行赋值,因为之前已经得到了字段的名称和字段对应的值,并保存到了集合中。这里主要是反射实体的setXxx等方法,反射方法时,需要知道方法的名称和方法参数的字节码类型(Strin.class)。那么就拼接需要反射的方法的名称,即set+字段名,不过字段的手写字母要大写。反射之前要反射构造函数,得到该实体类的实例对象。正常情况下都是对象操作属性,而反射则是属性操作对象。
    method.invoke(t, entry.getValue());这里就是方法调用对象(自己是这样理解的哈!),第一个参数是操作的对象,第二个参数是可变数组,即方法的实际参数。
  • public List<T> getList() {
        List<T> Objects = new ArrayList<>();
        List<Map<String, String>> list = selectData(getFiled());
    
        for (Map<String, String> map : list) {
            T t = null;
            try {
                //反射是属性操作对象,所以是需要对象的。
                t = (T) clazz.newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            for (Map.Entry<String, String> entry : map.entrySet()) {
                try {
                    //这里需要对Key(也就是字段进行处理,set后的第一个字母应该大写)
                    Method method = clazz.getDeclaredMethod(getMethodName(entry.getKey()    ), String.class);
                    method.invoke(t, entry.getValue());
                } catch (NoSuchMethodException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            Objects.add(t);
        }
        return Objects;
    }
    //拼接方法名称
    protected String getMethodName(String methodeName) {
    
        return "set" + methodeName.substring(0, 1).toUpperCase() + methodeName.substring(1);
    }
  •  最最后在测试一下
    
  • }
    @Test
    public void testORMUtil() {
            ORMUtil<city> ormUtil =
                    new ORMUtil<>(new city(),
                            "select  short_name,city_name,create_name from city");
            List<city> list = ormUtil.getList();
            for (city city:list){
                System.out.println(city.getShort_name()+" "
                        +city.getCity_name()+" "+city.getCreate_name());
            }
    }
    测试结果如下:
  • 济 济宁 管理员
    汶 汶川 会员
    德 德州 管理员
    汶 汶上 会员
    ==========================================================================================
  • 第一次写博客,其中难免有考虑不周的地方,有哪里不正确的地方请大家指出,我会努力改正!!
    

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值