- 前段时间学习了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()); } }
测试结果如下: -
济 济宁 管理员 汶 汶川 会员 德 德州 管理员 汶 汶上 会员
========================================================================================== -
第一次写博客,其中难免有考虑不周的地方,有哪里不正确的地方请大家指出,我会努力改正!!
初学反射,实现数据库到对象的关系映射,简陋版!
最新推荐文章于 2021-02-09 16:26:08 发布