平台目录树结构开发

介绍:给平台开发一个全局的系统目录树结构,可根据不同的目录属性自定义目录

主类 目录的增删改查

@Service
@Slf4j
public class CatalogServiceImpl extends ServiceImpl<CatalogMapper, Catalog> implements CatalogService {

    @Resource
    private CatalogMapper catalogMapper;


    private final int LEVEL = 4;


    /**
     * 功能描述 创建实时项目时自动创建系统根目录
     *	如果有多个目录 根据需求将目录加到list
     * @param * @param projectType
     * @param * @param projectId
     * @return
     * @author ZhiWen
     */
    @Override
    @Transactional(rollbackFor = CustomException.class)
    public void initRootCatalogByProject(String projectType, Long projectId) {
        //新增系统目录
        //用户的信息
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        Long userId = user.getId();
        try {
        	//list根据自己需求确定是否需要使用
            ArrayList<Catalog> list = new ArrayList<>();
            //离线项目
            if (projectType.equals(CatalogEnum.BATCH.getMsg())) {
                //新建 "离线数据同步目录"
                Catalog b1 = new Catalog()
                        .setCatalogUrl(CatalogEnum.BATCH_SYNC.getMsg())
                        .setCatalogType(CatalogEnum.CONTENT.getMsg())
                        .setCatalogProperty(CatalogEnum.ROOT.getMsg())
                        .setFatherCatalogId(0L)
                        .setModuleType(CatalogEnum.BATCH_SYNC_MODULE.getMsg())
                        .setProjectId(projectId)
                        .setCreateBy(userId);
                list.add(b1);
            } else if (projectType.equals(CatalogEnum.STREAM.getMsg())) {
                //新建 "实时数据同步目录"
                Catalog s1 = new Catalog()
                        .setCatalogUrl(CatalogEnum.STREAM_SYNC.getMsg())
                        .setCatalogType(CatalogEnum.CONTENT.getMsg())
                        .setCatalogProperty(CatalogEnum.ROOT.getMsg())
                        .setFatherCatalogId(0L)
                        .setModuleType(CatalogEnum.STREAM_SYNC_MODULE.getMsg())
                        .setProjectId(projectId)
                        .setCreateBy(userId);
                list.add(s1);
            }
            //批量保存
            saveBatch(list);
        } catch (Exception e) {
            log.error("创建项目新增系统根目录失败" + e);
            throw new CustomException(CatalogEnum.CATALOG_ERROR_08.getCode(), CatalogEnum.CATALOG_ERROR_08.getMsg());
        }

    }

    /**
     * 功能描述 新建文件夹
     *
     * @param folderDTO
     * @return
     * @author ZhiWen
     */
    @Override
    public void addFolder(CatalogAddFolderDTO folderDTO) {

        if (!folderDTO.getAddOrUpdate()) {
            throw new CustomException(-1, "入参异常");
        }
        checkName(folderDTO);
        Catalog fc = catalogMapper.selectById(folderDTO.getCatalogId());
        if (fc == null) {
            throw new CustomException(CatalogEnum.CATALOG_ERROR_01.getCode(), CatalogEnum.CATALOG_ERROR_01.getMsg());
        }
        String fcCatalogUrl = fc.getCatalogUrl();
        String[] urlArr = fcCatalogUrl.split("/");
        if (LEVEL == urlArr.length) {
            throw new CustomException(CatalogEnum.CATALOG_ERROR_02.getCode(), CatalogEnum.CATALOG_ERROR_02.getMsg());
        }
        boolean isFile = CatalogEnum.FILE.getMsg().equals(fc.getCatalogType());
        if (isFile) {
            log.error("该目录不支持创建文件夹");
            throw new CustomException(CatalogEnum.CATALOG_ERROR_03.getCode(), CatalogEnum.CATALOG_ERROR_03.getMsg());
        }
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        Catalog catalog = new Catalog()
                .setCatalogUrl(fcCatalogUrl + "/" + folderDTO.getName())
                .setCatalogType(CatalogEnum.CONTENT.getMsg())
                .setCatalogProperty(CatalogEnum.FOLDER.getMsg())
                .setModuleType(fc.getModuleType())
                .setFatherCatalogId(fc.getId())
                .setProjectId(fc.getProjectId())
                .setCreateBy(user.getId());

        try {
            catalogMapper.insert(catalog);
        } catch (Exception e) {
            log.error("新增文件夹失败" + e);
            throw new CustomException(CatalogEnum.CATALOG_ERROR_05.getCode(), CatalogEnum.CATALOG_ERROR_05.getMsg());
        }

    }

