fastjson对象序列化的问题

今天偶然遇到一个fastjson将字符串反序列化为一个对象的时候的问题,就是简单的通过com.alibaba.fastjson.JSON将对象转为字符串,然后再从字符串转换为原类型的对象。

涉及的代码也非常简单

java 复制代码
package cn.edu.sgu.www.mhxysy.service.role.impl;

import cn.edu.sgu.www.mhxysy.consts.RedisKeyPrefixConst;
import cn.edu.sgu.www.mhxysy.entity.role.AdvancedProperty;
import cn.edu.sgu.www.mhxysy.observe.observer.Observer;
import cn.edu.sgu.www.mhxysy.observe.subject.Subject;
import cn.edu.sgu.www.mhxysy.redis.StringRedisUtils;
import cn.edu.sgu.www.mhxysy.service.role.AdvancedPropertyService;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class AdvancedPropertyServiceImpl implements AdvancedPropertyService {

    private final StringRedisUtils stringRedisUtils;
    private final Subject advancedPropertySubject;
    private final Observer advancedPropertyObserver;

    @Autowired
    public AdvancedPropertyServiceImpl(
            StringRedisUtils stringRedisUtils,
            Subject advancedPropertySubject,
            Observer advancedPropertyObserver) {
        this.stringRedisUtils = stringRedisUtils;
        this.advancedPropertySubject = advancedPropertySubject;
        this.advancedPropertyObserver = advancedPropertyObserver;
    }

    @Override
    public AdvancedProperty selectByRoleId(String roleId) {
        String key = RedisKeyPrefixConst.PREFIX_ADVANCED_PROPERTY + roleId;

        // 没有命中缓存
        if (!stringRedisUtils.hasKey(key)) {
            advancedPropertySubject.addObserver(advancedPropertyObserver);
            advancedPropertySubject.notice(roleId);
        }

        String data = stringRedisUtils.get(key);
        Object object = JSON.parse(data);

        return (AdvancedProperty) object;
    }

}

这里应用了观察者模式,如果查询没有命中缓存,就会主动触发主题的通知方法notice(),最后会调用具体观察者的update()方法

java 复制代码
package cn.edu.sgu.www.mhxysy.observe.observer;

import cn.edu.sgu.www.mhxysy.consts.RedisKeyPrefixConst;
import cn.edu.sgu.www.mhxysy.dto.xingyin.XingyinAttributeDTO;
import cn.edu.sgu.www.mhxysy.entity.equipment.Equipment;
import cn.edu.sgu.www.mhxysy.entity.equipment.EquipmentTexiao;
import cn.edu.sgu.www.mhxysy.entity.role.AdvancedProperty;
import cn.edu.sgu.www.mhxysy.entity.xingyin.Xingyin;
import cn.edu.sgu.www.mhxysy.enums.WearStatus;
import cn.edu.sgu.www.mhxysy.mapper.baoshi.BaoshiMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentMapper;
import cn.edu.sgu.www.mhxysy.mapper.equipment.EquipmentTexiaoMapper;
import cn.edu.sgu.www.mhxysy.mapper.role.AdvancedPropertyMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinAttributeMapper;
import cn.edu.sgu.www.mhxysy.mapper.xingyin.XingyinMapper;
import cn.edu.sgu.www.mhxysy.redis.StringRedisUtils;
import cn.edu.sgu.www.mhxysy.vo.AttributeVO;
import cn.edu.sgu.www.mhxysy.vo.baoshi.BaoshiXiangqianVO;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 具体观察者-角色高级属性观察者
 * @author heyunlin
 * @version 1.0
 */
@Component
public class AdvancedPropertyObserver implements Observer {

    private final BaoshiMapper baoshiMapper;
    private final XingyinMapper xingyinMapper;
    private final EquipmentMapper equipmentMapper;
    private final StringRedisUtils stringRedisUtils;
    private final EquipmentTexiaoMapper equipmentTexiaoMapper;
    private final XingyinAttributeMapper xingyinAttributeMapper;
    private final AdvancedPropertyMapper advancedPropertyMapper;

    @Autowired
    public AdvancedPropertyObserver(
            BaoshiMapper baoshiMapper,
            XingyinMapper xingyinMapper,
            EquipmentMapper equipmentMapper,
            StringRedisUtils stringRedisUtils,
            EquipmentTexiaoMapper equipmentTexiaoMapper,
            XingyinAttributeMapper xingyinAttributeMapper,
            AdvancedPropertyMapper advancedPropertyMapper) {
        this.baoshiMapper = baoshiMapper;
        this.xingyinMapper = xingyinMapper;
        this.equipmentMapper = equipmentMapper;
        this.stringRedisUtils = stringRedisUtils;
        this.equipmentTexiaoMapper = equipmentTexiaoMapper;
        this.xingyinAttributeMapper = xingyinAttributeMapper;
        this.advancedPropertyMapper = advancedPropertyMapper;
    }

