首页 > 编程语言 >java 高效递归查询树 find_in_set 处理递归树

java 高效递归查询树 find_in_set 处理递归树

时间:2024-03-15 22:44:06浏览次数:22  
标签:set java 递归 value dept private deptDO new id

建表语句

DROP TABLE IF EXISTS `sys_dept`;
CREATE TABLE `sys_dept` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '部门id',
  `parent_id` bigint(20) DEFAULT '0' COMMENT '父部门id',
  `ancestors` varchar(256) DEFAULT '' COMMENT '祖级列表',
  `dept_name` varchar(64) DEFAULT '' COMMENT '部门名称',
  `order_num` int(4) DEFAULT '0' COMMENT '显示顺序',
  `status` tinyint(1) DEFAULT '0' COMMENT '部门状态(0正常 1停用)',
  `create_time` datetime DEFAULT NULL COMMENT '创建时间',
  `create_user_id` bigint(20) DEFAULT NULL COMMENT '创建人id',
  `create_user_name` varchar(64) DEFAULT NULL COMMENT '创建人姓名',
  `update_time` datetime DEFAULT NULL COMMENT '修改时间',
  `update_user_id` bigint(20) DEFAULT NULL COMMENT '修改人id',
  `update_user_name` varchar(64) DEFAULT NULL COMMENT '修改人姓名',
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `uk_dept_name` (`parent_id`,`dept_name`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 COMMENT='部门表';

-- ----------------------------
-- Records of sys_dept
-- ----------------------------
BEGIN;
INSERT INTO `sys_dept` VALUES (1, 0, '0', 'XX科技', 0, 0, '2021-10-09 10:31:47', 1, '系统管理员', NULL, NULL, NULL);
INSERT INTO `sys_dept` VALUES (2, 1, '0,1', '商务部', 3, 0, '2021-12-06 15:33:20', 1, '系统管理员', '2021-12-06 15:58:30', 1234, '管理');
INSERT INTO `sys_dept` VALUES (3, 1, '0,1', 'XX关务部', 4, 0, '2021-12-06 15:37:01', 1, '系统管理员', '2021-12-06 15:40:15', 1, '系统管理员');
INSERT INTO `sys_dept` VALUES (4, 1, '0,1', 'XX货主', 6, 0, '2021-12-06 15:38:34', 1, '系统管理员', '2021-12-06 17:17:27', 1, '系统管理员');
INSERT INTO `sys_dept` VALUES (5, 1, '0,1', '技术部', 1, 0, '2021-12-06 15:39:22', 1, '系统管理员', '2021-12-06 15:57:48', 1234, '管理');
INSERT INTO `sys_dept` VALUES (6, 4, '0,1,4', '货主-A', 1, 0, '2021-12-06 16:15:26', 1234, '小A', '2021-12-06 17:16:33', 1, '系统管理员');
INSERT INTO `sys_dept` VALUES (7, 4, '0,1,4', '货主-B', 2, 0, '2021-12-06 16:15:39', 1234, '小A', '2021-12-06 17:17:37', 1, '系统管理员');
INSERT INTO `sys_dept` VALUES (8, 6, '0,1,4,6', '1', 11, 0, '2022-03-16 10:27:28', 1, '系统管理员', '2022-03-16 10:27:37', 1, '系统管理员');
INSERT INTO `sys_dept` VALUES (9, 8, '0,1,4,6,8', '111111', 0, 0, '2022-03-16 10:27:45', 1, '系统管理员', NULL, NULL, NULL);
COMMIT;

新增

@Data
@ApiModel(value = "部门编辑对象", description = "部门编辑请求对象")
public class DeptEditRequest { @ApiModelProperty(value = "主键id", example = "-1") @DecimalMin(value = "1", message = "角色id最小为1") private Long id; @ApiModelProperty(value = "父部门id", example = "-1") @NotNull(message = "上级部门" + HibernateConstant.NOT_NULL) @JsonProperty("parent_id") private Long parentId; @ApiModelProperty(value = "部门名称", example = "IT部") @NotBlank(message = "部门名称" + HibernateConstant.NOT_NULL) @JsonProperty("dept_name") private String deptName; @ApiModelProperty(value = "显示顺序", example = "0") @NotNull(message = "显示" + HibernateConstant.NOT_NULL) @JsonProperty("order_num") private Integer orderNum; @ApiModelProperty(value = "部门状态(0正常 1停用)", example = "0") @Min(value = 0, message = "部门状态(0正常 1停用)") @Max(value = 1, message = "部门状态(0正常 1停用)") private byte status; }
    @ApiOperation("部门添加")
    @PostMapping("add")
    public JsonData add(
            @RequestBody DeptAddRequest request
    ) {
        return deptService.add(request);
    }
    @Override
    public JsonData add(DeptAddRequest request) {
        DeptEditRequest deptEditRequest = new DeptEditRequest();
        BeanUtils.copyProperties(request, deptEditRequest);
        //同级部门下,部门名称重复
        checkDeptNameUnique(deptEditRequest);
        DeptDO deptDO = new DeptDO();
        deptDO.setDeptName(request.getDeptName());
        deptDO.setParentId(request.getParentId());
        deptDO.setStatus(request.getStatus());
        deptDO.setOrderNum(request.getOrderNum());
        deptDO.setCreateTime(CommonUtil.getCurrentDate());
        deptDO.setCreateUserId(CommonUtil.getCurrentUserId());
        deptDO.setCreateUserName(CommonUtil.getCurrentUserName());
        //检查上级部门状态
        checkParentDeptState(deptDO);
        int rows = deptMapper.add(deptDO);
        if (rows > 0) {
            log.info("部门添加,rows:{},添加成功:{}", rows, deptDO);
            return JsonData.buildAddSuccess();
        }
        return JsonData.buildError("添加失败");
    }


    /**
     * 部门名称唯一值
     *
     * @param request
     */
    private void checkDeptNameUnique(DeptEditRequest request) {
        List<DeptDO> deptList = deptMapper.selectList(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getDeptName, request.getDeptName())
                        .eq(DeptDO::getParentId, request.getParentId())
        );
        for (DeptDO deptDO : deptList) {
            if (deptDO.getId() != request.getId()) {
                throw new BizException(500, "部门已存在");
            }
        }
    }


    /**
     * 检查上级部门状态
     *
     * @param dept 部门对象
     */
    private void checkParentDeptState(DeptDO dept) {
        DeptDO deptDO = deptMapper.selectOne(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getId, dept.getParentId())
        );
        if (deptDO == null) {
            throw new BizException(500, "上级部门不存在");
        }
        if (1 == deptDO.getStatus()) {
            throw new BizException(500, "上级部门已停用,不允许新增");
        }
        dept.setAncestors(deptDO.getAncestors() + "," + dept.getParentId());
    }

