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ā)布哦!