我们将对象数据存入redis中的hash结构时,需要将实体类的对象字段转换为hash结构的字段,不论是jedis客户端提供的hset方法还是redisTemplate提供的putAll方法,都可以通过map数据结构直接将键值对存入redis的hash中,所以有必要研究一下如何将实体类转换为map对象以及将map对象转换为实体类。
可以使用json工具类实现该功能,先将java对象序列化为json字符串,再反序列化为Map对象,这里有一个问题就是要两步才能达到目的,整体性能可想而知不会太好,如果小项目可以使用这种方式实现,主要是简单。
上面的处理方式并不好,涉及到数据的多次处理,下面介绍使用java的反射技术实现java对象向Map转换,直接上代码:
public Map<String, String> buildRedisHashData(Object obj) {
SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Map<String, String> data = new HashMap<>();
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field : fields) {
field.setAccessible(true);
String name = field.getName();
Object val = null;
try {
val = field.get(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
if(val == null) {
continue;
}
String value = null;
String fieldType = field.getType().getName();
if(fieldType.equals("java.util.Date")) {
value = dateTimeFormat.format((Date) val);
} else {
value = val.toString();
}
data.put(name, value);
}
return data;
}
上面的代码展示了如何将java对象转换为map,map的键为java实体类的字段名,值为字段对应的值,这里把时间类型的数据按照格式序列化为字符串。
当从redis的hash中取出数据也是一个map,这时就需要将map对象转换为java的实体类,同样可以使用反射来实现该功能:
public <T> T redisHashToObject(Map<Object, Object> data, Class<T> clazz) {
SimpleDateFormat dateTimeFormat1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat dateTimeFormat2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
if(data == null) {
return null;
}
try {
T obj = clazz.getDeclaredConstructor().newInstance();
Field[] fields = obj.getClass().getDeclaredFields();
for(Field field : fields) {
String name = field.getName();
Object val = data.get(name);
if(val == null) {
continue;
}
int mod = field.getModifiers();
// 有final、static修饰符
if (Modifier.isStatic(mod) || Modifier.isFinal(mod)) {
continue;
}
field.setAccessible(true);
String fieldType = field.getType().getName();
String strVal = (String) val;
if(fieldType.equals("java.lang.String")) {
field.set(obj, val);
} else if(fieldType.equals("java.lang.Byte") || fieldType.equals("byte")) {
field.set(obj, Byte.valueOf(strVal));
} else if(fieldType.equals("java.lang.Integer") || fieldType.equals("int")) {
field.set(obj, Integer.valueOf(strVal));
} else if(fieldType.equals("java.lang.Double") || fieldType.equals("double")) {
field.set(obj, Double.valueOf(strVal));
} else if(fieldType.equals("java.lang.Float") || fieldType.equals("float")) {
field.set(obj, Float.valueOf(strVal));
} else if(fieldType.equals("java.lang.Long") || fieldType.equals("long")) {
field.set(obj, Long.valueOf(strVal));
} else if(fieldType.equals("java.lang.Short") || fieldType.equals("short")) {
field.set(obj, Short.valueOf(strVal));
} else if(fieldType.equals("java.lang.Boolean") || fieldType.equals("boolean")) {
field.set(obj, Boolean.valueOf(strVal));
} else if (fieldType.equals("java.util.Date")) {
if(strVal.length() == 19) {
field.set(obj, dateTimeFormat1.parse(strVal));
} else {
field.set(obj, dateTimeFormat2.parse(strVal));
}
} else if(fieldType.equals("java.sql.Timestamp")) {
if(strVal.length() == 19) {
field.set(obj, new Timestamp(dateTimeFormat1.parse(strVal).getTime()));
} else {
field.set(obj, new Timestamp(dateTimeFormat2.parse(strVal).getTime()));
}
} else {
field.set(obj, val);
}
}
return obj;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
上面转换时涉及到具体数据类型的处理,使用比较low的处理方式每个字段都判断数据类型,然后根据具体的数据类型进行强制类型转换。