查询list转化为tree的两种方式及排序
方式一,数据库查询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
查询list转化为tree的两种方式及排序的更多相关文章
- Java中将xml文件转化为json的两种方式
原文地址https://blog.csdn.net/a532672728/article/details/76312475 最近有个需求,要将xml转json之后存储在redis中,找来找去发现整体来 ...
- C#复杂XML反序列化为实体对象两种方式
前言 今天主要讲的是如何把通过接口获取到的Xml数据转换成(反序列化)我们想要的实体对象,当然Xml反序列化和Json反序列化的方式基本上都是大同小异.都是我们事先定义好对应的对应的Xml实体模型,不 ...
- easyui里面的加载tree的两种方式
第一种: 使用EasyUI中Tree 符合EasyUI中Tree的Json格式,我们先看一下,格式是如何的 [{ "id":1, "text":"My ...
- linq 实现查询字符串拼接 : And 和 OR 两种方式
N年前我们是这样来 拼接查询字符串的: // 何问起 hovertree.com public string Test(string a, string b, string c,string d) { ...
- java.util.Arrays.sort两种方式的排序(及文件读写练习)
import java.io.*; import java.util.*; public class SortTest{ public static void main(String args[]) ...
- hibernate级联查询映射的两种方式
Hibernate主要支持两种查询方式:HQL查询和Criteria查询.前者应用较为广发,后者也只是调用封装好的接口. 现在有一个问题,就是实现多表连接查询,且查询结果集不与任何一个实体类对应,怎么 ...
- SpringBoot集成Mybatis实现多表查询的两种方式(基于xml)
下面将在用户和账户进行一对一查询的基础上进行介绍SpringBoot集成Mybatis实现多表查询的基于xml的两种方式. 首先我们先创建两个数据库表,分别是user用户表和account账户表 ...
- MySQL关闭查询缓存(QC)的两种方法
MySQL Query Cache 会缓存select 查询,安装时默认是开启的,但是如果对表进行INSERT, UPDATE, DELETE, TRUNCATE, ALTER TABLE, DROP ...
- 五 Mybatis一对一关联查询的两种方式(基于resultType&基于resultMap)
关联查询: 一个用户对应多个订单,一个订单只有一个用户 订单关联用户:两种方式 一:基于resultTYpe,一个与表关系一样的pojo实现 主表订单,从表用户 首先要有一个与关联查询表关系一样的po ...
随机推荐
- Vue 项目中对路由文件进行拆分(解构的方法)
项目需求场景: 在开发项目过程中,在项目过于庞大,路由信息非常多的情况下,如果将路由配置信息都放在一个文件里面,那么这个JS是不方便维护的, 那么,这个时候需要我们把这个庞大的路由文件,根据项目功能分 ...
- vue项目实现详情页后退缓存之前的数据
vue项目实现详情页后退缓存之前的数据 2019年02月19日 14:54:57 不想写代码的程序员 阅读数:244 一.需要缓存的内容: 1.后退缓存条件查询的数据 2.后退缓存分页信息 二.实 ...
- 【luoguP3243】[HNOI2015]菜肴制作--拓扑排序
题目描述 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为菜肴预估的质量从高到低给予1到N的顺序编号,预估质量最高的菜肴编号为1. 由于菜肴 ...
- 【集训队作业2018】line
DP方程十分简单,考虑前对后贡献即可. \(f_i = \min_{l_i \leq j < i} \left\{ f_j + \left(\max_{j < k \leq i} \lef ...
- SpringMVC——参数传递
一.接收零散参数 1.装配原则为传递参数名和方法接收参数名一致 2.手动装配@RequestParam name代表页面发送的参数名字 required代表参数是否必须传递 false代表可以不 ...
- DOM元素
元素的三种创建方法 1.doumrnt.write(可以写类名,各种表情属性) script写在哪里就创建在哪 <button>点我</button> <sc ...
- Android webView加载图片显示过大的问题
webview的基本使用流程这里我就不重复说明了,本篇针对的是文章详情加载完成后出现的情况,这里我们使用的方法是:通过js脚本,重置img标签中图片的宽度和高度. 使用步骤: 1.此方法需要使用js, ...
- how to force git to overwritten local files
最佳解决方法 重要提示:如果您有任何本地更改,将会丢失.无论是否有--hard选项,任何未被推送的本地提交都将丢失. 如果您有任何未被Git跟踪的文件(例如上传的用户内容),这些文件将不会受到影响. ...
- PHP ajax 实现三级联动
在一个单独JS页面中,利用ajax实现三级联动,做成一个三级联动形式,以便于以后随时调用 JS代码: $(document).ready(function(e) { $("#sanji&qu ...
- linux如何将某个用户加入到其它组?
答: 在Ubuntu下可以使用以下命令添加: sudo usermod -a -G <group_name> <user_name> 注意: 如何生效呢? 需要重新登陆系统 ...