概述

redis缓存简单对象很容易,但对于复杂对象,如果想和简单对象一样,直接将复杂对象转成JSON字符串,那很容易出现cannot be cast to java.XXX.XXX,也就是ClassCastException类型转换异常,或者是该复杂对象从redis中取出后,直接通过含有@RestController注解的Controller返回给前端,那么前端接收后会出现大量反斜杠。

这一问题在开发WHITE’S时,就时常出现,看到网上也没有什么很好的解决办法,所以我写一下自己的解决办法。

例如:使用mybatis-plus的分页对象IPage时,IPage内部有一个List集合对象Records,Records封装的是一个个的分页文章对象PaginationDto。

IPage<PaginationDto> pageData = new Page<>();
List<PaginationDto> records = pageData.getRecords();

ClassCastException类型转换异常原因

将上述pageData直接缓存到redis中,然后从redis中获取数据,得出的pageData字符串再强制转换回IPage类型,就会出现cannot be cast to java.XXX.XXX,因为存在多级嵌套对象。

            redisTemplate.opsForValue().set("pageData", JSONUtil.toJsonStr(pageData));
            Object data = redisTemplate.opsForValue().get("pageData");
            pageData = (IPage<PaginationDto>) data;//报错代码

前端接收pageData现大量反斜杠原因

将上述pageData直接缓存到redis中,然后从redis中获取数据后不做强转,直接返回这个对象,例如:

  	    redisTemplate.opsForValue().set("pageData", JSONUtil.toJsonStr(pageData));
            Object data = redisTemplate.opsForValue().get("pageData");
            return data;

注意,JSONUtil.toJsonStr(pageData)代表pageData对象第一次被转义成字符串对象,由于@RestController包含@ResponseBody注解,会经过第二次转义,也就是pageData被第二次转义,那么pageData字符串对象内部如果有双引号“""”这种歧义的标识,那么会被转义成反斜杠"\",所以前端接收pageData字符串对象时会出现大量反斜杠。

这种问题的解决方式,可以从前端入手,前端将反斜杠去掉(因为后端pageData是不会出现反斜杠,后端的pageData只经过一次转义),但具体操作我没有试过,网上有一些解答,但成功与否就不得而知了。

毕竟作为后端,还是以后端解决问题为主,下面来说明后端的解决方式。

对象拆分解决redis存储复杂对象问题

由于redis存储简单对象可以正常强转,那么照这个思路,只要将复杂对象转变为简单对象存储、将简单对象重新封装成复杂对象即可。

我选用了hash类型存储简单对象,因为key-的数据格式方便我的分页操作(但是hash会出现顺序问题,本人自己排了序,可以选用list)。

//拆分保存方法saveByRedis(pageData,"all_deleted_0");
    public void saveByRedis(IPage<PaginationDto> pageData, String redisHash){
        //保存的key-value集合
        Map<Object, Object> result = new HashMap<>();
	//pageData对象中拆分文章对象
        List<PaginationDto> paginationDtoList = pageData.getRecords();
        for (PaginationDto paginationDto:paginationDtoList
        ) {
            //key为博客id,value为PaginationDto对象
            result.put(paginationDto.getId().toString(),paginationDto);
        }
        //将博客对象存入redis
        redisTemplate.opsForHash().putAll(redisHash,result);
        ...
    }

//封装回复杂对象方法getByRedis
  public IPage<PaginationDto> getByRedis(IPage<PaginationDto> pageData,Map<Object, Object> value){
        //重新封装博客数据进行分页的list集合
        List<PaginationDto> returnList = new ArrayList<>();
        //遍历集合,value是从redis中key=all_deleted_0对应的拆分对象map
        Set<Object> keySet = value.keySet();
        System.out.println(keySet.toString()+"+++++++++++++++++++++");
        for (Object key:keySet
        ) {
            System.out.println(key.toString()+"-------------------------------");
	    //强制转换简单对象
            PaginationDto o = (PaginationDto) value.get(key);
            //重新封装回List<PaginationDto>
            returnList.add(o);
        }
	...
    }

通过saveByRedis方法,拆分出PaginationDto文章分页对象,将它们存入redis,获取时,用getByRedis方法从redis缓存中取出对应的PaginationDto对象,然后封装回List集合,最后再将List封装回pageData对象即可(这里步骤省略)。

如果大家还有什么好的解决办法可以互相分享一下!

欢迎踩一踩我的博客~
WHITE’S

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