Java树形结构,适配前端Cascader级联选择器使用

一、Entity

实体类:BCategoryDict.java

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;

/**
 * 业务-分类对象 b_category_dict
 * @author Xuedi
 * @date 2021-12-23
 */
@Data
public class BCategory {
    private Long id;
    /** 父类别id */
    private Long parentId;
    /** 祖级列表 */
    private String ancestors;
    /** 分类名 */
    private String name;
    /** 分类级别 */
    private Integer level;
    /** 状态(0关闭 1开启) */
    private Integer status;
    /** 排序 */
    private Integer sort;
    /** 描述 */
    private String description;
}

Vo类:BCategoryDictVo.java

import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
import java.util.Date;
import java.util.ArrayList;
import java.util.List;

/**
 * 业务-分类对象 b_category_dict
 * @author Xuedi
 * @date 2021-12-23
 */
@Data
public class BCategoryVo {
    private Long id;
    /** 父类别id */
    private Long parentId;
    /** 祖级列表 */
    private String ancestors;
    /** 分类名 */
    private String name;
    /** 分类级别 */
    private Integer level;
    /** 状态(0关闭 1开启) */
    private Integer status;
    /** 排序 */
    private Integer sort;
    /** 描述 */
    private String description;
	/** 子集 */
	private List<BCategoryVo> children = new ArrayList<BCategoryVo>();;
}

树形结构类:BCategoryTree.java

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serializable;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 树形结构实体Demo
 * @author Xuedi
 * @date 2021-12-23
 */
@Data
public class BCategoryTree implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 节点ID
     */
    private Long id;
    /**
     * 节点名称
     */
    private String label;
    /**
     * 子节点
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<BCategoryTree> children;

    public BCategoryTree() { }

    public BCategoryTree(BCategoryVo item) {
        this.id = item.getId();
        this.label = item.getName();
        this.children = item.getChildren().stream().map(BCategoryTree::new).collect(Collectors.toList());
    }
}

二、Controller

对外接口:BCategoryController.java

import com.smart.common.core.domain.AjaxResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.Map;

/**
 * 业务-分类接口层 Controller
 *
 * @author Xuedi
 * @date 2021-12-23
 */
@RestController
@RequestMapping("/business/category")
public class BCategoryController {
    @Autowired
    private IBCategoryService bCategoryService;

    /**
     * 查询业务-账单类别树形列表
     */
    @RequestMapping(value = "/getTreeByParams",method = RequestMethod.GET)
    public List<BCategoryTree> getTreeByParams(@RequestParam Map params) {
        return bCategoryService.getTreeByParams(params);
    }
}

三、service

业务逻辑层接口:IBCategoryService.java

import com.smart.common.core.domain.AjaxResult;
import java.util.Map;

/**
 * 业务-分类业务逻辑接口层 Service接口
 * @author Xuedi
 * @date 2021-12-23
 */
public interface IBCategoryService {
    /**
     * 获取区服树形列表
     * @param params
     * @return
     */
    public List<BCategoryTree> getTreeByParams(Map params);
}

业务逻辑层接口实现类:BCategoryServiceImpl.java

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 业务-分类 Service业务层处理
 * @author Xuedi
 * @date 2021-12-23
 */
@Service
public class BCategoryServiceImpl implements IBCategoryService {
    @Autowired
    private BCategoryMapper bCategoryMapper;

    /**
     * 获取树形列表
     * @param params
     * @return
     */
    @Override
    public List<BCategoryTree> getTreeByParams(Map params) {
        //查询所有节点
        List<BCategoryVo> lists = bCategoryMapper.getBCategoryListByParams(params);
        List<BCategoryVo> categoryTrees = buildTree(lists);
		List<BCategoryTree> data = categoryTrees.stream().map(BCategoryTree::new).collect(Collectors.toList());
        return data;
    }

