场景:
使用微服务后,商品类别服务要调用商品服务,并实现分页处理,在商品类别服务接口中解析得到并强制类型转换Map中的商品记录信息
商品类别接口如下:
// 定义一个接口接收分页类型参数,返回map(total,List<Product>)
@GetMapping("/productsByPage") // ProductDTO(List<Product>,Integer total)
public Map<String, Object> findByCategoryIdAndPage(Integer page, Integer rows, Integer categaoryId) {
log.info("当前页:{} 每页显示记录数:{} 当前类别id:{}", page, rows, categaoryId);
// 根据类别id分页查询符合当前页集合数据 List<Product>
// 根据类别id查询当前类别下总条数 total
HashMap<String, Object> map = new HashMap<>();
List<Product> products = new ArrayList<>();
products.add(new Product(1, "iphone13", 8888.88, new Date()));
products.add(new Product(2, "iphone14", 9999.88, new Date()));
products.add(new Product(3, "iphone15", 10000.88, new Date()));
int tatal = 100;
map.put("rows", products);
map.put("total", tatal);
return map;
}
Feign接口如下:
@FeignClient(value = "PRODUCT") // value: 用来书写调用服务的服务id
public interface ProductClient {
// 声明调用商品服务根据当前页,显示行数,类别id去查询所需要记录
// ProductDTO(List<Product>,Integer total)
@GetMapping("/productsByPage")
Map<String, Object> findByCategoryIdAndPage(
@RequestParam("page") Integer page,
@RequestParam("rows") Integer rows,
@RequestParam("categaoryId") Integer categaoryId);
}
调用商品服务接口:
@GetMapping("/categoryByPage")
public Map<String,Object> categoryByPage(){
log.info("cateforyByPage");
Map<String, Object> objectMap = productClient.findByCategoryIdAndPage(1, 5, 1);
return objectMap;
}
前端返回信息:
依照这个流程下来表面看是没什么问题的,但是如果说我想要在调用商品服务接口中将返回的Map中的rows进行操作,如下:
@GetMapping("/categoryByPage")
public Map<String,Object> categoryByPage(){
log.info("cateforyByPage");
Map<String, Object> objectMap = productClient.findByCategoryIdAndPage(1, 5, 1);
List<Product> rows = (List<Product>)(objectMap.get("rows"));
rows.forEach(product -> log.info("product:"+product));
return objectMap;
}
可以看到LinkedHashMap底层是没有办法帮进行强制类型转换的,因为rows底层是一个json格式数组的字符串,底层转为对象的时候不知道是哪个类型,前端能够转换为json格式数组是因为它把rows当做object去转
定义方法返回值类型为Map<String,Object>,因为value是object,就会导致map转换为json的时候它原始的product类型丢失了,所以到后面object才无法强转为product类型,原来的product类型在上一个被调用的服务中。
解决方法:
在@RestController类中,虽然我们定义的接口返回值是Map<String,Object>但是它响应给我们的是map转换为json,json就是普通的字符串,我们就把它当成一个字符串去处理,被调用的服务不变,将Feign接口和发请求的接口返回值从Map<String,Object>修改为String
// 声明调用商品服务根据当前页,显示行数,类别id去查询所需要记录
// ProductDTO(List<Product>,Integer total)
@GetMapping("/productsByPage")
String findByCategoryIdAndPage(
@RequestParam("page") Integer page,
@RequestParam("rows") Integer rows,
@RequestParam("categaoryId") Integer categaoryId);
}
通过使用fastjson将获取出来的字符串转换为对象,json的反序列化
fastjson依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
通过jsonObject解析String为JSONObject,进入JSONobject我们发现,其实现了Map接口,JSONObject本身就是一个Map
请求服务接口:
@GetMapping("/categoryByPage")
public String categoryByPage(){
log.info("cateforyByPage");
String result = productClient.findByCategoryIdAndPage(1, 5, 1);
// 自定义json反序列化 对象转为json(序列化) json转为对象(反序列化)
// 第一次反序列化,从String转换为JSONObject(Map)
JSONObject jsonObject = JSONObject.parseObject(result);
Object row = jsonObject.get("rows");
// 第二次反序列化
jsonObject.parseArray(row.toString(),Product.class).forEach(product -> log.info("product:{}",product));
return result;
}
至此转换成功!