【EasyPan】saveShare代码分析

【EasyPan】项目常见问题解答(自用&持续更新中…)汇总版

保存分享文件到个人网盘代码分析

一、代码结构概览

该代码实现了一个将他人分享的文件保存到自己网盘的功能,主要分为三个部分:

  1. 控制器层(Controller):处理HTTP请求和响应
  2. 服务层(Service):实现核心业务逻辑
  3. 递归方法:处理目录结构的深度复制

二、控制器层分析

saveShare 方法

@RequestMapping("/saveShare")
@GlobalInterceptor(checkParams = true, checkLogin = false)
public ResponseVO saveShare(HttpSession session,
                          @VerifyParam(required = true) String shareId,
                          @VerifyParam(required = true) String shareFileIds,
                          @VerifyParam(required = true) String myFolderId) {
    // 验证分享有效性
    SessionShareDto shareSessionDto = checkShare(session, shareId);
    
    // 获取当前用户信息
    SessionWebUserDto webUserDto = getUserInfoFromSession(session);
    
    // 防止自分享操作
    if (shareSessionDto.getShareUserId().equals(webUserDto.getUserId())) {
        throw new BusinessException("自己分享的文件无法保存到自己的网盘");
    }
    
    // 调用服务层保存逻辑
    fileInfoService.saveShare(shareSessionDto.getFileId(), shareFileIds, myFolderId, 
                            shareSessionDto.getShareUserId(), webUserDto.getUserId());
    
    return getSuccessResponseVO(null);
}

三、服务层分析

saveShare 方法

@Override
public void saveShare(String shareRootFilePid, String shareFileIds, String myFolderId, 
                     String shareUserId, String currentUserId) {
    // 分割文件ID列表
    String[] shareFileIdArray = shareFileIds.split(",");
    
    // 查询目标文件夹现有文件(用于重名检查)
    FileInfoQuery fileInfoQuery = new FileInfoQuery();
    fileInfoQuery.setUserId(currentUserId);
    fileInfoQuery.setFilePid(myFolderId);
    List<FileInfo> currentFileList = this.fileInfoMapper.selectList(fileInfoQuery);
    
    // 构建文件名映射表
    Map<String, FileInfo> currentFileMap = currentFileList.stream()
        .collect(Collectors.toMap(FileInfo::getFileName, Function.identity(), (data1,data2)->data2));
    
    // 查询待保存的分享文件列表
    fileInfoQuery = new FileInfoQuery();
    fileInfoQuery.setUserId(shareUserId);
    fileInfoQuery.setFileIdArray(shareFileIdArray);
    List<FileInfo> shareFileList = this.fileInfoMapper.selectList(fileInfoQuery);
    
    // 准备拷贝文件列表
    List<FileInfo> copyFileList = new ArrayList<>();
    Date curDate = new Date();
    
    // 处理每个待保存文件
    for (FileInfo item : shareFileList) {
        // 处理重名文件
        FileInfo haveFile = currentFileMap.get(item.getFileName());
        if (haveFile != null) {
            item.setFileName(StringTools.rename(item.getFileName()));
        }
        
        // 递归处理文件/目录
        findAllSubFile(copyFileList, item, shareUserId, currentUserId, curDate, myFolderId);
    }
    
    // 批量插入数据库
    this.fileInfoMapper.insertBatch(copyFileList);
}

四、递归方法分析

findAllSubFile 方法

private void findAllSubFile(List<FileInfo> copyFileList, FileInfo fileInfo, 
                          String sourceUserId, String currentUserId, 
                          Date curDate, String newFilePid) {
    // 保存原始文件ID(用于目录查询)
    String sourceFileId = fileInfo.getFileId();
    
    // 更新文件元信息
    fileInfo.setCreateTime(curDate);
    fileInfo.setLastUpdateTime(curDate);
    fileInfo.setFilePid(newFilePid);
    fileInfo.setUserId(currentUserId);
    
    // 生成新文件ID
    String newFileId = StringTools.getRandomString(Constants.LENGTH_10);
    fileInfo.setFileId(newFileId);
    
    // 添加到拷贝列表
    copyFileList.add(fileInfo);
    
    // 如果是目录则递归处理子文件
    if (FileFolderTypeEnums.FOLDER.getType().equals(fileInfo.getFolderType())) {
        FileInfoQuery query = new FileInfoQuery();
        query.setFilePid(sourceFileId);
        query.setUserId(sourceUserId);
        List<FileInfo> sourceFileList = this.fileInfoMapper.selectList(query);
        
        for (FileInfo item : sourceFileList) {
            findAllSubFile(copyFileList, item, sourceUserId, currentUserId, curDate, newFileId);
        }
    }
}

五、安全性和可靠性设计

  1. 参数校验

    • 使用@VerifyParam确保必要参数非空
    • 通过checkShare验证分享有效性
  2. 数据隔离

    • 严格区分shareUserIdcurrentUserId
    • 所有查询都带有用户ID条件
  3. 异常处理

    • 自分享操作抛出明确业务异常
    • 潜在的数据库异常由全局异常处理器捕获
  4. 幂等性设计

    • 重名文件自动重命名
    • 使用新ID避免冲突
### EasyPan 源码下载及相关信息 #### GitHub 和 Gitee 地址 EasyPan 的源码可以通过其官方的托管平台获取。通常情况下,类似的开源项目会在 GitHub 或 Gitee 上提供完整的代码仓库链接以便于开发者访问和贡献[^1]。如果该项目遵循常见的开源实践,则可以在以下位置查找: - **GitHub**: 如果项目主要托管在 GitHub 上,可以直接通过搜索引擎输入 `EasyPan GitHub` 找到对应的仓库地址。 - **Gitee**: 对于国内用户来说,部分项目也会同步至 Gitee 平台以提高访问速度。可以尝试搜索 `EasyPan Gitee` 获取镜像仓库。 具体地址可能需要进一步确认,但基于已有经验,许多开源项目都会在其 README 文件中明确说明如何克隆或下载代码[^2]。 --- #### 易用性与功能扩展 对于希望快速了解并使用该工具的开发者而言,建议按照如下方法操作: 首先确保本地安装了 Git 工具,随后执行命令行指令完成代码拉取工作。例如: ```bash git clone https://github.com/username/EasyPan.git ``` 或者针对 Gitee 镜像仓库: ```bash git clone https://gitee.com/username/EasyPan.git ``` 上述 URL 中的 `username` 应替换为实际维护者的用户名[^4]。此外,某些复杂项目可能会附带详细的编译指南以及依赖项列表,这些内容一般位于项目的根目录下名为 `README.md` 的文件中。 --- #### 项目文件结构概述 典型的 Spring Boot 类型项目(假设 EasyPan 基于此框架构建),其基本文件夹布局应类似于下面描述的内容[^3]: | 路径 | 描述 | |------|--------| | src/main/java/com/example/easypandemo/controller | 控制层实现类存放处 | | src/main/resources/application.yml | 系统配置参数定义区域 | | src/test/java | 单元测试相关逻辑编写区 | 以上仅为推测性的标准模板展示;真实情况需参照具体的工程设计而定。值得注意的是,当涉及多媒体处理模块时(如视频转码等功能),还可能存在额外的技术栈集成痕迹,比如 FFmpeg API 接口调用片段等[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值