Java常用代码合集2
树形工具类合集
方法一
适用多级菜单、多级评论、多级部门、多级分类的统一工具类
树形结构类
/**
* @Description: 树形结构类
*/
public interface ITreeNode<T> {
/**
* @return 获取当前元素Id
*/
Object getId();
/**
* @return 获取父元素Id
*/
Object getParentId();
/**
* @return 获取当前元素的 children 属性
*/
List<T> getChildren();
/**
* ( 如果数据库设计有tree_path字段可覆盖此方法来生成tree_path路径 )
*
* @return 获取树路径
*/
default Object getTreePath() { return ""; }
}
TreeNodeUtil
/**
* @Description: 树形结构工具类
*/
public class TreeNodeUtil {
private static final Logger log = LoggerFactory.getLogger(TreeNodeUtil.class);
public static final List<Object> IDS = Collections.singletonList(0L);
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList) {
return buildTree(dataList, IDS, (data) -> data, (item) -> true);
}
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList, Function<T, T> map) {
return buildTree(dataList, IDS, map, (item) -> true);
}
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList, Function<T, T> map, Predicate<T> filter) {
return buildTree(dataList, IDS, map, filter);
}
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList, List<Object> ids) {
return buildTree(dataList, ids, (data) -> data, (item) -> true);
}
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList, List<Object> ids, Function<T, T> map) {
return buildTree(dataList, ids, map, (item) -> true);
}
/**
* 数据集合构建成树形结构
* 如果最开始的 ids 不在 dataList 中,不会进行任何处理 )
* @param dataList 数据集合
* @param ids 父元素的 Id 集合
* @param map 调用者提供 Function<T, T> 由调用着决定数据最终呈现形势
* @param filter 调用者提供 Predicate<T> false 表示过滤 ( 注: 如果将父元素过滤掉等于剪枝 )
* @param <T> extends ITreeNode
* @return
*/
public static <T extends ITreeNode> List<T> buildTree(List<T> dataList, List<Object> ids, Function<T, T> map, Predicate<T> filter) {
if (CollectionUtils.isEmpty(ids)) {
return Collections.emptyList();
}
// 将数据分为 父子结构
Map<Boolean, List<T>> nodeMap = dataList.stream()
.filter(filter)
.collect(Collectors.partitioningBy(item -> ids.contains(item.getParentId())));
List<T> parent = nodeMap.getOrDefault(true, Collections.emptyList());
List<T> children = nodeMap.getOrDefault(false, Collections.emptyList());
if (parent.isEmpty()) {
return children;
}
List<Object> nextIds = new ArrayList<>(dataList.size());
List<T> collectParent = parent.stream().map(map).collect(Collectors.toList());
for (T parentItem : collectParent) {
if (nextIds.size() == children.size()) {
break;
}
nextIds.addAll(children.stream()
.filter(childrenItem -> parentItem.getId().equals(childrenItem.getParentId()))
.peek(parentItem.getChildren()::add)
.map(T::getParentId)
.collect(Collectors.toList()));
}
buildTree(children, nextIds, map, filter);
return parent;
}
/**
* 生成路径 treePath 路径
*
* @param currentId 当前元素的 id
* @param getById 用户返回一个 T
* @param <T>
* @return
*/
public static <T extends ITreeNode> String generateTreePath(Serializable currentId, Function<Serializable, T> getById) {
if (SystemConstants.ROOT_NODE_ID.equals(currentId)) {
return currentId.toString();
} else {
T byId = getById.apply(currentId);
if (!ObjectUtils.isEmpty(byId)) {
String parentTreePath = generateTreePath(byId.getParentId(), getById);
return parentTreePath + "," + byId.getId();
}
}
return "";
}
}
使用示例
/**
* @Description: 测试树形工具类
*/
@Data
@EqualsAndHashCode(callSuper = false)
@Accessors(chain = true)
@AllArgsConstructor
public class TestChildren implements ITreeNode<TestChildren> {
private Long id;
private String name;
private String treePath;
private Long parentId;
public TestChildren(Long id, String name, String treePath, Long parentId) {
this.id = id;
this.name = name;
this.treePath = treePath;
this.parentId = parentId;
}
@TableField(exist = false)
private List<TestChildren> children = new ArrayList<>();
}
public static void main(String[] args) {
List<TestChildren> testChildren = new ArrayList<>();
testChildren.add(new TestChildren(1L, "父元素", "", 0L));
testChildren.add(new TestChildren(2L, "子元素1", "1", 1L));
testChildren.add(new TestChildren(3L, "子元素2", "1", 1L));
testChildren.add(new TestChildren(4L, "子元素2的孙子元素", "1,3", 3L));
testChildren = TreeNodeUtil.buildTree(testChildren);
System.out.println(JSONUtil.toJsonStr(Result.success(testChildren)));
// 对 3L 进行剪枝,对 1L 进行修改
testChildren = TreeNodeUtil.buildTree(testChildren, (item) -> {
if (item.getId().equals(1L)) {
item.setName("更改了 Id 为 1L 的数据名称");
}
return item;
}, (item) -> item.getId().equals(3L));
System.out.println(JSONUtil.toJsonStr(Result.success(testChildren)));
}
方法二
/**
* 伪代码
*/
public class QcsbController {
private static Map<Integer,List<QcsbModel>> map = new HashMap<>();
/**
* 获取属性结构下拉树
*
* @return {@link List}<{@link Tree}<{@link Integer}>>
*/
@GetMapping("/tree")
public List<Tree<Integer>> equipmentTree(){
List<QcsbModel> data = qcsbService.getSelectTreeData();
// 顶级节点下的所有子级
List<QcsbModel> collect = data.stream().filter(x -> x.getPid().equals(0)).collect(Collectors.toList());
for (QcsbModel model : data) {
if (!model.getPid().equals(0)){
if (!map.containsKey(model.getPid())){
List<QcsbModel> list1 = new ArrayList<>();
list1.add(model);
map.put(model.getPid(),list1);
}else {
List<QcsbModel> list2 = map.get(model.getPid());
list2.add(model);
map.put(model.getPid(),list2);
}
}
}
List<QcsbModel> collect2 = collect.stream()
.peek(this::getL).collect(Collectors.toList());
log.info("最终数据{}", JSONUtil.toJsonStr(collect2));
return equipmentTreeList;
}
public void getL(QcsbModel model){
if (map.containsKey(model.getQcsbId())){
model.setChildren(map.get(model.getQcsbId()));
for (int i = 0; i < model.getChildren().size(); i++) {
getL(model.getChildren().get(i));
}
}
}
}
方法三
方法3未完全测试,仅供参考
public interface SysMenuService extends IService<SysMenu> {
List<SysMenu> getMenuTree();
}
@Service("sysMenuService")
public class SysMenuServiceImpl extends ServiceImpl<SysMenuDao, SysMenu> implements SysMenuService {
@Autowired
private SysMenuDao sysMenuDao ;
@Override
public List<SysMenu> getMenuTree() {
//查询出所有菜单
List<SysMenu> sysMenus = sysMenuDao.selectList(null);
//2、组装成树形结构
//2.1)、找到所有的一级菜单
List<SysMenu> level1Menus = sysMenus.stream().filter(sysMenu ->
sysMenu.getPid() == 0
).map((menu) -> {
menu.setChildren(getChildrens(menu, sysMenus));
return menu;
// 排序
}).sorted((menu1, menu2) -> {
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return level1Menus;
}
//递归查找所有菜单的子菜单,主要就是用了这个递归查询。
private List<SysMenu> getChildrens(SysMenu root, List<SysMenu> all) {
List<SysMenu> children = all.stream().filter(sysMenu -> {
return sysMenu.getPid() == root.getId();
}).map(sysMenu -> {
//1、找到子菜单
sysMenu.setChildren(getChildrens(sysMenu, all));
return sysMenu;
}).sorted((menu1, menu2) -> {
//2、菜单的排序
return (menu1.getSort() == null ? 0 : menu1.getSort()) - (menu2.getSort() == null ? 0 : menu2.getSort());
}).collect(Collectors.toList());
return children;
}
方法四
方法 4 来源 Hutool 工具类
public List<Tree<Integer>> equipmentTree(){
List<Model> data = service.getSelectTreeData();
//配置
TreeNodeConfig treeNodeConfig = new TreeNodeConfig();
// 自定义属性名
treeNodeConfig.setIdKey("Id");
treeNodeConfig.setParentIdKey("pid");
//转换器
equipmentTreeList = TreeUtil.build(data, CodeConstants.ZERO, treeNodeConfig,
(treeNode, tree) -> {
tree.setId(treeNode.getId());
tree.setParentId(treeNode.getPid());
tree.setName(treeNode.getName());
});
return equipmentTreeList;
}