package org.jeecg.modules.doc.component; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import lombok.extern.slf4j.Slf4j; import org.apache.commons.codec.digest.DigestUtils; import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.RedisUtil; import org.jeecg.modules.doc.constant.Constant; import org.jeecg.modules.doc.entity.DocFile; import org.jeecg.modules.doc.entity.DocFilePath; import org.jeecg.modules.doc.mapper.DocFileMapper; import org.jeecg.modules.doc.mapper.DocFilePathMapper; import org.jeecg.modules.doc.service.IDocFilePathService; import org.jeecg.modules.doc.vo.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.annotation.Resource; import java.io.IOException; import java.io.InputStream; import java.util.*; @Slf4j @Component public class DocFileDealComp { @Autowired private IDocFilePathService docFilePathService; @Resource DocFilePathMapper filePathMapper; @Resource DocFileMapper docFileMapper; @Autowired private RedisUtil redisUtil; /** * 组织一个树目录节点 * * @param treeNode * @param id * @param filePath * @param nodeNameQueue * @return */ public DocTree insertTreeNode(DocTree treeNode, long id, String filePath, Queue nodeNameQueue, String pathId){ List childrenTreeNodes = treeNode.getChildren(); String currentNodeName = nodeNameQueue.peek(); if (currentNodeName == null){ return treeNode; } QiwenFile qiwenFile = new QiwenFile(filePath, currentNodeName, true); filePath = qiwenFile.getPath(); if (!isExistPath(childrenTreeNodes, currentNodeName)){ //1、判断有没有该子节点,如果没有则插入 //插入 DocTree resultTreeNode = new DocTree(); resultTreeNode.setPath(filePath); resultTreeNode.setTitle(nodeNameQueue.poll()); resultTreeNode.setId(++id); resultTreeNode.setLeaf(true); resultTreeNode.setKey(treeNode.getKey()+"-"+childrenTreeNodes.size()); resultTreeNode.getSlots().setIcon("folder"); resultTreeNode.getScopedSlots().setTitle("custom"); childrenTreeNodes.add(resultTreeNode); }else{ //2、如果有,则跳过 nodeNameQueue.poll(); } if (nodeNameQueue.size() != 0) { for (int i = 0; i < childrenTreeNodes.size(); i++) { DocTree childrenTreeNode = childrenTreeNodes.get(i); if (currentNodeName.equals(childrenTreeNode.getTitle())){ childrenTreeNode = insertTreeNode(childrenTreeNode, id * 10, filePath, nodeNameQueue, pathId); childrenTreeNodes.remove(i); childrenTreeNodes.add(childrenTreeNode); // treeNode.setChildren(childrenTreeNodes); } } }else{ for (int i = 0; i < childrenTreeNodes.size(); i++) { DocTree childrenTreeNode = childrenTreeNodes.get(i); if (currentNodeName.equals(childrenTreeNode.getTitle())){ childrenTreeNode.setPathId(pathId); childrenTreeNodes.remove(i); childrenTreeNodes.add(childrenTreeNode); } } //treeNode.setChildren(childrenTreeNodes); //treeNode.setLeaf(false); } return treeNode; } /** * 判断该路径在树节点中是否已经存在 * @param childrenTreeNodes * @param path * @return */ public boolean isExistPath(List childrenTreeNodes, String path){ boolean isExistPath = false; try { for (int i = 0; i < childrenTreeNodes.size(); i++){ if (path.equals(childrenTreeNodes.get(i).getTitle())){ isExistPath = true; } } }catch (Exception e){ e.printStackTrace(); } return isExistPath; } public boolean isDirExist(String fileName, String filePath, long userId){ LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DocFilePath::getFileName, fileName) .eq(DocFilePath::getFilePath, QiwenFile.formatPath(filePath)) .eq(DocFilePath::getDeleteFlag, Constant.DEL_FALSE) .eq(DocFilePath::getIsDir, Constant.IS_DIR); List list = docFilePathService.list(lambdaQueryWrapper); if (list != null && !list.isEmpty()) { return true; } return false; } /** * 递归遍历树的节点,对节点子节点按key值进行排序 * @param node */ public void sortByKey(DocTree node){ List children = node.getChildren(); Collections.sort(children, (o1, o2) -> { int o1Key = Integer.valueOf(o1.getKey().substring(o1.getKey().lastIndexOf('-'))); int o2Key = Integer.valueOf(o2.getKey().substring(o2.getKey().lastIndexOf('-'))); return o2Key-o1Key; }); for (DocTree child: children) { this.sortByKey(child); } } public void checkLeaf(DocTree node) { List children = node.getChildren(); for (DocTree dt: children) { if(dt.getChildren().size() > 0) { dt.setLeaf(false); } this.checkLeaf(dt); } } /** * 获取重复文件名 * * 场景1: 文件还原时,在 savefilePath 路径下,保存 测试.txt 文件重名,则会生成 测试(1).txt * 场景2: 上传文件时,在 savefilePath 路径下,保存 测试.txt 文件重名,则会生成 测试(1).txt * * @param userFile * @param savefilePath * @return */ public String getRepeatFileName(DocFilePath userFile, String savefilePath) { String fileName = userFile.getFileName(); String extendName = userFile.getExtendName(); Integer deleteFlag = userFile.getDeleteFlag(); int isDir = userFile.getIsDir(); LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.eq(DocFilePath::getFilePath, savefilePath) .eq(DocFilePath::getDeleteFlag, deleteFlag) .eq(DocFilePath::getFileName, fileName) .eq(DocFilePath::getIsDir, isDir); if (userFile.getIsDir() == Constant.IS_NOT_DIR) { lambdaQueryWrapper.eq(DocFilePath::getExtendName, extendName); } List list = filePathMapper.selectList(lambdaQueryWrapper); if (list == null) { return fileName; } if (list.isEmpty()) { return fileName; } int i = 0; while (list != null && !list.isEmpty()) { i++; LambdaQueryWrapper lambdaQueryWrapper1 = new LambdaQueryWrapper<>(); lambdaQueryWrapper1.eq(DocFilePath::getFilePath, savefilePath) .eq(DocFilePath::getDeleteFlag, deleteFlag) .eq(DocFilePath::getFileName, fileName + "(" + i + ")") .eq(DocFilePath::getIsDir, isDir); if (userFile.getIsDir() == Constant.IS_NOT_DIR) { lambdaQueryWrapper1.eq(DocFilePath::getExtendName, extendName); } list = filePathMapper.selectList(lambdaQueryWrapper1); } return fileName + "(" + i + ")"; } /** * 还原父文件路径 *

* 1、回收站文件还原操作会将文件恢复到原来的路径下,当还原文件的时候,如果父目录已经不存在了,则需要把父目录给还原 * 2、上传目录 * * @param * @param childId 文件pathID */ public synchronized void restoreParentFilePath(QiwenFile qiwenFile, String childId) { if (qiwenFile.isFile()) { qiwenFile = qiwenFile.getParentFile(); } while(qiwenFile.getParent() != null) { String fileName = qiwenFile.getName(); String parentFilePath = qiwenFile.getParent(); // QueryWrapper qw = new QueryWrapper<>(); // qw.eq("file_path", parentFilePath).eq("file_name", fileName).eq("delete_flag", Constant.DEL_FALSE).eq("is_dir", Constant.IS_DIR); List userFileList = docFilePathService.getDocFilePathsByPathName(parentFilePath, fileName); String parentId; DocFilePath userFile; if (userFileList.size() == 0) { userFile = PathFileUtil.getDir( parentFilePath, fileName, null); try { userFileList.add(userFile); redisUtil.set(CacheConstant.DOC_FILE_PATH_CACHE+"::"+parentFilePath+':'+fileName,userFileList); filePathMapper.insert(userFile); } catch (Exception e) { // System.out.println("重复:::"); if (e.getMessage().contains("Duplicate entry")) { log.error("重复了!!" + "【" + fileName+"】" + "["+ parentFilePath + "]"); //ignore } else { log.error("异常了"); // log.error(e.getMessage()); } } qiwenFile = new QiwenFile(parentFilePath, true); } else { userFile = userFileList.get(0); qiwenFile = new QiwenFile("/", true); } parentId = userFile.getPathId(); filePathMapper.update(null, new LambdaUpdateWrapper().set(DocFilePath::getParentId,parentId).eq(DocFilePath::getPathId, childId)); childId = userFile.getPathId(); } } /** * 拷贝文件 * 场景:修改的文件被多处引用时,需要重新拷贝一份,然后在新的基础上修改 * @param fileBean * @param userFile * @return */ public String copyFile(DocFile fileBean, DocFilePath userFile) { Copier copier = new LocalStorageCopier(); Downloader downloader = new LocalStorageDownloader(); DownloadFile downloadFile = new DownloadFile(); downloadFile.setFileUrl(fileBean.getFileUrl()); CopyFile copyFile = new CopyFile(); copyFile.setExtendName(userFile.getExtendName()); String fileUrl = copier.copy(downloader.getInputStream(downloadFile), copyFile); if (downloadFile.getOssClient() != null) { downloadFile.getOssClient().shutdown(); } fileBean.setFileUrl(fileUrl); fileBean.setFileId(null); docFileMapper.insert(fileBean); userFile.setFileId(fileBean.getFileId()); userFile.setUpdateTime(DateUtils.getDate()); filePathMapper.updateById(userFile); return fileUrl; } public void saveFileInputStream(String fileUrl, InputStream inputStream) throws IOException { Writer writer1 = new LocalStorageWriter(); WriteFile writeFile = new WriteFile(); writeFile.setFileUrl(fileUrl); int fileSize = inputStream.available(); writeFile.setFileSize(fileSize); writer1.write(inputStream, writeFile); } public String getIdentifierByFile(String fileUrl, int storageType) throws IOException { DownloadFile downloadFile = new DownloadFile(); downloadFile.setFileUrl(fileUrl); InputStream inputStream = new LocalStorageDownloader().getInputStream(downloadFile); String md5Str = DigestUtils.md5Hex(inputStream); return md5Str; } /** * 删除重复的子目录文件 * * 当还原目录的时候,如果其子目录在文件系统中已存在,则还原之后进行去重操作 * @param filePath */ public void deleteRepeatSubDirFile(String filePath) { log.debug("删除子目录:"+filePath); LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.select(DocFilePath::getFileName, DocFilePath::getFilePath) .likeRight(DocFilePath::getFilePath, PathFileUtil.formatLikePath(filePath)) .eq(DocFilePath::getIsDir, Constant.IS_DIR) .eq(DocFilePath::getDeleteFlag, Constant.DEL_FALSE) .groupBy(DocFilePath::getFilePath, DocFilePath::getFileName) .having("count(file_name) >= 2"); List repeatList = docFilePathService.list(lambdaQueryWrapper); for (DocFilePath userFile : repeatList) { LambdaQueryWrapper lambdaQueryWrapper1 = new LambdaQueryWrapper<>(); lambdaQueryWrapper1.eq(DocFilePath::getFilePath, userFile.getFilePath()) .eq(DocFilePath::getFileName, userFile.getFileName()) .eq(DocFilePath::getDeleteFlag, Constant.DEL_FALSE); List userFiles = docFilePathService.list(lambdaQueryWrapper1); for (int i = 0; i < userFiles.size() - 1; i ++) { docFilePathService.removeById(userFiles.get(i).getPathId()); } } } public DocFilePath getParent(String filePath) { QiwenFile qiwenFile = new QiwenFile(filePath, true); DocFilePath parent = docFilePathService.getOne(new LambdaQueryWrapper() .eq(DocFilePath::getFilePath, qiwenFile.getParent()) .eq(DocFilePath::getFileName, qiwenFile.getName()) .eq(DocFilePath::getDeleteFlag, Constant.DEL_FALSE) .eq(DocFilePath::getIsDir, Constant.IS_DIR)); return parent; } /** * 判定是不是有访问权限的祖先节点,如果是前端需要展示该文件 * @param subVisits * @param i * @return */ public boolean isParentsOrChild(Map subVisits, DocFilePath i, boolean visit) { // 遍历权限列表 Iterator iterator = subVisits.keySet().iterator(); while (iterator.hasNext()){ String id = iterator.next(); DocFilePath dfp = subVisits.get(id); if (dfp == null) continue; // 获取有权限的文件全路径 String path = new QiwenFile(dfp.getFilePath(),dfp.getFileName(),true).getPath(); // 判断当前文件是不是有权限文件的子级 if ( i.getFilePath().startsWith( path )) { return true; } // 如果是访问权限,需要判断当前文件是不是有访问权限文件的祖先节点 if (visit && i.isDirectory()) { String curPath = new QiwenFile(i.getFilePath(), i.getFileName(), true).getPath(); if (dfp.getFilePath().startsWith(curPath)){ i.setPermission(true); return true; } } } return false; } /** * 判定是不是有访问权限的祖先节点,如果是前端需要展示该文件 * @param subVisits * @param i * @return */ public boolean isParentsOrChild(Map subVisits, RecoveryFileListVo i, boolean visit) { // 遍历权限列表 Iterator iterator = subVisits.keySet().iterator(); while (iterator.hasNext()){ String id = iterator.next(); DocFilePath dfp = subVisits.get(id); if (dfp == null) continue; // 获取有权限的文件全路径 String path = new QiwenFile(dfp.getFilePath(),dfp.getFileName(),true).getPath(); // 判断当前文件是不是有权限文件的子级 try { if (i.getFilePath().startsWith(path)) { return true; } }catch (Exception e) { e.printStackTrace(); } // 如果是访问权限,需要判断当前文件是不是有访问权限文件的祖先节点 if (visit && i.isDirectory()) { String curPath = new QiwenFile(i.getFilePath(), i.getFileName(), true).getPath(); if (dfp.getFilePath().startsWith(curPath)){ // i.setPermission(true); return true; } } } return false; } }