JdbcTemplate实体映射

JdbcTemplate实体映射

如果你需要使用JdbcTemplate将查询的数据映射成Java POJO,那么这篇文章适合你。

一个例子入门

下面是一个将表中一行记录映射成Map的例子,也是JdbcTemplate默认提供的功能。

List<Map<String, Object>> result = jdbcTemplate.queryForList("select id, name, age from tbl");

然而,我们更希望得到的是下面这样的。

List<User> result = jdbcTemplate.queryForList("select id, name, age from tbl", User.class);

其中User中的属性与字段一一对应,还能自动将下划线转成驼峰。

开始

实现思路是通过反射将字段映射到对象对应的属性。

核心代码

public <T> List<T> queryForList(String sql, Class<T> clazz, Object... params) {
        final List<T> result = new ArrayList<>();
        jdbcTemplate.query(sql, params, rs -> {
            try {
                // 字段名称
                List<String> columnNames = new ArrayList<>();
                ResultSetMetaData meta = rs.getMetaData();
                int num = meta.getColumnCount();
                for (int i = 0; i < num; i++) {
                    columnNames.add(meta.getColumnLabel(i + 1));
                }
                // 设置值
                do {
                    T obj = clazz.getConstructor().newInstance();
                    for (int i = 0; i < num; i++) {
                        // 获取值
                        Object value = rs.getObject(i + 1);
                        // table.column形式的字段去掉前缀table.
                        String columnName = resolveColumn(columnNames.get(i));
                        // 下划线转驼峰
                        String property = CamelCaseUtils.toCamelCase(columnName);
                        // 复制值到属性,这是spring的工具类
                        BeanUtils.copyProperty(obj, property, value);
                    }
                    result.add(obj);
                } while (rs.next());
            } catch (Exception e) {
                throw new QueryException(e);
            }
        });
        if (CollectionUtils.isEmpty(result)) {
            return Collections.emptyList();
        }
        return result;
    }

注意:

  • String columnName = resolveColumn(columnNames.get(i))用来去掉字段的表前缀,比如t.id替换成id
  • String property = CamelCaseUtils.toCamelCase(columnName)用来将字段的下划线转成属性的驼峰形式,比如page_view转换成pageView
  • BeanUtils.copyProperty(obj, property, value)是用来复制值到对象的属性中,BeanUtils是spring的工具类,经常会使用到

下面是两个工具方法或类。

去掉表前缀

之所以去掉表前缀,是为了避免在SQL中使用别名,导致SQL过长。

private String resolveColumn(String column) {
    final int notExistIndex = -1;
    int index = column.indexOf(".");
    if (index == notExistIndex) {
        return column;
    }
    return column.substring(index + 1);
}

字段下划线转成属性的驼峰

当然,下划线转驼峰有很多更好的实现,这里不限制。如下是一个实现:

public final class CamelCaseUtils {

    private static final char SEPARATOR = '_';

    private CamelCaseUtils() {
    }

    public static String toCamelCase(String input) {
        if (input == null) {
            return null;
        }
        input = input.toLowerCase();
        int length = input.length();

        StringBuilder sb = new StringBuilder(length);
        boolean upperCase = false;
        for (int i = 0; i < length; i++) {
            char c = input.charAt(i);
            if (c == SEPARATOR) {
                upperCase = true;
            } else if (upperCase) {
                sb.append(Character.toUpperCase(c));
                upperCase = false;
            } else {
                sb.append(c);
            }
        }

        return sb.toString();
    }

}

使用

接下来就可以愉快的映射成POJO了:

List<User> result = queryForList("select t.id, t.name, t.age, t.mobile_phone from tbl t where t.id < ?", User.class, 100L);

如果参数比较多,还是通过数组传入:

List<User> result = queryForList("select t.id, t.name, t.age, t.mobile_phone from tbl t where t.id < ?", User.class, new Object[]{100L});

下面定义POJO:

public class User implements Serializabl {
    
    private Long id;

    private String name;

    private Integer age;

    private String mobilePhone;

    // 省略到getters、setters
}

补充

映射成一个值

在count时,我们是希望返回一个值的,接下来是将结果映射成一个值。

public <T> T queryOneColumn(String sql, Class<T> clazz, Object... params) {
    T result;
    if (ArrayUtils.isEmpty(params)) {
        result = jdbcTemplate.queryForObject(sql, clazz);
    } else {
        result = jdbcTemplate.queryForObject(sql, params, clazz);
    }
    return result;
}

使用:

long total = queryOneColumn("select count(1) from tbl", Long.class);
posted @ 2019-03-28 19:17  bener  阅读(9370)  评论(0编辑  收藏  举报