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<String> nodeNameQueue, String pathId){
|
List<DocTree> 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<DocTree> 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<DocFilePath> 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<DocFilePath> list = docFilePathService.list(lambdaQueryWrapper);
|
if (list != null && !list.isEmpty()) {
|
return true;
|
}
|
return false;
|
}
|
|
/**
|
* 递归遍历树的节点,对节点子节点按key值进行排序
|
* @param node
|
*/
|
public void sortByKey(DocTree node){
|
List<DocTree> 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<DocTree> 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<DocFilePath> 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<DocFilePath> list = filePathMapper.selectList(lambdaQueryWrapper);
|
if (list == null) {
|
return fileName;
|
}
|
if (list.isEmpty()) {
|
return fileName;
|
}
|
int i = 0;
|
|
while (list != null && !list.isEmpty()) {
|
i++;
|
LambdaQueryWrapper<DocFilePath> 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 + ")";
|
|
}
|
|
/**
|
* 还原父文件路径
|
* <p>
|
* 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<DocFilePath> 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<DocFilePath> 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<DocFilePath>().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<DocFilePath> 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<DocFilePath> repeatList = docFilePathService.list(lambdaQueryWrapper);
|
|
for (DocFilePath userFile : repeatList) {
|
LambdaQueryWrapper<DocFilePath> lambdaQueryWrapper1 = new LambdaQueryWrapper<>();
|
lambdaQueryWrapper1.eq(DocFilePath::getFilePath, userFile.getFilePath())
|
.eq(DocFilePath::getFileName, userFile.getFileName())
|
.eq(DocFilePath::getDeleteFlag, Constant.DEL_FALSE);
|
List<DocFilePath> 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<DocFilePath>()
|
.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<String,DocFilePath> subVisits, DocFilePath i, boolean visit) {
|
// 遍历权限列表
|
Iterator<String> 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<String,DocFilePath> subVisits, RecoveryFileListVo i, boolean visit) {
|
// 遍历权限列表
|
Iterator<String> 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;
|
}
|
}
|