16. jdbc实战-实现类Mybatis结果集解析

it2022-05-05  145

jdbc 系列文章列表, 请查看目录: 《jdbc学习笔记》

Jdbc 比较繁琐的一个操作就是解析结果集ResultSet, 在实际开发时, 通常会将对结果集的解析封装为一个工具类. 需要注意的时, jdbc查询出来的属性可能不能直接转换为java的类型, 比如说java.sql.Date, 不能直接转换为java.util.Date 或LocalDate等类型, 需要自定义转换器. 如果比较熟悉Mybatis的话, 会发现Mybatis底层也封装了大量的类型转换器.

1. 工具类源码

笔者的工具类比较简单, 只封装了三个方法:

方法签名方法描述参数说明public static LinkedHashMap<String, Object> toPropertyMap(ResultSet resultSet) throws SQLException转换单行结果集为Map结构. key为列别名, value为列值resultSet: 查询结果集 public static T toBean(ResultSet resultSet, Class clz)转换结果集为单行对象clz: 目标对象类型 resultSet: 结果集 public static List toBeans(ResultSet resultSet, Class clz) throws SQLException转换结果集为java对象集合.clz: 要转换的javaBean类 resultSet: 结果集

1.1 ResultSetUtil 源码

/** 结果集解析工具类 * @since 1.0 * @author zongf * @created 2019-07-18 */ public class ResultSetUtil { /** 转换单行结果集为Map结构. key为列别名, value为列值 * @param resultSet 查询结果集 * @return 结果集中为空时, 返回null * @since 1.0 * @author zongf * @created 2019-07-18 */ public static LinkedHashMap<String, Object> toPropertyMap(ResultSet resultSet) throws SQLException { // 如果结果集为空,则返回null if (!resultSet.next()) return null; LinkedHashMap<String, Object> cloumnMap = new LinkedHashMap<>(); // 获取结果集元信息 ResultSetMetaData metaData = resultSet.getMetaData(); // 获取每一列列名与值 for (int i = 1; i <= metaData.getColumnCount(); i++) { // 获取列别名为key String columnLabel = metaData.getColumnLabel(i); Object columnValue = resultSet.getObject(i); cloumnMap.put(columnLabel, columnValue); } return cloumnMap; } /** 转换结果集为单行对象 * @param clz 目标对象类型 * @param resultSet 结果集 * @since 1.0 * @return null * @author zongf * @created 2019-07-18 */ public static <T> T toBean(ResultSet resultSet, Class<T> clz) { try { LinkedHashMap<String, Object> propertyMap = toPropertyMap(resultSet); return ReflectUtil.newInstance(clz, propertyMap, new DateTypeConverter()); } catch (SQLException e) { throw new RuntimeException("sql 执行异常!", e); } } /** 转换结果集为java对象集合. * @param clz 要转换的javaBean类 * @param resultSet 结果集 * @return 结果集中没有数据时, 返回null * @since 1.0 * @author zongf * @created 2019-07-18 */ public static <T> List<T> toBeans(ResultSet resultSet, Class<T> clz) throws SQLException { List<T> list = new ArrayList<>(); LinkedHashMap<String, Object> propertyMap = null; // 解析结果集 while ((propertyMap = toPropertyMap(resultSet)) != null) { T t = (T) ReflectUtil.newInstance(clz, propertyMap, new DateTypeConverter()); if(t != null) list.add(t); } return list.size() > 0 ? list : null; } }

1.2 ReflectUtil 源码

这是笔者对使用到的反射技术封装的一个简单工具类.

/** 反射工具类 * @since 1.0 * @author zongf * @created 2019-07-18 */ public class ReflectUtil { /**为对象属性赋值 * @param target 目标对象 * @param property 属性名 * @param property 属性名 * @return value 属性值 * @since 1.0 * @author zongf * @created 2019-07-18 */ public static void setPropertyValue(Object target, String property, Object value) { try { PropertyDescriptor descriptor = new PropertyDescriptor(property, target.getClass()); Method writeMethod = descriptor.getWriteMethod(); writeMethod.invoke(target, value); } catch (Exception e) { throw new RuntimeException("为对象属性赋值异常!",e); } } /** 获取对象属性值 * @param target 目标对象 * @param property 属性 * @return Object 返回对象属性值 * @since 1.0 * @author zongf * @created 2019-07-18 */ public static Object getPropertyValue(Object target, String property) { try { PropertyDescriptor descriptor = new PropertyDescriptor(property, target.getClass()); Method readMethod = descriptor.getReadMethod(); return readMethod.invoke(target); } catch (Exception e) { throw new RuntimeException("获取对象属性异常!",e); } } /** 反射创建对象 * @param clz 目标对象的类型 * @return propertiesMap 目标对象的属性与值 * @since 1.0 * @author zongf * @created 2019-07-18 */ public static <T> T newInstance(Class<T> clz, HashMap<String, Object> propertiesMap, DateTypeConverter typeConverter){ // 如果属性为空, 则不进行创建, 返回null if (propertiesMap == null || propertiesMap.isEmpty()) { return null; } // 使用无参数构造方法创建对象 T t = null; try { t = clz.newInstance(); for (Map.Entry<String, Object> entry : propertiesMap.entrySet()) { // 获取对象属性与值 String property = entry.getKey(); Object value = entry.getValue(); // 获取属性描述符 PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, clz); // 获取属性类型 Class<?> propertyType = propertyDescriptor.getPropertyType(); // 使用类型转换器转换参数类型 value = typeConverter.convert(value, propertyType); // 调用set方法, 赋值 Method writeMethod = propertyDescriptor.getWriteMethod(); writeMethod.invoke(t, value); } } catch (Exception e) { throw new RuntimeException("反射创建对象失败!", e); } return t; } }

1.3 DateTypeConverter 转换器

笔者仅仅编写了一个日期类型的转换器, 在企业开发中, 可能需要用到的转换器会更多.

/** 日期类型转换器 * @since 1.0 * @author zongf * @created 2019-07-18 */ public class DateTypeConverter { /** 转换对象的类型 * @param value 值 * @param javaType java类型 * @return 转换后的类型 * @since 1.0 * @author zongf * @created 2019-07-18 */ public Object convert(Object value, Class javaType) { Object obj = value; // 如果是java 日期 if(javaType.equals(Date.class)) { java.sql.Date date = (java.sql.Date) value; obj = date.toInstant().getEpochSecond(); // 如果是java8 日期 } else if(javaType.equals(LocalDate.class)){ obj = ((java.sql.Date) value).toLocalDate(); } else { obj = value; } return obj; } }

2. 单元测试

2.1 创建javaBean

测试时, 需要创建t_user表和javabean, 笔者这边仅给出javabean的定义.

public class UserPO { private Integer id; private String name; private String password; private LocalDate birthday; // 省略setter/getter/toString 方法 }

2.2 测试用例

// 测试转换单个对象为Map 结构 @Test public void toPropertyMap() throws SQLException { String str = "select id uId, name , pwd, birthday from t_user where id = 1001"; Connection connection = DbConnUtil.getConnection(true); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(str); LinkedHashMap<String, Object> map = ResultSetUtil.toPropertyMap(resultSet); map.forEach((key, val) -> System.out.println(key + ":" + val)); } // 测试转换对象为单个bean @Test public void toBean() throws SQLException { String str = "select * from t_user where id = 1002"; Connection connection = DbConnUtil.getConnection(true); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(str); UserPO userPO = ResultSetUtil.toBean(resultSet, UserPO.class); System.out.println(userPO); } // 测试转换对象为bean列表 @Test public void toBeans() throws SQLException { String str = "select * from t_user "; Connection connection = DbConnUtil.getConnection(true); Statement statement = connection.createStatement(); ResultSet resultSet = statement.executeQuery(str); List<UserPO> userPOList = ResultSetUtil.toBeans(resultSet, UserPO.class); userPOList.forEach(System.out::println); }

最新回复(0)