    /**
     * 功能描述 名称重名校验
     *
     * @param folderDTO
     * @return
     * @author ZhiWen
     */
    @Override
    public void checkName(CatalogAddFolderDTO folderDTO) {
        Catalog fc = catalogMapper.selectById(folderDTO.getCatalogId());
        if (fc == null) {
            throw new CustomException(CatalogEnum.CATALOG_ERROR_01.getCode(), CatalogEnum.CATALOG_ERROR_01.getMsg());
        }
        String newName;
        if (folderDTO.getAddOrUpdate()) {
            newName = fc.getCatalogUrl() + "/" + folderDTO.getName();
        } else {
            //获取全路径名
            String allUrl = fc.getCatalogUrl();
            //作切割 最后一级名用新名代替
            newName = allUrl.substring(0, allUrl.lastIndexOf("/") + 1) + folderDTO.getName();
        }
        QueryWrapper<Catalog> wrapper = new QueryWrapper<>();
        wrapper.eq("catalog_url", newName)
                .eq("module_type", fc.getModuleType())
                .ne("id", fc.getId());
        if (fc.getProjectId() != null) {
            wrapper.eq("project_id", fc.getProjectId());
        }
        Integer count = catalogMapper.selectCount(wrapper);
        if (count > 0) {
            throw new CustomException(CatalogEnum.CATALOG_ERROR_04.getCode(), CatalogEnum.CATALOG_ERROR_04.getMsg());
        }
    }


    @Override
    public List<CatalogTreeDTO> listCatalogTree(CatalogByModuleDTO moduleDTO) {
        //TODO 先确定目录展示跟项目是否有关
        String moduleType = moduleDTO.getModuleType();
        Long projectId = moduleDTO.getProjectId();
        //目前数据服务开发不跟项目挂钩
        boolean isDataService = moduleType.equals(CatalogEnum.DATA_SERVICE_DEV_MODULE.getMsg());
        if (!isDataService) {
            if (projectId == null) {
                throw new CustomException(-1, "入参异常");
            }
        }
        // 查询指定模块下的所有目录
        QueryWrapper<Catalog> wrapper = new QueryWrapper<>();
        wrapper.eq("module_type", moduleType);
        if (projectId != null) {
            wrapper.eq("project_id", projectId);
        }
        List<Catalog> catalogList = catalogMapper.selectList(wrapper);
        if (CollectionUtils.isEmpty(catalogList)) {
            throw new CustomException(CatalogEnum.CATALOG_ERROR_06.getCode(), CatalogEnum.CATALOG_ERROR_06.getMsg());
        }
        //转换成树结构
        List<CatalogTreeDTO> catalogTreeList = BeanUtil.copyListProperties(catalogList, CatalogTreeDTO.class);
        try {
            //添加作业信息
            log.info("添加作业信息>>>>>>>>>>>>>>>>");

            //获取目录树
            log.info("开始获取目录树结构>>>>>>>>>>>");
            List<CatalogTreeDTO> catalogTree = listToTree(catalogTreeList);

            //将目录树的数据结构化成前端展示数据
            for (CatalogTreeDTO treeDTO : catalogTree) {
                dataStructure(treeDTO);
            }
            return catalogTree;
        } catch (Exception e) {
            log.error("获取目录树失败" + e);
            throw new CustomException(CatalogEnum.CATALOG_ERROR_07.getCode(), CatalogEnum.CATALOG_ERROR_07.getMsg());
        }
    }


    /**
     *功能描述 删除当前目录及所有子目录
     * @author ZhiWen
     * @param  * @param id
     * @return
     */
    @Override
    public void deleteCatalog(Long id){
        Catalog fc = catalogMapper.selectById(id);
        if (fc == null){
            throw new CustomException(CatalogEnum.CATALOG_ERROR_01.getCode(),CatalogEnum.CATALOG_ERROR_01.getMsg());
        }
        //这里考虑根目录不可以删除
        boolean isRoot = CatalogEnum.ROOT.getMsg().equals(fc.getCatalogProperty());
        if (isRoot){
            throw new CustomException(CatalogEnum.CATALOG_ERROR_09.getCode(),CatalogEnum.CATALOG_ERROR_09.getMsg());
        }
        boolean isFile = CatalogEnum.FILE.getMsg().equals(fc.getCatalogType());
        //删除单个目录和层级目录
        if (isFile){
            catalogMapper.deleteById(id);
        }else {
            QueryWrapper<Catalog> wrapper = new QueryWrapper<>();
            wrapper.eq("module_type",fc.getModuleType())
                    .likeRight("catalog_url",fc.getCatalogUrl());
            if (fc.getProjectId()!=null){
                wrapper.eq("project_id",fc.getProjectId());
            }
            catalogMapper.delete(wrapper);
        }

    }