编辑

@Data
@ApiModel(value = "部门编辑对象", description = "部门编辑请求对象")
public class DeptEditRequest {
    @ApiModelProperty(value = "主键id", example = "-1")
    @DecimalMin(value = "1", message = "角色id最小为1")
    private Long id;

    @ApiModelProperty(value = "父部门id", example = "-1")
    @NotNull(message = "上级部门" + HibernateConstant.NOT_NULL)
    @JsonProperty("parent_id")
    private Long parentId;

    @ApiModelProperty(value = "部门名称", example = "IT部")
    @NotBlank(message = "部门名称" + HibernateConstant.NOT_NULL)
    @JsonProperty("dept_name")
    private String deptName;

    @ApiModelProperty(value = "显示顺序", example = "0")
    @NotNull(message = "显示" + HibernateConstant.NOT_NULL)
    @JsonProperty("order_num")
    private Integer orderNum;

    @ApiModelProperty(value = "部门状态(0正常 1停用)", example = "0")
    @Min(value = 0, message = "部门状态(0正常 1停用)")
    @Max(value = 1, message = "部门状态(0正常 1停用)")
    private byte status;
}
    @ApiOperation("部门修改")
    @PostMapping("edit")
    public JsonData edit(
            @RequestBody DeptEditRequest request
    ) {
        if (request.getId() == 1) {
            throw new BizException(500, "不允许操作系统默认部门");
        }
        return deptService.edit(request);
    }
    @Override
    @Transactional
    public JsonData edit(DeptEditRequest request) {
        DeptDO deptDO = new DeptDO();
        BeanUtils.copyProperties(request, deptDO);
        //同级部门下,部门名称重复
        checkDeptNameUnique(request);
        //检查上级部门状态
        checkParentDeptState(deptDO);
        //上级部门不能是自己
        checkParentDept(request);
        //父级对象
        DeptDO parentDept = deptMapper.selectOne(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getId, deptDO.getParentId())
        );
        if (parentDept == null) {
            throw new BizException(500, "上级部门不存在");
        }
        DeptDO oldDept = deptMapper.selectOne(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getId, deptDO.getId())
        );
        if (oldDept == null) {
            throw new BizException(500, "记录不存在,请稍后重试");
        }
        String newAncestors = parentDept.getAncestors() + "," + parentDept.getId();
        String oldAncestors = oldDept.getAncestors();
        deptDO.setAncestors(newAncestors);
        byte oldState = oldDept.getStatus();
        int rows = deptMapper.updateById(deptDO);
        if (rows > 0) {
            log.info("部门修改,rows:{},修改成功:{}", rows, deptDO);
            //递归处理子部门状态
            if (oldState != deptDO.getStatus()) {
                updateChildDeptState(deptDO, newAncestors, oldAncestors);
            }
            return JsonData.buildEditSuccess();
        }
        return JsonData.buildError("修改失败");
    }


    /**
     * 部门名称唯一值
     *
     * @param request
     */
    private void checkDeptNameUnique(DeptEditRequest request) {
        List<DeptDO> deptList = deptMapper.selectList(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getDeptName, request.getDeptName())
                        .eq(DeptDO::getParentId, request.getParentId())
        );
        for (DeptDO deptDO : deptList) {
            if (deptDO.getId() != request.getId()) {
                throw new BizException(500, "部门已存在");
            }
        }
    }


    /**
     * 检查上级部门状态
     *
     * @param dept 部门对象
     */
    private void checkParentDeptState(DeptDO dept) {
        DeptDO deptDO = deptMapper.selectOne(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getId, dept.getParentId())
        );
        if (deptDO == null) {
            throw new BizException(500, "上级部门不存在");
        }
        if (1 == deptDO.getStatus()) {
            throw new BizException(500, "上级部门已停用,不允许新增");
        }
        dept.setAncestors(deptDO.getAncestors() + "," + dept.getParentId());
    }

    /**
     * 上级部门不能是自己
     *
     * @param request
     */
    private void checkParentDept(DeptEditRequest request) {
        if (request.getId().equals(request.getParentId())) {
            throw new BizException(500, "上级部门不能是自己");
        }
    }

    /**
     * 处理子部门状态
     *
     * @param deptDO       部门对象
     * @param newAncestors 新的父ID集合
     * @param oldAncestors 旧的父ID集合
     */
    private void updateChildDeptState(DeptDO deptDO, String newAncestors, String oldAncestors) {
        deptMapper.batchUpdateChildDeptState(deptDO.getId(), deptDO.getStatus());
        //找所有子部门
        List<DeptDO> deptList = deptMapper.selectChildrenDeptById(deptDO.getId());
        for (DeptDO dpt : deptList) {
            dpt.setAncestors(dpt.getAncestors().replaceFirst(oldAncestors, newAncestors));
            deptMapper.updateById(dpt);
        }
    }
    /**
     * 批量更新子部门状态
     *
     * @param id    部门id
     * @param state 状态
     * @return
     */
    int batchUpdateChildDeptState(
            @Param("id") Long id,
            @Param("state") Byte state
    );

    <!-- 批量更新子部门状态 -->
    <update id="batchUpdateChildDeptState">
        UPDATE
            sys_dept
        SET
            `status`=#{state}
        WHERE ancestors LIKE CONCAT('%',#{id},'%')
    </update>


    /**
     * 根据id找所有子部门
     *
     * @param id
     * @return
     */
    List<DeptDO> selectChildrenDeptById(@Param("id") Long id);

    <!-- 根据id找所有子部门 -->
    <select id="selectChildrenDeptById" resultMap="BaseResultMap">
        SELECT
            id,
            parent_id,
            ancestors,
            dept_name,
            order_num,
            `status`,
            create_time,
            create_user_id,
            create_user_name,
            update_time,
            update_user_id,
            update_user_name
        FROM
            sys_dept
        WHERE
            FIND_IN_SET(#{id},ancestors)
    </select>

删除

    @ApiOperation("部门删除")
    @GetMapping("remove")
    public JsonData remove(
            @ApiParam(value = "部门id", required = true) @RequestParam(value = "id", required = true) Long id
    ) {
        if (id == 1) {
            throw new BizException(500, "不允许操作系统默认部门");
        }
        return deptService.remove(id);
    }
    @Override
    public JsonData remove(Long id) {
        int rows = deptMapper.deleteById(id);
        if (rows > 0) {
            log.info("部门删除,rows:{},删除成功:{}", rows, id);
            //递归删除子部门
            removeChildDept(id);
            return JsonData.buildRemoveSuccess();
        }
        return JsonData.buildError("部门删除失败");
    }

    /**
     * 删除子部门
     *
     * @param parentId
     */
    private void removeChildDept(Long parentId) {
        List<DeptDO> deptList = deptMapper.selectList(
                new LambdaQueryWrapper<DeptDO>()
                        .eq(DeptDO::getParentId, parentId)
        );
        for (DeptDO deptDO : deptList) {
            deptMapper.deleteById(deptDO.getId());
            removeChildDept(deptDO.getId());
        }
    }

递归树

@Data
@ApiModel(value = "DeptTreeVo对象", description = "部门树对象信息")
public class DeptTreeVo {
    @ApiModelProperty("节点id")
    @JsonSerialize(using = ToStringSerializer.class)
    private Long id;

    @ApiModelProperty("节点名称")
    private String label;

    @ApiModelProperty("子节点")
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private List<DeptTreeVo> children;
}
    @ApiOperation("部门树")
    @GetMapping("deptTree")
    public JsonData<List<DeptTreeVo>> deptTree() {
        return deptService.deptTree();
    }
    private static final ThreadPoolExecutor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(
            APS * 2,
            APS * 4,
            KEEP_ALIVE_TIME,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(256),
            new ThreadFactoryBuilder().setNameFormat("部门-pool-%d").build(),
            new ThreadPoolExecutor.CallerRunsPolicy()
    );

    @Override
    public JsonData<List<DeptTreeVo>> deptTree() {
        LambdaQueryWrapper<DeptDO> wrapper = new LambdaQueryWrapper<DeptDO>();
        wrapper.orderByAsc(DeptDO::getParentId, DeptDO::getOrderNum);
        List<DeptDO> deptList = deptMapper.selectList(wrapper);
        return buildDeptTree(deptList);
    }



    /**
     * 构建前端需要构建树结构
     *
     * @param deptList 部门集合
     * @return
     */
    private JsonData<List<DeptTreeVo>> buildDeptTree(List<DeptDO> deptList) {
        List<DeptTreeVo> deptTreeList = new ArrayList<>();
        List<DeptDO> rootDeptList = deptList.stream().filter(obj -> 1 == obj.getId()).collect(Collectors.toList());
        CountDownLatch latch = new CountDownLatch(rootDeptList.size());
        for (DeptDO deptDO : rootDeptList) {
            THREAD_POOL_EXECUTOR.execute(() -> {
                DeptTreeVo vo = new DeptTreeVo();
                vo.setId(deptDO.getId());
                vo.setLabel(deptDO.getDeptName());
                buildChildrentDeptTree(deptList, deptDO.getId(), vo);
                deptTreeList.add(vo);
                latch.countDown();
            });
        }
        try {
            latch.await();
        } catch (InterruptedException e) {
            log.error("构建部门树结构线程报错:{}", e);
        }
        return JsonData.buildSuccess(deptTreeList);
    }


    /**
     * 构建子部门树
     *
     * @param deptList 部门集合
     * @param parentId 父ID
     * @param vo       部门树
     */
    private void buildChildrentDeptTree(List<DeptDO> deptList, Long parentId, DeptTreeVo vo) {
        List<DeptDO> childList = deptList.stream().filter(obj -> parentId == obj.getParentId()).collect(Collectors.toList());
        List<DeptTreeVo> childDeptTreeList = new ArrayList<>();
        for (DeptDO deptDO : childList) {
            DeptTreeVo dtv = new DeptTreeVo();
            dtv.setId(deptDO.getId());
            dtv.setLabel(deptDO.getDeptName());
            buildChildrentDeptTree(deptList, deptDO.getId(), dtv);
            childDeptTreeList.add(dtv);
        }
        vo.setChildren(childDeptTreeList);
    }


@Data
@TableName("sys_dept")
@ApiModel(value = "SysDeptDO对象", description = "部门表")
public class DeptDO implements Serializable {

    private static final long serialVersionUID = 1L;

    @ApiModelProperty(value = "部门id")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    @ApiModelProperty(value = "父部门id")
    private Long parentId;

    @ApiModelProperty(value = "祖级列表")
    private String ancestors;

    @ApiModelProperty(value = "部门名称")
    private String deptName;

    @ApiModelProperty(value = "显示顺序")
    private Integer orderNum;

    @ApiModelProperty(value = "部门状态(0正常 1停用)")
    private byte status;

    @ApiModelProperty(value = "创建时间")
    @TableField(value = "create_time", fill = FieldFill.INSERT)
    private Date createTime;

    @ApiModelProperty(value = "创建人id")
    @TableField(value = "create_user_id", fill = FieldFill.INSERT)
    private Long createUserId;

    @ApiModelProperty(value = "创建人姓名")
    @TableField(value = "create_user_name", fill = FieldFill.INSERT)
    private String createUserName;

    @ApiModelProperty(value = "修改时间")
    @TableField(value = "update_time", fill = FieldFill.UPDATE)
    private Date updateTime;

    @ApiModelProperty(value = "修改人id")
    @TableField(value = "update_user_id", fill = FieldFill.UPDATE)
    private Long updateUserId;

    @ApiModelProperty(value = "修改人姓名")
    @TableField(value = "update_user_name", fill = FieldFill.UPDATE)
    private String updateUserName;
}

 

标签:set,java,递归,value,dept,private,deptDO,new,id
From: https://www.cnblogs.com/chenyanbin/p/18076418

相关文章

  • Java中二维数组全部赋成同一个值
    有以下几种方法可以将二维数组全部赋成同一个值:1. 使用双重循环遍历二维数组,逐个元素赋值。int[][]arr=newint[3][3];intvalue=5;for(inti=0;i<arr.length;i++){for(intj=0;j<arr[i].length;j++){arr[i][j]=value;}}2. 使用Arrays.......
  • java毕业设计夕阳红养老院系统(springboot+mysql+jdk1.8+meven)
    本系统(程序+源码)带文档lw万字以上 文末可领取本课题的JAVA源码参考系统程序文件列表系统的选题背景和意义选题背景:随着社会的发展和人口老龄化的加剧,养老问题逐渐成为社会关注的焦点。传统的家庭养老模式已无法满足日益增长的养老需求,特别是对于独居老人和失能老人来说,......
  • 深入理解 Java 多线程、Lambda 表达式及线程安全最佳实践
    Java线程线程使程序能够通过同时执行多个任务而更有效地运行。线程可用于在不中断主程序的情况下在后台执行复杂的任务。创建线程有两种创建线程的方式。扩展Thread类可以通过扩展Thread类并覆盖其run()方法来创建线程:publicclassMyThreadextendsThread{public......
  • Windows 部署 JAVA服务
    WinSW.exe是一个可以将Windows上的任何一个程序注册为服务的工具,也可以进行卸载该服务。下载WinSW.exe重命名为 bsq-admin.exe,放到 C:\bsq\bsqmes文件夹复制bsq-admin.jar包到 C:\bsq\bsqmes文件夹新建 bsq-admin.xml配置文件,内容如下:<service>   <id>bsq-......
  • L1-7 分寝室 [java]
    分数20学校新建了宿舍楼,共有 n 间寝室。等待分配的学生中,有女生 n0​ 位、男生 n1​ 位。所有待分配的学生都必须分到一间寝室。所有的寝室都要分出去,最后不能有寝室留空。现请你写程序完成寝室的自动分配。分配规则如下:男女生不能混住;不允许单人住一间寝室;对每种性......
  • 什么是分库分表?用Java手写一个分库分表组件
    分库分表分库分表路由组件的主要功能是负责处理数据在多个数据库和表之间的分配和路由。在分库分表的场景中,数据会根据一定的策略(如业务逻辑、哈希算法等)被分散到不同的数据库或表中,以提高系统的并发处理能力和扩展性。具体来说,分库分表路由组件需要完成以下任务:数据源的......
  • Java学习第二天——基础语法
    Java基础语法数据类型强类型语言要求变量的使用要严格符合规定,所有变量都必须先定义后才能使用!!!Java的数据类型分类基本类型(primitivetype)1.数值类型整数类型浮点类型字符类型(只占有两个字节)2.boolean类型:占一位,其值为true或者false引用类型(referencetype)类、接......
  • Java基础知识篇02——Java基本语法
    一、数据类型定义:就是用了保存数据的一个类型,一种数据类型,只能保存该类型数据值作用:只有了解数据类型,才能选择合适的类型存放数据,才能更好的利用计算机硬件资源(内存和硬盘等)。不同的数据类型存放数据大小是不同的。数据类型的使用方式就是用来声明一个变量,装数据的。......
  • 程序人生——Java枚举和注解使用建议
    目录引出枚举和注解建议83:推荐使用枚举定义常量建议84:使用构造函数协助描述枚举项建议85:小心switch带来的空值异常建议86:在switch的default代码块中增加AssertionError错误建议87:使用valueOf前必须进行校验建议88:用枚举实现工厂方法模式更简洁建议89:枚举项的数量控制......
  • 程序人生——Java泛型和反射的使用建议
    目录引出泛型和反射建议93:Java的泛型是类型擦除的建议94:不能初始化泛型参数和数组建议95:强制声明泛型的实际类型建议96:不同的场景使用不同的泛型通配符建议97:警惕泛型是不能协变和逆变的建议98:建议采用的顺序是List,List,List建议99:严格限定泛型类型采用多重界限建议1......