最近工作接触一个java项目,项目没有使用mybatis等这类层久层,直接用的spring内置的连接池,所以就会有很多从数据库查找结果转转成DTO的函数,查找的结果集是一个Map对象如:
List<Map<String, Object>> resultList = executeJdbcQuery(sql, paramMap);
resultList结果需要保存为对象
public class ArticleKindResponse {
private Long kindId;
private String name;
private String shortName;
private String createTime;
private Integer status;
...
}
所以代码里有很多类似这样的代码:
private ArticleKindResponse constructArticleKindResponse(Map<String, Object> map){
ArticleKindResponse kind = new ArticleKindResponse();
kind.setKindId(map.get("kind_id") == null ? null : Long.valueOf(map.get("kind_id").toString()));
kind.setName(map.get("name") == null ? null : map.get("name").toString());
kind.setShortName(map.get("short_name") == null ? null : map.get("short_name").toString());
kind.setStatus(map.get("status") == null ? null : Integer.valueOf(map.get("status").toString()));
kind.setCreateTime(map.get("create_time") == null ? null : map.get("create_time").toString());
return kind;
}
每一个DTO都有一个类似的方法,简直不能忍。所以此刻想到用反射去改造它:
改造的前提:
- DTO的命名规范采用驼峰形式,基本数据类型为装箱类型
- 数据库字段命名全为小写字体,并用下划线连接
改造如下:
protected <T> T constructObject(Map<String, Object> map, Class<T> clazz) throws DaoException {
try {
T obj = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
String key = StringUtil.toCamelUnderline(field.getName());
String type = field.getType().getName();
if (type.equals("java.lang.String")) {
String value = map.get(key) == null ? null : map.get(key).toString();
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Integer")) {
Integer value = map.get(key) == null ? null : Integer.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Long")) {
Long value = map.get(key) == null ? null : Long.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Double")) {
Double value = map.get(key) == null ? null : Double.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Float")) {
Float value = map.get(key) == null ? null : Float.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Short")) {
Short value = map.get(key) == null ? null : Short.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Byte")) {
Byte value = map.get(key) == null ? null : Byte.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Character")) {
Character value = map.get(key) == null ? null : map.get(key).toString().charAt(0);
if (value != null) field.set(obj, value);
} else if (type.equals("java.lang.Boolean")) {
Boolean value = map.get(key) == null ? null : Boolean.valueOf(map.get(key).toString());
if (value != null) field.set(obj, value);
}
}
return obj;
} catch (InstantiationException | IllegalAccessException e) {
String errorMsg = "转换对象异常";
logger.error(MessageFormattor.errorFormat(
this.getClass().getName(), "constructObject",
ExceptionType.EXCEPTION_DAO, errorMsg), e);
throw new DaoException(ExceptionType.EXCEPTION_DAO, new ErrorVO(
ErrorDescription.ERR_CD_UT_DATE_CONVERSION,
ErrorDescription.ERR_CD_UT_DATE_CONVERSION, errorMsg));
}
}
其中,得到类变量的名字后,需要装驼峰形式转为下划线形式,调用了工具类:
public static String toCamelUnderline(String str) {
char[] chars = str.toCharArray();
StringBuilder result = new StringBuilder();
for (char c : chars) {
//大写字母
if (c <= 90 && c >= 65) {
result.append("_").append((char)(c + 32));
} else {
result.append(c);
}
}
if (result.length() > 0 && result.charAt(0) == '_') {
result.deleteCharAt(0);
}
return result.toString();
}
这里转换直接简单粗暴转为字符数组去处理,其实也可以用正则表达式去匹配然后递归调用,此法也可以。
最后,把调用函数 constructArticleKindResponse(map) 改为 constructObj(map, ArticleKindResponse.class)即可
测试,大功告成。
评论列表