    /**
     *功能描述 获取当前文件下所有的子目录
     * @author ZhiWen
     * @param  * @param id
     * @return
     */
    @Override
    public List<Catalog> selectSubcatalogList(Long id){
        Catalog fc = catalogMapper.selectById(id);
        if (fc == null){
            throw new CustomException(CatalogEnum.CATALOG_ERROR_01.getCode(),CatalogEnum.CATALOG_ERROR_01.getMsg());
        }
        QueryWrapper<Catalog> wrapper = new QueryWrapper<>();
        wrapper.eq("module_type",fc.getModuleType())
                .likeRight("catalog_url",fc.getCatalogUrl());
        if (fc.getProjectId()!=null){
            wrapper.eq("project_id",fc.getProjectId());
        }
        return catalogMapper.selectList(wrapper);
    }


    /**
     *功能描述 获取当前文件夹下所有的 moduleId(对应的任务id)
     * @author ZhiWen
     * @param  * @param id
     * @return
     */
    @Override
    public List<Long> getModuleIdList(Long id){
        List<Catalog> catalogList = selectSubcatalogList(id);
        return catalogList.stream().map(Catalog::getModuleId).filter(moduleId -> moduleId != null)
                .collect(Collectors.toList());
    }

    /**
     *功能描述 目录重命名
     * @author ZhiWen
     * @param  * @param folderDTO
     * @return
     */
    @Override
    public void updateCatalog(CatalogAddFolderDTO folderDTO){
        //名称校验
        if (folderDTO.getAddOrUpdate()){
            throw new CustomException(-1,"入参异常");
        }
        checkName(folderDTO);
        Catalog fc = catalogMapper.selectById(folderDTO.getCatalogId());
        if (fc == null){
            throw new CustomException(CatalogEnum.CATALOG_ERROR_01.getCode(),CatalogEnum.CATALOG_ERROR_01.getMsg());
        }
        //根据目录类型更改
        User user = (User) SecurityUtils.getSubject().getPrincipal();
        if (CatalogEnum.FILE.getMsg().equals(fc.getCatalogType())){
            //获取全路径名
            String allUrl = fc.getCatalogUrl();
            //作切割 最后一级名用新名代替
            String newCatalogUrl = allUrl.substring(0, allUrl.lastIndexOf("/") + 1) + folderDTO.getName();
            fc.setCatalogUrl(newCatalogUrl);
            fc.setUpdateBy(user.getId());
            catalogMapper.updateById(fc);
        }else {
            //获取修改前全路径名
            String oldUrl = fc.getCatalogUrl();
            int length = oldUrl.split("/").length;
            //查出所有需要修改的子目录集
            List<Catalog> catalogList = selectSubcatalogList(folderDTO.getCatalogId());
            //遍历操作每个子目录
            for (Catalog catalog : catalogList) {
                //每级目录的全路径名称
                String allUrl = catalog.getCatalogUrl();
                //子目录切割
                String[] split = allUrl.split("/");
                //对应目录名替换
                split[length - 1] = folderDTO.getName();
                String catalogUrl = String.join("/", split);
                catalog.setCatalogUrl(catalogUrl);
                catalog.setUpdateBy(user.getId());
            }
            updateBatchById(catalogList);
        }

    }


    /*-------------------------------------------私有方法------------------------------------------*/


    /**
     * 功能描述 目录列表生成目录树
     *
     * @param * @param list
     * @return
     * @author ZhiWen
     */
    private List<CatalogTreeDTO> listToTree(List<CatalogTreeDTO> list) {
        //最好如果有多个根目录再启用
        List<CatalogTreeDTO> treeList = new ArrayList<CatalogTreeDTO>();
        for (CatalogTreeDTO tree : list) {
            //首先判断找根目录,根目录长度
            if (tree.getCatalogUrl().split("/").length == 2) {
                //去找该根目录下的所有子目录,并把此根目录及其子目录添加到结果集
                treeList.add(findChildren(tree, list));
                //如果根目录只有一个 启用
                //break;
            }
        }
        return treeList;
    }


    /**
     * 功能描述 找该树目录下的所有子目录
     *
     * @param *    @param tree
     * @param list
     * @return
     * @author ZhiWen
     */
    private CatalogTreeDTO findChildren(CatalogTreeDTO tree, List<CatalogTreeDTO> list) {
        for (CatalogTreeDTO node : list) {
            //目录的全路径名称
            String urlAll = node.getCatalogUrl();
            //最后一级目录的父目录的全路径名称
            String url = urlAll.substring(0, node.getCatalogUrl().lastIndexOf("/"));
            //判断是否是传入目录的子目录
            if (url.equals(tree.getCatalogUrl())) {
                //初始空间
                if (tree.getChildCatalogTree() == null) {
                    tree.setChildCatalogTree(new ArrayList<CatalogTreeDTO>());
                }
                //添加子目录,并继续找子目录的子目录
                tree.getChildCatalogTree().add(findChildren(node, list));
            }
        }
        return tree;
    }

