解決RestTemplate反序列化嵌套對象的問題
RestTemplate反序列化嵌套對象
假設某個接口返回的數(shù)據(jù)如下格式
{ "msg" : "ok", "code" : 0, "data" : { "id" : 1, "tasks" : [ { "id" : 300, "nodeId" : 801, "status" : 3, "actionName" : "pick", "wcsProcessName" : "rgv" }, { "id" : 301, "nodeId" : 720, "status" : 3, "actionName" : "move", "wcsProcessName" : "rgv" }, { "id" : 302, "nodeId" : 720, "status" : 3, "actionName" : "checker", "wcsProcessName" : "checker" }, { "id" : 303, "nodeId" : 801, "status" : 3, "actionName" : "checker", "wcsProcessName" : "checker" } ], "status" : 3 } }
仿寫一個測試接口,用于返回這種格式的數(shù)據(jù)
@PostMapping("/aiot/task/info") public R queryTask(@RequestBody Map map) { Integer taskId = (Integer) map.get("taskId"); Map res = new HashMap(); res.put("id", taskId); res.put("tasks", Arrays.asList( new TaskProcess(300, 801, 3, "pick", "rgv"), new TaskProcess(301, 720, 3, "move", "rgv"), new TaskProcess(302, 720, 3, "checker", "checker"), new TaskProcess(303, 801, 3, "checker", "checker") )); res.put("status", 3); return R.ok(res); }
客戶端的代碼如下
@Test public void test() { HashMap<String, Integer> map = new HashMap<>(); map.put("taskId", 1); ResponseEntity<WcsR> wcsRResponseEntity = restTemplate.postForEntity("http://localhost:8081/aiot/task/info", map, WcsR.class); WcsR wcsR = wcsRResponseEntity.getBody(); }
方案一
一般情況下,我們會創(chuàng)建一個與服務端一致的通用值返回對象。
@Data public class WcsR { private String msg; private Integer code; private Object data; }
data的類型無法確定。
在客戶端不知道類型的情況下,我們看下data會被解析成什么
@Test public void test() { HashMap<String, Integer> map = new HashMap<>(); map.put("taskId", 1); ResponseEntity<WcsR> wcsRResponseEntity = restTemplate.postForEntity("http://localhost:8081/aiot/task/info", map, WcsR.class); WcsR wcsR = wcsRResponseEntity.getBody(); System.out.println(wcsR.getData().getClass().getName()); }
運行結果
看后臺的代碼我們可以知道,data是一個對象,里面有三個變量,id(整型),tasks(對象數(shù)組),status(整型)。
下面嘗試獲取這些成員變量
@Test public void test() { HashMap<String, Integer> map = new HashMap<>(); map.put("taskId", 1); ResponseEntity<WcsR> wcsRResponseEntity = restTemplate.postForEntity("http://localhost:8081/aiot/task/info", map, WcsR.class); WcsR wcsR = wcsRResponseEntity.getBody(); System.out.println(wcsR.getData().getClass().getName()); LinkedHashMap dataMap = (LinkedHashMap) wcsR.getData(); System.out.println("id: " + dataMap.get("id").getClass().getName()); System.out.println("tasks: " + dataMap.get("tasks").getClass().getName()); System.out.println("status: " + dataMap.get("status").getClass().getName()); }
結果
可以看到,數(shù)組被解析成了Arraylist, 基本類型被解析成對應的包裝類型。
數(shù)組里面還是個對象,還會繼續(xù)幫我們解析嗎?測試代碼如下
@Test public void test() { HashMap<String, Integer> map = new HashMap<>(); map.put("taskId", 1); ResponseEntity<WcsR> wcsRResponseEntity = restTemplate.postForEntity("http://localhost:8081/aiot/task/info", map, WcsR.class); WcsR wcsR = wcsRResponseEntity.getBody(); LinkedHashMap dataMap = (LinkedHashMap) wcsR.getData(); // System.out.println("id: " + dataMap.get("id").getClass().getName()); // System.out.println("tasks: " + dataMap.get("tasks").getClass().getName()); // System.out.println("status: " + dataMap.get("status").getClass().getName()); ArrayList tasks = (ArrayList) dataMap.get("tasks"); System.out.println(tasks.get(0).getClass().getName()); }
結果
即使再次嵌套,還是對象還是被解析成了LinkedHashMap。
可以得到結論,在沒有提供對象類型的情況下,RestTemplate默認情況下是這么幫我們解析的:
所有的對象都解析LinkedHashMap, 數(shù)組解析為ArrayList,基本類型解析為Integer(以及其他的包裝類)。
方案二
為什么說是在“沒有提供對象類型的情況”?
這個例子中,最外層WcsR是我們自己提供的對象,假設我們提供所有的嵌套對象,
則可以定義以下對象用于接收返回值
最外層對象
@Data public class WcsR { private String msg; private Integer code; // private Object data; private TaskDetail tasks; }
第二層對象
@Data public class TaskDetail { private Integer id; private List<TaskProcess>tasks; private Integer status; }
第三層對象
@Data public class TaskProcess { private Integer id; private Integer nodeId; private Integer status; private String actionName; private String wcsProcessName; }
測試類
@Test public void test() { HashMap<String, Integer> map = new HashMap<>(); map.put("taskId", 1); ResponseEntity<WcsR> wcsRResponseEntity = restTemplate.postForEntity("http://localhost:8081/aiot/task/info", map, WcsR.class); WcsR wcsR = wcsRResponseEntity.getBody(); System.out.println(wcsR.getData()); System.out.println(wcsR.getData().getId()); System.out.println(wcsR.getData().getTasks()); System.out.println(wcsR.getData().getStatus()); System.out.println(wcsR.getData().getTasks().get(0)); }
測試結果
這種方法也是可以的。
總結
可以看出,反序列化的方案與SpringMvc的HttpMessageConvert有點類似,如果你提供了對象,則會按照對象的結構反序列化。如果沒有提供變量,則會轉化成map、List等結構。
如果接口比較少、字段比較多,可以用第二種方案。
如果接口比較多,字段比較少,并且字段數(shù)量都比較少時,為了避免定義過多的無用類,可以用第一種方案。
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Springboot Websocket Stomp 消息訂閱推送
本文主要介紹了Springboot Websocket Stomp 消息訂閱推送,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-07-07解決springcloud 配置gateway 出現(xiàn)錯誤的問題
今天給大家分享springcloud 配置gateway 出現(xiàn)錯誤的問題,其實解決方法很簡單,只需要降低springcloud版本,改成Hoxton.SR5就好了,再次改成Hoxton.SR12,也不報錯了,下面給大家展示下,感興趣的朋友一起看看吧2021-11-11