    @Override
    public void update(Object message) {
        String roleId = (String) message;
        AdvancedProperty advancedProperty = advancedPropertyMapper.selectByRoleId(roleId);

        advancedProperty.setRoleId(roleId);

        /*
         * 物理暴击
         */
        AtomicInteger wlbj = new AtomicInteger(0);
        /*
         * 物理抗暴
         */
        AtomicInteger wlkb = new AtomicInteger(0);
        /*
         * 法术暴击
         */
        AtomicInteger fsbj = new AtomicInteger(0);
        /*
         * 法术抗暴
         */
        AtomicInteger fskb = new AtomicInteger(0);
        /*
         * 忽视物防
         */
        AtomicInteger hswf = new AtomicInteger(0);
        /*
         * 忽视法防
         */
        AtomicInteger hsff = new AtomicInteger(0);
        /*
         * 封印命中
         */
        AtomicInteger fymz = new AtomicInteger(0);
        /*
         * 抵抗封印
         */
        AtomicInteger dkfy = new AtomicInteger(advancedProperty.getDkfy());

        // 星印附加属性
        /*
         * 物暴伤害
         */
        AtomicInteger wbsh = new AtomicInteger(0);
        /*
         * 法暴伤害
         */
        AtomicInteger fbsh = new AtomicInteger(0);
        /*
         * 物理抵抗
         */
        AtomicInteger wldk = new AtomicInteger(0);
        /*
         * 法术抵抗
         */
        AtomicInteger fsdk = new AtomicInteger(0);
        /*
         * 回复强度
         */
        AtomicInteger hfqd = new AtomicInteger(0);

        // todo 查询高级属性并赋值
        // 查询角色穿戴的装备
        QueryWrapper<Equipment> wrapper = new QueryWrapper<>();

        wrapper.eq("role_id", roleId);
        wrapper.eq("wear_status", WearStatus.YCD.getValue());

        List<Equipment> list = equipmentMapper.selectList(wrapper);

        if(!list.isEmpty()) {
            // 装备特效增加的属性
            for (Equipment equipment : list) {
                EquipmentTexiao texiao = equipmentTexiaoMapper.selectById(equipment.getTexiaoId());

                java.lang.String name = texiao.getName();

                switch (name) {
                    case "物理暴击+1%":
                        wlbj.addAndGet(1);
                        break;
                    case "物理抗暴+2%":
                        wlkb.addAndGet(2);
                        break;
                    case "法术暴击+1%":
                        fsbj.addAndGet(1);
                        break;
                    case "法术抗暴+2%":
                        fsbj.addAndGet(2);
                        break;
                    case "封印命中+1%":
                        fymz.addAndGet(10);
                        break;
                    case "抵抗封印+1%":
                        dkfy.addAndGet(10);
                        break;
                    case "忽视物防+2%":
                        hswf.addAndGet(2);
                        break;
                    case "忽视法防+2%":
                        hsff.addAndGet(2);
                        break;
                    default:
                        break;
                }

                // 查询角色装备上镶嵌的宝石(红纹石:封印命中、神秘石:抵抗封印)
                List<BaoshiXiangqianVO> attributes = baoshiMapper.selectAttributes(equipment.getId());

                for (BaoshiXiangqianVO attribute : attributes) {
                    if ("抵抗封印".equals(attribute.getPropertyName())) {
                        dkfy.addAndGet(attribute.getGrade() * attribute.getPropertyValue());
                    } else if ("封印命中".equals(attribute.getPropertyName())) {
                        fymz.addAndGet(attribute.getGrade() * attribute.getPropertyValue());
                    }
                }
            }
        }

        // 查询角色穿戴的星印
        Map<java.lang.String, Object> map = new HashMap<>();

        map.put("role_id", roleId);
        map.put("wear_state", WearStatus.YCD.getValue());

        List<Xingyin> xingyinList = xingyinMapper.selectByMap(map);

        if (!xingyinList.isEmpty()) {
            // 获取星印的属性
            XingyinAttributeDTO xingyinAttributeDTO = new XingyinAttributeDTO();

            for (Xingyin xingyin : xingyinList) {
                xingyinAttributeDTO.setXingyinId(xingyin.getId());

                List<AttributeVO> attributes = xingyinAttributeMapper.selectAttributes(xingyinAttributeDTO);

                for (AttributeVO attribute : attributes) {
                    if ("气血回复效果".equals(attribute.getPropertyName())) {
                        hfqd.addAndGet(attribute.getPropertyValue());
                    } else if ("物理抵抗".equals(attribute.getPropertyName())) {
                        wldk.addAndGet(attribute.getPropertyValue());
                    } else if ("法术抵抗".equals(attribute.getPropertyName())) {
                        fsdk.addAndGet(attribute.getPropertyValue());
                    } else if ("封印命中".equals(attribute.getPropertyName())) {
                        fymz.addAndGet(attribute.getPropertyValue());
                    } else if ("抵抗封印".equals(attribute.getPropertyName())) {
                        dkfy.addAndGet(attribute.getPropertyValue());
                    } else if ("法术暴击伤害".equals(attribute.getPropertyName())) {
                        fbsh.addAndGet(attribute.getPropertyValue());
                    } else if ("物理暴击伤害".equals(attribute.getPropertyName())) {
                        wbsh.addAndGet(attribute.getPropertyValue());
                    }
                }
            }
        }

        advancedProperty.setWlbj(wlbj.get() + "%");
        advancedProperty.setWlkb(wlkb.get() + "%");
        advancedProperty.setFsbj(fsbj.get()  + "%");
        advancedProperty.setFskb(fskb.get()  + "%");
        advancedProperty.setHswf(hswf.get() + "%");
        advancedProperty.setHsff(hsff.get() + "%");
        advancedProperty.setFymz(fymz.get());
        advancedProperty.setDkfy(dkfy.get());
        advancedProperty.setWbsh(wbsh.get());
        advancedProperty.setFbsh(fbsh.get());
        advancedProperty.setWldk(wldk.get());
        advancedProperty.setFsdk(fsdk.get());
        advancedProperty.setHfqd(hfqd.get());

        // 保存到redis中
        String key = RedisKeyPrefixConst.PREFIX_ADVANCED_PROPERTY + roleId;

        stringRedisUtils.set(key, JSON.toJSONString(advancedProperty));
    }

}