    // ============= 树结构 start =============
    /**
     * 构建树形结构
     * @param list
     * @return
     */
    public List<BCategoryVo> buildTree(List<BCategoryVo> list) {
        List<BCategoryVo> returnList = new ArrayList<BCategoryVo>();
        //id集合
        List<Long> idList = new ArrayList<Long>();
        for (BCategoryVo item : list) {
            idList.add(item.getId());
        }
        //循环
        for (Iterator<BCategoryVo> iterator = list.iterator(); iterator.hasNext();) {
            BCategoryVo vo = (BCategoryVo) iterator.next();
            // 如果是顶级节点, 遍历该父节点的所有子节点
            if (!idList.contains(vo.getParentId())) {
                recursionFn(list, vo);
                if (vo.getLevel() == 1){
                    returnList.add(vo);
                }
            }
        }
        if (returnList.isEmpty()) {
            returnList = list;
        }
        return returnList;
    }
    /**
     * 递归列表
     */
    private void recursionFn(List<BCategoryVo> list, BCategoryVo t) {
        // 得到子节点列表
        List<BCategoryVo> childList = getChildList(list, t);
        t.setChildren(childList);
        for (BCategoryVo tChild : childList) {
            // 判断是否有子节点
            if(getChildList(list, tChild).size() > 0){
                recursionFn(list, tChild);
            }
        }
    }
    /**
     * 得到子节点列表
     */
    private List<BCategoryVo> getChildList(List<BCategoryVo> list, BCategoryVo t) {
        List<BCategoryVo> tlist = new ArrayList<BCategoryVo>();
        Iterator<BCategoryVo> it = list.iterator();
        while (it.hasNext()) {
            BCategoryVo n = (BCategoryVo) it.next();
            if (null != n.getParentId() && n.getParentId().longValue() == t.getId().longValue()) {
                tlist.add(n);
            }
        }
        return tlist;
    }
    // ============= 树结构 end =============
}

四、mapper

Mapper接口:BCategoryMapper.java

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Map;

/**
 * 业务-分类 Mapper接口
 * @author Xuedi
 * @date 2021-12-23
 */
@Repository
@Mapper
public interface BCategoryMapper {
    /**
     * 查询业务列表
     */
    public List<BCategoryVo> getBCategoryListByParams(Map params);
}

五、mapper.xml

resultType需要自己指定上面的vo类路径

<select id="getBCategoryListByParams" parameterType="map" resultType="com.smart.business.entity.vo.BCategoryVo">
	SELECT id, parent_id, ancestors, name, level, status, sort, description FROM b_category
	<where>
		<if test="ancestors != null">
			AND find_in_set( #{ancestors}, ancestors)
		</if>
		<if test="parentId != null">
			AND parent_id = #{parentId}
		</if>
		<if test="level != null">
			AND level = #{level}
		</if>
		<if test="status != null">
			AND status = #{status}
		</if>
	</where>
</select>

七、结果

[
	{
		"id": 1,
		"label": "首页模块",
		"children": [
			{
				"id": 6,
				"label": "A图标"
			},
			{
				"id": 7,
				"label": "B图标"
			}
		]
	},
	{
		"id": 2,
		"label": "个人中心模块",
		"children": [
			{
				"id": 8,
				"label": "A图标"
			},
		]
	},
	{
		"id": 3,
		"label": "看视频模块",
		"children": [
			{
				"id": 16,
				"label": "图标",
				"children": [
					{
						"id": 17,
						"label": "A图标"
					},
					{
						"id": 18,
						"label": "B图标"
					}
				]
			}
		]
	}
]

数据库表结构,mysql

CREATE TABLE `b_category` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `parent_id` bigint(20) DEFAULT '0' COMMENT '父类别id',
  `ancestors` varchar(50) DEFAULT '' COMMENT '祖级列表',
  `name` varchar(255) DEFAULT NULL COMMENT '类型名',
  `level` int(11) DEFAULT NULL COMMENT '分类等级',
  `status` int(1) DEFAULT '1' COMMENT '状态',
  `sort` int(10) DEFAULT '0' COMMENT '排序',
  `description` varchar(255) DEFAULT NULL COMMENT '描述',
  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='分类';

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学弟不想努力了

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值