1. 程式人生 > >JdbcTemplate實體映射

JdbcTemplate實體映射

ada copy pro 屬性。 限制 tolower bstr poj names

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);

JdbcTemplate實體映射