而AdvancedProperty是一个数据库entity类

java 复制代码
package cn.edu.sgu.www.mhxysy.entity.role;

import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import java.io.Serializable;

/**
 * 角色高级属性表
 * @author heyunlin
 * @version 1.0
 */
@Data
@TableName("advanced_property")
public class AdvancedProperty implements Serializable {
    private static final long serialVersionUID = 18L;

    /**
     * 角色ID
     */
    private String roleId;

    /**
     * 物理暴击
     */
    private String wlbj;

    /**
     * 物理抗暴
     */
    private String wlkb;

    /**
     * 法术暴击
     */
    private String fsbj;

    /**
     * 法术抗暴
     */
    private String fskb;

    /**
     * 忽视物防
     */
    private String hswf;

    /**
     * 忽视法防
     */
    private String hsff;

    /**
     * 封印命中
     */
    private Integer fymz;

    /**
     * 抵抗封印
     */
    private Integer dkfy;

    // 星印附加属性

    /**
     * 物暴伤害
     */
    private Integer wbsh;

    /**
     * 法暴伤害
     */
    private Integer fbsh;

    /**
     * 物理抵抗
     */
    private Integer wldk;

    /**
     * 法术抵抗
     */
    private Integer fsdk;

    /**
     * 回复强度
     */
    private Integer hfqd;
}

然后在查询数据的时候发生了类型转换异常。

最后通过debug发现其实通过下面代码解析得到的对象的结构和AdvancedProperty是一样的

java 复制代码
Object object = JSON.parse(data);

既然如此,不能转换类型,那就不转了呗,其实返回值的类型并不影响前端页面的数据渲染,所以把接口返回类型改为Object,问题完美解决~

java 复制代码
package cn.edu.sgu.www.mhxysy.service.role.impl;

import cn.edu.sgu.www.mhxysy.consts.RedisKeyPrefixConst;
import cn.edu.sgu.www.mhxysy.observe.observer.Observer;
import cn.edu.sgu.www.mhxysy.observe.subject.Subject;
import cn.edu.sgu.www.mhxysy.redis.StringRedisUtils;
import cn.edu.sgu.www.mhxysy.service.role.AdvancedPropertyService;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @author heyunlin
 * @version 1.0
 */
@Service
public class AdvancedPropertyServiceImpl implements AdvancedPropertyService {

    private final StringRedisUtils stringRedisUtils;
    private final Subject advancedPropertySubject;
    private final Observer advancedPropertyObserver;

    @Autowired
    public AdvancedPropertyServiceImpl(
            StringRedisUtils stringRedisUtils,
            Subject advancedPropertySubject,
            Observer advancedPropertyObserver) {
        this.stringRedisUtils = stringRedisUtils;
        this.advancedPropertySubject = advancedPropertySubject;
        this.advancedPropertyObserver = advancedPropertyObserver;
    }

    @Override
    public Object selectByRoleId(String roleId) {
        String key = RedisKeyPrefixConst.PREFIX_ADVANCED_PROPERTY + roleId;

        // 没有命中缓存
        if (!stringRedisUtils.hasKey(key)) {
            advancedPropertySubject.addObserver(advancedPropertyObserver);
            advancedPropertySubject.notice(roleId);
        }

        String data = stringRedisUtils.get(key);

        return JSON.parse(data);
    }

}
相关推荐
fangzhanpeng1686 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心8 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552714 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552714 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝16 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552716 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552716 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u01030552719 天前
Java实用类应用精讲
人工智能·1024程序员节
u01030552719 天前
Java I/O核心操作实战
人工智能·1024程序员节
u01030552720 天前
ArrayList操作详解与实战应用
人工智能·1024程序员节