方式一,數據庫查詢tree;
MyBatis collection 集合
MyBatis 是數據持久層框架,支持定制化 SQL、存儲過程以及高級映射。尤其強大在於它的映射語句,比如高級映射中的 collection 集合。
collection 集合,集合常用的兩個場景是集合的嵌套查詢、集合的嵌套結果。集合的嵌套結果就是查詢結果對應嵌套子對象。這里就是利用 collection 集合嵌套查詢樹形節點。下面來一一實現。
查詢樹形節點 Web 案例
創建數據庫表
節點表:
CREATE TABLE `node` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(32) NOT NULL, `parent_id` int(11) unsigned NOT NULL, PRIMARY KEY (`id`), KEY `parent_id` (`parent_id`) ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8mb4 COMMENT='節點表'
簡單的節點父子關系設計,下面插入幾條數據:
INSERT INTO node (name, parent_id) VALUES ('一級節點A', 0); INSERT INTO node (name, parent_id) VALUES ('一級節點B', 0); INSERT INTO node (name, parent_id) VALUES ('一級節點C', 0); INSERT INTO node (name, parent_id) VALUES ('二級節點AA', 1); INSERT INTO node (name, parent_id) VALUES ('二級節點aa', 1); INSERT INTO node (name, parent_id) VALUES ('二級節點BB', 2); INSERT INTO node (name, parent_id) VALUES ('三級級節點AAA', 4); INSERT INTO node (name, parent_id) VALUES ('三級級節點aaa', 4); INSERT INTO node (name, parent_id) VALUES ('三級級節點BBB', 6);
重要的還是看 collection 在 xml 的映射實現,NodeMapper.xml 代碼如下:
<mapper namespace="org.mybatis.dao.NodeDao"> <resultMap id="BaseTreeResultMap" type="org.mybatis.domain.Node"> <result column="id" property="id"/> <result column="name" property="name"/> <collection column="id" property="next" javaType="java.util.ArrayList" ofType="org.mybatis.domain.Node" select="getNextNodeTree"/> </resultMap> <resultMap id="NextTreeResultMap" type="org.mybatis.domain.Node"> <result column="id" property="id"/> <result column="name" property="name"/> <collection column="id" property="next" javaType="java.util.ArrayList" ofType="org.mybatis.domain.Node" select="getNextNodeTree"/> </resultMap> <sql id="Base_Column_List"> id, name </sql> <select id="getNextNodeTree" resultMap="NextTreeResultMap"> SELECT <include refid="Base_Column_List"/> FROM node WHERE parent_id = #{id} </select> <select id="getNodeTree" resultMap="BaseTreeResultMap"> SELECT <include refid="Base_Column_List"/> FROM node WHERE parent_id = 0 </select> </mapper>
在 dao 層,我們只調用 getNodeTree
方法,parent_id = 0
代表頂級節點。然后通過 collection 節點繼續調用 getNextNodeTree
方法進行循環調用。
<collection column="id" property="next" javaType="java.util.ArrayList" ofType="org.mybatis.domain.Node" select="getNextNodeTree"/>
以下是關鍵的知識點:
- column 代表會拿父節點 id ,作為參數獲取 next 對象
- javaType 代表 next 對象是個列表,其實可以省略不寫
- ofType 用來區分 JavaBean 屬性類型和集合包含的類型
- select 是用來執行循環哪個 SQL
工程代碼地址:https://github.com/JeffLi1993/myabtis-learning-example
工程演示后的結果如圖所示:

普通list轉樹狀list
public static List<User> list2tree(List<User> list) { List<User> result = new ArrayList<>(); Map<Object, User> hash = list.stream().collect(Collectors.toMap(u -> u.getId(), u -> u)); for (User u : list) { User p = hash.get(u.getParent()); if (p == null) { result.add(u); } else { if (p.getChildren() == null) { p.setChildren(new ArrayList<>()); } p.getChildren().add(u); } } return result; }
樹狀list轉普通list
public static List<User> tree2list(List<User> list) { List<User> result = new ArrayList<>(); for (User u : list) { List<User> c = u.getChildren(); result.add(u); if (!CollectionUtils.isEmpty(c)) { result.addAll(tree2list(c)); u.setChildren(null);// } } return result; }
java8 stream多字段排序
使用java8新特性,下面先來點基礎的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
List<類> list; 代表某集合
//返回 對象集合以類屬性一升序排序
list.stream().sorted(Comparator.comparing(類::屬性一));
//返回 對象集合以類屬性一降序排序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed());
//先以屬性一升序,結果進行屬性一降序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()));
//以屬性一降序
//返回 對象集合以類屬性一升序 屬性二升序
list.stream().sorted(Comparator.comparing(類::屬性一).thenComparing(類::屬性二));
//返回 對象集合以類屬性一降序 屬性二升序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二));
//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二升序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()).thenComparing(類::屬性二));
//先以屬性一降序,再進行屬性二升序
//返回 對象集合以類屬性一降序 屬性二降序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二,Comparator.reverseOrder()));
//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二降序
list.stream().sorted(Comparator.comparing(類::屬性一,Comparator.reverseOrder()).thenComparing(類::屬性二,Comparator.reverseOrder()));
//先以屬性一降序,再進行屬性二降序
//返回 對象集合以類屬性一升序 屬性二降序 注意兩種寫法
list.stream().sorted(Comparator.comparing(類::屬性一).reversed().thenComparing(類::屬性二).reversed());
//先以屬性一升序,升序結果進行屬性一降序,再進行屬性二升序,結果進行屬性一降序屬性二降序
list.stream().sorted(Comparator.comparing(類::屬性一).thenComparing(類::屬性二,Comparator.reverseOrder()));
//先以屬性一升序,再進行屬性二降序<br><br><br>
|
通過以上例子我們可以發現
1. Comparator.comparing(類::屬性一).reversed();
2. Comparator.comparing(類::屬性一,Comparator.reverseOrder());
兩種排序是完全不一樣的,一定要區分開來 1 是得到排序結果后再排序,2是直接進行排序,很多人會混淆導致理解出錯,2更好理解,建議使用2
3.注意排序后需要另外一個lis來接收List<xxx> list= Stream.sort(xxx).collect(toList());
class testRun { public static void main(String[] args) { List<test> testList = new ArrayList<>(); Date d = DateUtils.now(); for (int i = 1; i <= 3; i++) { test t = new test(i, DateUtils.addDays(d, i)); testList.add(t); } for (int i = 1; i <= 3; i++) { test t = new test(i, DateUtils.addMonths(d, i)); testList.add(t); } testList.forEach(o -> { System.out.println(o.toString()); }); List<test> sort = testList.stream().sorted(Comparator.comparing(test::getState).thenComparing(test::getTime,Comparator.reverseOrder())).collect(toList()); System.out.println("------------------------------------"); sort.forEach(o -> { System.out.println(o.toString()); }); } }
參考
鏈接:https://blog.csdn.net/qq_41991665/article/details/90484690