redis中@type导致取数据解析报错
java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
新建一个对象存入redis中,对象中会出现一个字段@type
LoginUser user = new LoginUser ()
......
redisTemplate.opsForValue().set(key, user)
存入redis中数据如下
127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"@type\":\"com.common.core.domain.model.LoginUser\",\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"params\":{\"@type\":\"java.util.HashMap\"},\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"params\":{\"@type\":\"java.util.HashMap\"},\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>
取数据时,redisTemplate.opsForValue().get(key);
如果LoginUser对象的包与存入时的包路径不一致,会报错java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to
redis缓存序列化导致存储数据没有@type
在使用redis注解将数据缓存的时候发现存储进去的数据是这样的,没有@type
127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>
之前通过set方法放进去的数据是这样的
127.0.0.1:6379> get login_tokens:5be4de32-6eb5-44a5-b212-56d93e3fc067
"{\"@type\":\"com.common.core.domain.model.LoginUser\",\"deptId\":103L,\"expireTime\":1710463649132,\"token\":\"xxxx\",\"user\":{\"admin\":true,\"createBy\":\"admin\",\"dept\":{\"deptId\":103L,\"deptName\":\"xxx",\"orderNum\":1,\"params\":{\"@type\":\"java.util.HashMap\"},\"parentId\":101L,\"status\":\"0\"},\"deptId\":103L,\"loginDate\":\"2024-03-14 14:35:56\",\"loginIp\":\"127.0.0.1\",\"nickName\":\"xxx\",\"params\":{\"@type\":\"java.util.HashMap\"},\"phonenumber\":\"15888888888\",\"sex\":\"1\",\"status\":\"0\",\"userId\":1L,\"userName\":\"admin\"},\"userId\":1L,\"username\":\"admin\"}"
127.0.0.1:6379>
原因:
是因为set方法的序列化方法和注解的序列化方法不同
解决办法:
将序列化方法更换成set方法所使用的序列化方法
下面是序列化方法
public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T> {
@SuppressWarnings("unused")
private ObjectMapper objectMapper = new ObjectMapper();
public static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;
private Class<T> clazz;
static {
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
}
public FastJson2JsonRedisSerializer(Class<T> clazz) {
super();
this.clazz = clazz;
}
@Override
public byte[] serialize(T t) throws SerializationException {
if (t == null) {
return new byte[0];
}
return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
}
@Override
public T deserialize(byte[] bytes) throws SerializationException {
if (bytes == null || bytes.length <= 0) {
return null;
}
String str = new String(bytes, DEFAULT_CHARSET);
return JSON.parseObject(str, clazz);
}
public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null");
this.objectMapper = objectMapper;
}
protected JavaType getJavaType(Class<?> clazz) {
return TypeFactory.defaultInstance().constructType(clazz);
}
}
SerializerFeature.WriteClassName这个序列化
public static String getString(Object object) {
return JSON.toJSONString(object, SerializerFeature.WriteClassName);
}
如果加了SerializerFeature.WriteClassName存进redis当中的实体类就会带@type路径地址
“@type”:“com.xxx.xxx.entity.OpenNotice”
问题解决方案:去掉@type 或者 两边@type路径存放路径一致 (包名和实体类修改为一致)
去掉@type使用 JSONObject.toJSONString(obj)来存value实体类
/**
* hashMap存值方式
*
* @param parentKey
* @param fieldKey
* @param obj
*/
public static void hashSet(String parentKey, String fieldKey, Object obj) {
try {
jedis.hset(parentKey, fieldKey, JSONObject.toJSONString(obj));
//jedis.hset(parentKey, fieldKey, JSONParser.getString(obj)); //"@type":"com.xyz.miniLegion.entity.OpenNotice"
} finally {
jedis.close();
}
}
获取hashAll数据
/**
* 获取hashGetAll
* @param parentKey
* @return
*/
public Map<String, String> hashGetAll(String parentKey) {
try (Jedis jedis = pools.getResource()) { //这种写法不需要手动close();
return jedis.hgetAll(parentKey);
}catch (Exception e) {
return null;
}
}
测试Redis转实体类`在这里插入代码片
@Test
void getSoldierAttribute() {
Map<String, String> openNoticeMap = redisPoolMgr.hashGetAll(StaticData.OpenNotice);
//第一种根据key循环
for (String key : openNoticeMap.keySet()) {
OpenNotice openNotice = JSONObject.parseObject(openNoticeMap.get(key), OpenNotice.class);
System.out.println("根据key循环:" +openNotice.getContent());
System.out.println("根据key循环:" + JSONObject.toJSONString(openNotice));
}
//第二种根据value循环
for (String values : openNoticeMap.values()) {
OpenNotice openNotice = JSONObject.parseObject(values, OpenNotice.class);
System.out.println("根据value循环:"+openNotice.getContent());
System.out.println("根据value循环:" + JSONObject.toJSONString(openNotice));
}
}