需求:
前端頁面需要展示三級菜單,后端返回結果集。問題在於,JavaBean中的屬性值比實際需要的數量多,為了節省后端傳遞給前端的流量,將不需要的屬性值設為null,這樣轉換為Json字符串的長度會小很多。
難點在於如何將id和parentid設置為null
數據結構要求如下:

1 [ 2 { 3 name:"一級菜單" 4 menus:[ 5 { 6 name:"二級菜單" 7 menus:[ 8 { 9 name:"三級菜單" 10 }, 11 ....... 12 ] 13 }, 14 ....... 15 ] 16 }, 17 ....... 18 ]
數據庫中數據表:

1 CREATE TABLE `tb_ad` ( 2 `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID', 3 `name` varchar(50) DEFAULT NULL COMMENT '廣告名稱', 4 `position` varchar(50) DEFAULT NULL COMMENT '廣告位置', 5 `start_time` datetime DEFAULT NULL COMMENT '開始時間', 6 `end_time` datetime DEFAULT NULL COMMENT '到期時間', 7 `status` char(1) DEFAULT NULL COMMENT '狀態', 8 `image` varchar(100) DEFAULT NULL COMMENT '圖片地址', 9 `url` varchar(100) DEFAULT NULL COMMENT 'URL', 10 `remarks` varchar(1000) DEFAULT NULL COMMENT '備注', 11 PRIMARY KEY (`id`) 12 )
對應的JavaBean如下:

1 @Table(name="tb_category") 2 public class Category implements Serializable{ 3 4 @Id 5 private Integer id;//分類ID 6 7 private String name;//分類名稱 8 9 private Integer goodsNum;//商品數量 10 11 private String isShow;//是否顯示 12 13 private String isMenu;//是否導航 14 15 private Integer seq;//排序 16 17 private Integer parentId;//上級ID 18 19 private Integer templateId;//模板ID 20 private List<Category> menus; 21 //省略get/set 22 23 }
方式一,在雙層嵌套循環的過程中,在適當位置將id和parentid賦值為null。
優點,代碼編寫簡單,測試容易。缺點,對於非包裝類型無能為力,邏輯有點繞。

1 public List<Category> findCategoryTree() { 2 //1.查找所有需要顯示的category 3 Example example = new Example(Category.class); 4 Example.Criteria criteria = example.createCriteria(); 5 criteria.andEqualTo("isShow","1"); 6 example.setOrderByClause("seq");//排序 7 List<Category> categories = categoryMapper.selectByExample(example); 8 ArrayList<Category> parentList = new ArrayList<>(); 9 //2.通過遞歸的方式,給menus賦值 10 for (Category category : categories) { 11 //一級category 12 if(Objects.nonNull(category.getParentId())&&category.getParentId()==0){ 13 //清除一級目錄的parentId 14 category.setParentId(null); 15 parentList.add(category); 16 } 17 findChildren(categories,category); 18 category.setGoodsNum(null); 19 category.setIsMenu(null); 20 category.setIsShow(null); 21 category.setSeq(null); 22 category.setTemplateId(null); 23 } 24 return parentList; 25 } 26 27 private void findChildren(List<Category> categories, Category category){ 28 List<Category> list=new ArrayList<>(); 29 for (Category category1 : categories) { 30 if(category.getId().equals(category1.getParentId())){ 31 //到此說明已經找到它的father,那么parentId已經沒有用了 32 category1.setParentId(null); 33 list.add(category1); 34 } 35 } 36 //到此說明已經找到它所有的children,那么id已經沒有用了 37 category.setId(null); 38 if(list.size()>0){ 39 category.setMenus(list); 40 } 41 }
方式二,講樹狀的結果集轉為json字符串,利用正則表達式替換掉不需要的屬性,然后再將字符串轉為Object。
優點,對於非包裝類的屬性也適用,代碼重復利用性高。缺點,會生成多個字符串常量,占用內存稍高,正則表達式寫起來麻煩,不容易測試。

1 public Object findCategoryTree() { 2 //1.查找所有需要顯示的category 3 Example example = new Example(Category.class); 4 Example.Criteria criteria = example.createCriteria(); 5 criteria.andEqualTo("isShow","1"); 6 example.setOrderByClause("seq");//排序 7 List<Category> categories = categoryMapper.selectByExample(example); 8 ArrayList<Category> parentList = new ArrayList<>(); 9 //2.通過遞歸的方式,給menus賦值 10 for (Category category : categories) { 11 //一級category 12 if(Objects.nonNull(category.getParentId())&&category.getParentId()==0){ 13 //清除一級目錄的parentId 14 //category.setParentId(null); 15 parentList.add(category); 16 } 17 findChildren(categories,category); 18 category.setGoodsNum(null); 19 category.setIsMenu(null); 20 category.setIsShow(null); 21 category.setSeq(null); 22 category.setTemplateId(null); 23 } 24 //3.通過自定義方法將"id","parentId"屬性移除 25 ArrayList<String> attributes = new ArrayList<>(); 26 attributes.add("id"); 27 attributes.add("parentId"); 28 return AttributeUtils.removeAttribute(parentList,attributes); 29 } 30 31 private void findChildren(List<Category> categories, Category category){ 32 List<Category> list=new ArrayList<>(); 33 for (Category category1 : categories) { 34 if(category.getId().equals(category1.getParentId())){ 35 //到此說明已經找到它的father,那么parentId已經沒有用了 36 //category1.setParentId(null); 37 list.add(category1); 38 } 39 } 40 //到此說明已經找到它所有的children,那么id已經沒有用了 41 //category.setId(null); 42 if(list.size()>0){ 43 category.setMenus(list); 44 } 45 }
自定義工具類

1 public class AttributeUtils { 2 public static <T> Object removeAttribute(List<T> list, List<String> attributeNames) { 3 //1.將list轉為json字符串 4 String jsonString = JSONObject.toJSONString(list); 5 //2.刪除掉json字符串中相關屬性及屬性值 6 for (String attributeName : attributeNames) { 7 //元素在開頭 8 String regex1 = "[^,]\""+attributeName+"\":*[^}]*?,"; 9 Pattern p1 = Pattern.compile(regex1); 10 Matcher m1 = p1.matcher(jsonString); 11 jsonString = m1.replaceAll("{"); 12 //元素在尾部 13 String regex2 = ",\""+attributeName+"\":*[^{]*?}"; 14 Pattern p2 = Pattern.compile(regex2); 15 Matcher m2 = p2.matcher(jsonString); 16 jsonString=m2.replaceAll("}"); 17 //元素在中間 18 String regex3 = ",\""+attributeName+"\":*[^{]*?,"; 19 Pattern p3 = Pattern.compile(regex3); 20 Matcher m3 = p3.matcher(jsonString); 21 jsonString=m3.replaceAll(""); 22 } 23 Object parse = JSONObject.parse(jsonString); 24 return parse; 25 } 26 }