    /**
     * 功能描述 数据结构化 转换成前端展示数据格式
     *
     * @param * @param treeNode
     * @return
     * @author ZhiWen
     */
    private void dataStructure(CatalogTreeDTO treeNode) {
        //全路径
        String allUrl = treeNode.getCatalogUrl();
        //最后一级目录的名称
        String substring = allUrl.substring(allUrl.lastIndexOf("/") + 1);
        //转换数据 去掉了/ 及其父目录
        treeNode.setCatalogUrl(substring);
        List<CatalogTreeDTO> childTree = treeNode.getChildCatalogTree();
        //子目录的数据格式化
        if (childTree != null) {
            for (CatalogTreeDTO node : childTree) {
                dataStructure(node);
            }
        }
    }
}

枚举类

/**
 * @description 目录相关枚举
 * @author: ZhiWen
 * @create: 2020-04-14 14:39
 **/
@Getter
public enum CatalogEnum {

    /**项目类型*/
    /**
     * 离线
     */
    BATCH("batch"),
    /**
     * 实时
     */
    STREAM("stream"),

    /**默认根目录*/
    /**
     * 离线同步
     */
    BATCH_SYNC("/离线数据同步目录"),
    /**
     * 实时同步
     */
    STREAM_SYNC("/实时数据同步目录"),


    /**catalogType*/
    /**
     * 目录
     */
    CONTENT("content"),
    /**
     * 文件
     */
    FILE("file"),


    /**请自定义module*/
    /**
     * 数据服务开发模块
     */
    DATA_SERVICE_DEV_MODULE("development"),
    /**
     * 离线同步模块
     */
    BATCH_SYNC_MODULE("batchSync"),
    /**
     * 实时同步模块
     */
    STREAM_SYNC_MODULE("streamSync"),


    /**请自定义 catalog_property*/
    /**
     * 根目录
     */
    ROOT("root"),
    /**
     * 普通文件夹
     */
    FOLDER("folder"),
    /**
     * API
     */
    API("api"),
    /**
     * 任务类JOB
     */
    JOB("job"),
    SYNC_FOLDER("syncFolder"),


    /**目录表错误信息*/
    CATALOG_ERROR_01(6301,"目录不存在"),
    CATALOG_ERROR_02(6302,"目录不可以超过三层"),
    CATALOG_ERROR_03(6303,"不支持创建目录"),
    CATALOG_ERROR_04(6304,"名称不可以重复"),
    CATALOG_ERROR_05(6305,"新建目录失败"),
    CATALOG_ERROR_06(6306,"查询目录列表为空"),
    CATALOG_ERROR_07(6307,"获取目录树失败"),
    CATALOG_ERROR_08(6308,"创建项目新增根目录失败"),
    CATALOG_ERROR_09(6309,"根目录不可以删除"),
    ;


    private Integer code;
    private String msg;

    CatalogEnum() {
    }

    CatalogEnum(String msg) {
        this.msg = msg;
    }

    CatalogEnum(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

}

表结构

CREATE TABLE `sys_catalog` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `version` int(10) DEFAULT '1' COMMENT '乐观锁版本',
  `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '逻辑删除字段(0:未删除,1:已删除)',
  `gmt_create` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `gmt_modified` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
  `create_by` bigint(20) DEFAULT NULL COMMENT '创建人',
  `update_by` bigint(20) DEFAULT NULL COMMENT '修改人',
  `catalog_url` varchar(255) DEFAULT NULL COMMENT '目录的全路径',
  `module_type` varchar(32) DEFAULT NULL COMMENT '模块类型,(服务开发:development,...)',
  `catalog_type` varchar(32) NOT NULL COMMENT '目录类型,(目录型:content,文件型:file)',
  `catalog_property` varchar(32) NOT NULL COMMENT '目录属性,(根目录:root,文件夹:folder,API:api,...)',
  `module_id` bigint(20) DEFAULT NULL COMMENT '该节点指向的关联表的主键id',
  `father_catalog_id` bigint(20) NOT NULL COMMENT '父目录id,根目录为0',
  `project_id` bigint(20) DEFAULT NULL COMMENT '所属项目id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=455 DEFAULT CHARSET=utf8 COMMENT='系统目录表';
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值