周青的日常问题记录
项目场景
学习硅谷电商毕设项目_微服务版本,建站练手。进行到商城前端服务开发的热门商品分类展示服务 store-front-product阶段。
想实现的功能为根据类别名称(categoryName)查询出该类别下的热门商品列表(productList)。
对应数据库两张表(类别表与商品表):
有问题的Impl类下逻辑代码如下:
@Service
@Slf4j
public class ProductServiceImpl implements ProductService {
@Autowired
private CategoryClient categoryClient;
@Autowired
private ProductMapper productMapper;
/**
* 1.根据单类别名称,调用feign,访问类别服务获取类别数据
* 2.成功 继续根据类别id查询商品数据 【热门 销售量倒序 查询前7个】
* 3.封装结果
* @param categoryName
* @return
*/
@Override
public R promo(String categoryName) {
R r = categoryClient.byName(categoryName);
if(r.getCode().equals(R.FAIL_CODE)){
log.info("ProductServiceImpl业务结束,结果:{}","类别查询失败");
return r;
}
Category category = (Category) r.getData();
Integer categoryId = category.getCategoryId();
//封装查询参数
QueryWrapper<Product> proqueryWrapper = new QueryWrapper<>();
proqueryWrapper.eq("category_id",categoryId);
proqueryWrapper.orderByDesc("product_sales");
//分页
IPage<Product> page = new Page<>(1,7);
page = productMapper.selectPage(page,proqueryWrapper);
List<Product> productList = page.getRecords();
long total = page.getTotal();
log.info(String.valueOf(total));
log.info("ProductServiceImpl.promo业务结束,结果:{}",productList);
return R.ok("数据查询成功(product)",productList);
}
}
R实体类(部分)
@Data
public class R {
/**
* 通用成功状态码
*/
public static final String SUCCESS_CODE = "001";
/**
* 失败状态码
*/
public static final String FAIL_CODE = "004";
private String code;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String msg;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Object data;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Long total;
public static R ok(String msg,Object data){
return ok(msg,data,null);
}
问题描述
运行后报错如下:Java.lang.ClassCastException: java,util.LinkedHashMap cannot be cast to com,atguigu,pojo.Category
根据老师解释,通过feign网络请求将查询到的categoryId发送到product服务,json在传递到Java中Jackson默认将json转换成LInkHashMap类型。老师的解决方法是不再用自定义类Category而是用LInkHashMap类来getData,把之前的
Category category = (Category) r.getData();
Integer categoryId = category.getCategoryId();
换成
LinkedHashMap<String,Object> map = (LinkedHashMap<String, Object>) r.getData();
Integer categoryId = (Integer) map.get("categoryId");
后老师成功运行。
问题来了
问题来了
问题来了
我跟着做此改动后,虽然代码成功运行,后台没有报错,但postman输出的data中为空,没有查询到任何数据。
原因分析
经测试排查,数据库没有问题,r.getData()可以正常查询到根据categoryName所查到的category表中元素,但接下来的categoryId却取不到。
原因可能在于,使用LInkHashMap接收Data后,再对LInkHashMap类型的map用get方法,因LInkHashMap的get方法需要判断传入key的哈希值相等才能返回get结果,所以我用同样的文本“categoryId”查不到我想要的结果。
(此处感叹:学面试八股有用啊)
附源码:
public V get(Object key)
{
Node<K,V> e;
//调用核心方法getNode来获取对应值
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
static final int hash(Object key)
{
int h;
//1.如果key为null则返回0
//2.根据key的hashCode值逻辑右移16做散列处理得到哈希值
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
//传入参数:1.根据key散列计算得到的哈希值 2.key值
final Node<K,V> getNode(int hash, Object key)
{
Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
//判断表是否为空,判断key对应的链表节点是否存在
if ((tab = table) != null && (n = tab.length) > 0 && (first = tab[(n - 1) & hash]) != null)
{
//判断链表的头部元素是否是key值对应的真实value,对比项:1.hash 2.key值
if (first.hash == hash && ((k = first.key) == key || (key != null && key.equals(k))))
return first;
//判断链表下个元素是否存在,存在则继续往下走
if ((e = first.next) != null)
{
//判断是否是红黑树
if (first instanceof TreeNode)
//走红黑树逻辑,从红黑树中获取对应的value
return ((TreeNode<K,V>)first).getTreeNode(hash, key);
//遍历链表
do
{
//判断链表下个元素是否是key值对应的真实value,对比项:1.hash 2.key值
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
return e;
} while ((e = e.next) != null);
}
}
//没有找到对应value则返回null
return null;
}
解决方案
使用com.alibaba.fastjson这一工具包帮助我们进行java对象和json格式的字符串之间的相互转换,曲线救国。
- 在对应服务的pom中导入依赖
< dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
< /dependency>
- 更改impl实现类代码
将
LinkedHashMap<String,Object> map = (LinkedHashMap<String, Object>) r.getData();
Integer categoryId = (Integer) map.get("categoryId");
改为
LinkedHashMap<String,Object> map = (LinkedHashMap<String, Object>) r.getData();
//将对象转换为字符串
String jsonmap = JSON.toJSONString(map);
//将json格式字符串转换为自定义类
Category category = (Category)JSON.parseObject(jsonmap,Category.class) ;
Integer categoryId = category.getCategoryId();
- install对应的product服务包,rerun服务。
- 测试通过,前端联调正常显示数据图片。
后记
在意识到hashmap的问题导致自己查不出数据后,曾尝试过重写hashcode()方法和equal()方法,如此尝试后并没有成功。如果有朋友改hash成功的话欢迎留言讨论。
参考文章:
[1] RookieJay.关于map的细节-map.get(Object key)为null
[2] 十_亿_光_年.LinkedHashMap 不能强转为自定义的对象的解决方案
[3] 尽力漂亮. com.alibaba的fastjson简介