SpringBoot系列(九):解析前端請求“無限嵌套層級的列表數(shù)據(jù)”
作者:
修羅debug
版權(quán)聲明:本文為博主原創(chuàng)文章,遵循 CC 4.0 by-sa 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接和本聲明。
摘要:本文我們將分享介紹后端如何解析快速、高效地解析前端某些奇葩請求中的某些奇葩數(shù)據(jù),“無限嵌套的層級列表數(shù)據(jù)”便是其中的一種,在本文我們將介紹如何奇妙地利用“遞歸”算法層級遍歷并獲取相應(yīng)的層級列表數(shù)據(jù),并將其封裝成對象,最終將其更新至數(shù)據(jù)庫表中。
內(nèi)容:正常情況下,后端接口對于前端請求傳遞過來的數(shù)據(jù)一般都是了然于胸的,從而在后端接口解析期間,也就知道了前端傳遞的數(shù)據(jù)對應(yīng)的字段的含義,最終也就能“胸有成竹”般的正常解析完。
但有些時候,也存在著一些奇葩情況,如下圖所示的“菜單請求傳遞過來的層級列表數(shù)據(jù)”:
如果,前端傳遞過來的只有 id、parentId、name三個字段,那么直接采用某個類實例直接接受即可(這應(yīng)該沒啥難度)!
但是現(xiàn)在多了一個sons,sons里面也是一堆實體,每個實體也包含id、parentId、name三個字段 加一個 sons 列表字段,以此類推下去,即所謂的“無限層級嵌套列表數(shù)據(jù)”!
此時,如果你采用傳統(tǒng) for 或者 while循環(huán)遍歷sons進(jìn)行處理,那是行不通的,不行的話,各位小伙伴可以試試!
為啥不行呢:因為你壓根不知道它嵌套了多少層級,而且每個層級里面本身還要再去處理id、parentId、name這樣的“父實體”信息,該實體信息下可能還有sons嵌套層級列表數(shù)據(jù)(簡直“瘋掉”?。?/span>
明人不說暗話,其實,這種數(shù)據(jù)案例就是一種典型的“漢諾塔”遞歸實例。下面,我們采用“遞歸”的思想來實現(xiàn)這種功能續(xù)期吧
首先是建立一個請求方法用于接收前端請求中的數(shù)據(jù),該請求方法位于BaseController中,如下所示:
@Autowired
private MenuService menuService;
@RequestMapping(value = "/menu",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
public BaseResponse menu(@RequestBody MenuDto menuDto){
BaseResponse response=new BaseResponse(StatusCode.Success);
try {
menuService.manageMenu(menuDto);
}catch (Exception e){
response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
}
return response;
}
其中,MenuDto類代碼如下所示:
@Data
public class MenuDto implements Serializable{
private Integer id;
private Integer parentId;
private String name;
private List<MenuDto> sons;
}
其中,MenuService的manageMenu方法的核心實現(xiàn)邏輯如下所示:
@Service
public class MenuService {
private static final Logger log= LoggerFactory.getLogger(MenuService.class);
public void manageMenu(MenuDto menuDto) throws Exception{
log.info("接收到前端菜單層級列表樹:{}",menuDto);
List<MenuEntity> resList= Lists.newLinkedList();
circleMenu(menuDto,resList);
log.info("處理結(jié)果:{}",resList);
for (MenuEntity entity:resList){
log.info("遍歷可以準(zhǔn)備插入數(shù)據(jù)庫:{} ",entity);
}
}
}
其中的circleMenu()方法即為“遞歸算法”的核心所在:
private void circleMenu(MenuDto dto,List<MenuEntity> resList){
MenuEntity entity=new MenuEntity();
entity.setId(dto.getId());
entity.setParentId(dto.getParentId());
entity.setName(dto.getName());
resList.add(entity);
List<MenuDto> sons=dto.getSons();
if (sons!=null && !sons.isEmpty()){
sons.stream().forEach(m -> circleMenu(m,resList));
}
}
其核心思想其實在于“遞歸”無限級的調(diào)用自己的“方法”,如下圖所示:
最后,我們進(jìn)入測試環(huán)節(jié),廢話不多講,直接Postman的請求示意圖:
再觀察Console控制臺的輸出信息,可以看到處理結(jié)果是OK的,如下圖所示:
當(dāng)然啦,世間萬物,向來是“有一陰,必有一陽”,有優(yōu)點,也勢必有其缺點所在,“遞歸算法”也是如此,它也肯定無法處理“層級數(shù)”無窮大的情況(即棧的深度是有講究的,這一原理各位小伙伴百度即可?。?nbsp;
補充:
1、本文涉及到的相關(guān)的源代碼可以到此地址,check出來進(jìn)行查看學(xué)習(xí):
https://gitee.com/steadyjack/SpringBootTechnology
2、目前Debug已將本文所涉及的內(nèi)容整理錄制成視頻教程,感興趣的小伙伴可以前往觀看學(xué)習(xí):
https://www.fightjava.com/web/index/course/detail/5
3、關(guān)注一下Debug的技術(shù)微信公眾號,最新的技術(shù)文章、技術(shù)課程以及技術(shù)專欄將會第一時間在公眾號發(fā)布哦!