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替換成idString property = CamelCaseUtils.toCamelCase(columnName)用來將字段的下划線轉成屬性的駝峰形式,比如page_view轉換成pageViewBeanUtils.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);
