建表語句
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; }