今天偶然遇到一个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;@Autowiredpublic AdvancedPropertyServiceImpl(StringRedisUtils stringRedisUtils,Subject advancedPropertySubject,Observer advancedPropertyObserver) {this.stringRedisUtils = stringRedisUtils;this.advancedPropertySubject = advancedPropertySubject;this.advancedPropertyObserver = advancedPropertyObserver;}@Overridepublic 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;@Autowiredpublic 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;}@Overridepublic 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);
既然如此,不能转换类型,那就不转了呗,其实返回值的类型并不影响前端页面的数据渲染,所以把接口返回类型改为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;@Autowiredpublic AdvancedPropertyServiceImpl(StringRedisUtils stringRedisUtils,Subject advancedPropertySubject,Observer advancedPropertyObserver) {this.stringRedisUtils = stringRedisUtils;this.advancedPropertySubject = advancedPropertySubject;this.advancedPropertyObserver = advancedPropertyObserver;}@Overridepublic 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);}}