MyBatis实现三级树查询

在实际项目开发中,树形结构的数据查询是一个非常常见的需求。比如组织架构、菜单管理、地区选择等场景都需要处理树形数据。

目录

数据库设计

实体类设计

Mapper接口设计

XML映射文件实现

Service层实现

Controller层实现


数据库设计

CREATE TABLE `sys_area` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `parent_id` bigint(20) DEFAULT NULL COMMENT '父级ID',
  `name` varchar(50) NOT NULL COMMENT '地区名称',
  `level` int(11) NOT NULL COMMENT '层级(1:省份 2:城市 3:区县)',
  `sort` int(11) DEFAULT 0 COMMENT '排序号',
  `status` tinyint(4) DEFAULT 1 COMMENT '状态(0:禁用 1:启用)',
  `create_time` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  PRIMARY KEY (`id`),
  KEY `idx_parent_id` (`parent_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='地区表';

实体类设计

@Data
public class Area implements Serializable {
    private static final long serialVersionUID = 1L;
    
    // 主键ID
    private Long id;
    
    // 父级ID
    private Long parentId;
    
    // 地区名称
    private String name;
    
    // 层级
    private Integer level;
    
    // 排序号
    private Integer sort;
    
    // 状态
    private Integer status;
    
    // 创建时间
    private Date createTime;
    
    // 更新时间
    private Date updateTime;
    
    // 子节点列表
    private List<Area> children;
}

Mapper接口设计

@Mapper
public interface AreaMapper {
    /**
     * 查询所有地区数据
     * @return 地区列表
     */
    List<Area> selectAllAreas();
    
    /**
     * 根据父ID查询子地区
     * @param parentId 父级ID
     * @return 子地区列表
     */
    List<Area> selectAreasByParentId(Long parentId);
    
    /**
     * 查询指定层级的地区
     * @param level 层级
     * @return 地区列表
     */
    List<Area> selectAreasByLevel(Integer level);
}

XML映射文件实现

@Service
@Slf4j
public class AreaServiceImpl implements AreaService {
    
    @Autowired
    private AreaMapper areaMapper;
    
    @Override
    public List<Area> buildAreaTree() {
        // 查询所有地区数据
        List<Area> allAreas = areaMapper.selectAllAreas();
        
        // 构建树形结构
        return buildTree(allAreas);
    }
    
    /**
     * 构建树形结构
     * @param areas 地区列表
     * @return 树形结构的地区列表
     */
    private List<Area> buildTree(List<Area> areas) {
        List<Area> trees = new ArrayList<>();
        
        // 获取所有根节点(省份)
        areas.stream()
            .filter(area -> area.getLevel() == 1)
            .forEach(province -> {
                // 设置省份的子节点(城市)
                List<Area> cities = getChildren(areas, province.getId());
                province.setChildren(cities);
                
                // 设置城市的子节点(区县)
                cities.forEach(city -> {
                    List<Area> districts = getChildren(areas, city.getId());
                    city.setChildren(districts);
                });
                
                trees.add(province);
            });
            
        return trees;
    }
    
    /**
     * 获取子节点
     * @param areas 所有地区列表
     * @param parentId 父级ID
     * @return 子节点列表
     */
    private List<Area> getChildren(List<Area> areas, Long parentId) {
        return areas.stream()
            .filter(area -> Objects.equals(area.getParentId(), parentId))
            .collect(Collectors.toList());
    }
}

Service层实现

@Service
@Slf4j
public class AreaServiceImpl implements AreaService {
    
    @Autowired
    private AreaMapper areaMapper;
    
    @Override
    public List<Area> buildAreaTree() {
        // 查询所有地区数据
        List<Area> allAreas = areaMapper.selectAllAreas();
        
        // 构建树形结构
        return buildTree(allAreas);
    }
    
    /**
     * 构建树形结构
     * @param areas 地区列表
     * @return 树形结构的地区列表
     */
    private List<Area> buildTree(List<Area> areas) {
        List<Area> trees = new ArrayList<>();
        
        // 获取所有根节点(省份)
        areas.stream()
            .filter(area -> area.getLevel() == 1)
            .forEach(province -> {
                // 设置省份的子节点(城市)
                List<Area> cities = getChildren(areas, province.getId());
                province.setChildren(cities);
                
                // 设置城市的子节点(区县)
                cities.forEach(city -> {
                    List<Area> districts = getChildren(areas, city.getId());
                    city.setChildren(districts);
                });
                
                trees.add(province);
            });
            
        return trees;
    }
    
    /**
     * 获取子节点
     * @param areas 所有地区列表
     * @param parentId 父级ID
     * @return 子节点列表
     */
    private List<Area> getChildren(List<Area> areas, Long parentId) {
        return areas.stream()
            .filter(area -> Objects.equals(area.getParentId(), parentId))
            .collect(Collectors.toList());
    }
}

Controller层实现

@RestController@RequestMapping("/api/areas")public class AreaController {        @Autowired    private AreaService areaService;        /**     * 获取地区树形数据     */    @GetMapping("/tree")    public ResponseResult<List<Area>> getAreaTree() {        try {            List<Area> trees = areaService.buildAreaTree();            return ResponseResult.success(trees);        } catch (Exception e) {            log.error("获取地区树形数据失败", e);            return ResponseResult.error("获取地区树形数据失败");        }    }}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晴天飛 雪

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

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

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

打赏作者

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

抵扣说明:

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

余额充值