今天偶然遇到一个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 wrapper = new QueryWrapper<>();
wrapper.eq("role_id", roleId);
wrapper.eq("wear_status", WearStatus.YCD.getValue());
List 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 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 map = new HashMap<>();
map.put("role_id", roleId);
map.put("wear_state", WearStatus.YCD.getValue());
List xingyinList = xingyinMapper.selectByMap(map);
if (!xingyinList.isEmpty()) {
// 获取星印的属性
XingyinAttributeDTO xingyinAttributeDTO = new XingyinAttributeDTO();
for (Xingyin xingyin : xingyinList) {
xingyinAttributeDTO.setXingyinId(xingyin.getId());
List 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;
@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);
}
}