fastjson对象序列化的问题

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

 

问题引入

涉及的代码也非常简单

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()方法

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类

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是一样的

Object object = JSON.parse(data);

问题解决方案

1、返回Object

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

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);
    }

}

2、调用其他方法

调用JSON.parseObject(String, Class)方法指定转换的类型

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);

        return JSON.parseObject(data, AdvancedProperty.class);
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值