feat:1.日志管理模块FTP服务替换为本地文件服务2.日志文件列表增加分页

This commit is contained in:
nieziyan 2024-03-21 18:08:11 +08:00
parent c9ee863667
commit 89075bef6d
5 changed files with 132 additions and 169 deletions

View File

@ -6,8 +6,8 @@ import java.util.Comparator;
public class FileComparator implements Comparator<FileDto> { public class FileComparator implements Comparator<FileDto> {
private String field; private final String field;
private String order; private final String order;
public FileComparator(String field, String order) { public FileComparator(String field, String order) {
this.field = field; this.field = field;

View File

@ -2,7 +2,9 @@ package org.jeecg.modules.controller;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.FTPUtil; import org.jeecg.common.util.FTPUtil;
import org.jeecg.modules.base.bizVo.FileVo;
import org.jeecg.modules.entity.FileInfo; import org.jeecg.modules.entity.FileInfo;
import org.jeecg.modules.entity.LogManage; import org.jeecg.modules.entity.LogManage;
import org.jeecg.modules.service.ILogManageService; import org.jeecg.modules.service.ILogManageService;
@ -20,31 +22,24 @@ import java.util.List;
@Api(value = "日志管理", tags = "日志管理") @Api(value = "日志管理", tags = "日志管理")
public class LogManageController { public class LogManageController {
@Autowired
private FTPUtil ftpUtil;
@Autowired @Autowired
private ILogManageService logManageService; private ILogManageService logManageService;
@GetMapping("findFtpFolders") @GetMapping("findFtpFolders")
@ApiOperation(value = "查询日志文件夹树形结构", notes = "查询日志文件夹树形结构") @ApiOperation(value = "查询日志文件夹树形结构", notes = "查询日志文件夹树形结构")
public List<LogManage> findFtpFolders(String workPath) { public List<LogManage> findFtpFolders(String workPath) {
return logManageService.findFtpFolders(workPath); return logManageService.fileTree(workPath);
} }
/**
* 查询目录下文件内容
* @param path
* @return
*/
@GetMapping("findFiles") @GetMapping("findFiles")
@ApiOperation(value = "查询目录下文件内容", notes = "查询目录下文件内容") @ApiOperation(value = "查询目录下文件内容", notes = "查询目录下文件内容")
public List<FileInfo> findFiles(String path) { public Result<?> findFiles(String path, FileVo fileVo) {
return logManageService.findFiles(path); return logManageService.findFiles(path, fileVo);
} }
@PostMapping("downloadFile") @PostMapping("downloadFile")
@ApiOperation(value = "ftp文件下载", notes = "ftp文件下载") @ApiOperation(value = "ftp文件下载", notes = "ftp文件下载")
public void downloadFile(String localPath, String fileName, HttpServletResponse response) { public void downloadFile(String localPath, HttpServletResponse response) {
ftpUtil.downloadFTPFile(localPath, response); logManageService.downloadFile(localPath, response);
} }
} }

View File

@ -1,24 +1,24 @@
package org.jeecg.modules.service; package org.jeecg.modules.service;
import org.jeecg.common.api.vo.Result;
import org.jeecg.modules.base.bizVo.FileVo;
import org.jeecg.modules.entity.FileInfo; import org.jeecg.modules.entity.FileInfo;
import org.jeecg.modules.entity.LogManage; import org.jeecg.modules.entity.LogManage;
import javax.servlet.http.HttpServletResponse;
import java.util.List; import java.util.List;
public interface ILogManageService { public interface ILogManageService {
/** /**
* 查询日志文件夹树形结构 * 查询日志文件夹树形结构
* @param workPath
* @return
*/ */
List<LogManage> findFtpFolders(String workPath); List<LogManage> fileTree(String workPath);
/** /**
* 查询目录下文件内容 * 查询目录下文件内容
* @param path
* @return
*/ */
List<FileInfo> findFiles(String path); Result<?> findFiles(String path, FileVo fileVo);
void downloadFile(String localPath, HttpServletResponse response);
} }

View File

@ -1,192 +1,159 @@
package org.jeecg.modules.service.impl; package org.jeecg.modules.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool; import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.net.ftp.FTPClient; import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile; import org.apache.commons.net.ftp.FTPFile;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.Prompt;
import org.jeecg.common.properties.SpectrumPathProperties;
import org.jeecg.common.util.DateUtils; import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.FTPUtil; import org.jeecg.common.util.ExportUtil;
import org.jeecg.common.util.PageUtil;
import org.jeecg.modules.base.bizVo.FileVo;
import org.jeecg.modules.entity.FileInfo; import org.jeecg.modules.entity.FileInfo;
import org.jeecg.modules.entity.LogManage; import org.jeecg.modules.entity.LogManage;
import org.jeecg.modules.service.ILogManageService; import org.jeecg.modules.service.ILogManageService;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.*; import java.util.*;
import java.util.stream.Collectors;
@Service("logManageService") @Slf4j
@Service
public class LogManageServiceImpl implements ILogManageService { public class LogManageServiceImpl implements ILogManageService {
@Autowired @Autowired
private FTPUtil ftpUtil; private SpectrumPathProperties spectrumPath;
@Override @Override
public List<LogManage> findFtpFolders(String workPath) { public List<LogManage> fileTree(String workPath) {
List<LogManage> result = new ArrayList<>(); List<LogManage> result = new ArrayList<>();
FTPClient ftpClient = ftpUtil.LoginFTP(); workPath = spectrumPath.getRootPath() + StringPool.SLASH + workPath;
if(Objects.isNull(ftpClient)){ List<File> files = ListUtil.toList(FileUtil.ls(workPath));
throw new RuntimeException("ftp connection failed!"); if (CollUtil.isEmpty(files)) return result;
int num = 1;
for (File file : files) {
LogManage logManage = new LogManage();
logManage.setName(file.getName());
logManage.setOrderNum(num++);
logManage.setPath(workPath + StringPool.SLASH + file.getName());
List<LogManage> children = this.getChildren(logManage);
logManage.setHashChild(CollUtil.isNotEmpty(children));
logManage.setChildren(children);
result.add(logManage);
} }
try {
//切换被动模式
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
// 设置编码当文件中存在中文且上传后文件乱码时可使用此配置项
ftpClient.setControlEncoding("UTF-8");
ftpClient.setFileTransferMode(FTPClient.STREAM_TRANSFER_MODE);
//切换工作文件路径
workPath = ftpUtil.getFtpRootPath()+StringPool.SLASH+workPath;
ftpClient.changeWorkingDirectory(workPath);
List<FTPFile> ftpFiles = Arrays.asList(ftpClient.listDirectories());
if (CollectionUtils.isNotEmpty(ftpFiles)){
int num =1;
for (FTPFile ftpFile:ftpFiles) {
LogManage logManage = new LogManage();
logManage.setName(ftpFile.getName());
logManage.setOrderNum(num);
logManage.setParentNum(0);
logManage.setPath(workPath + StringPool.SLASH + ftpFile.getName());
result.add(logManage);
num++;
}
}
if (CollectionUtils.isNotEmpty(result)){
List<LogManage> list = new LinkedList<>();
for (LogManage logManage:result) {
list = this.findDirectory(ftpClient, list, logManage.getOrderNum(), workPath + StringPool.SLASH + logManage.getName() , logManage.getName());
ftpClient.changeToParentDirectory();
}
result.addAll(list);
}
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
try {
if (ftpClient != null){
ftpClient.disconnect();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
result = this.LogManageTree(result);
return result; return result;
} }
@Override @Override
public List<FileInfo> findFiles(String path) { public Result<?> findFiles(String path, FileVo fileVo) {
List<FileInfo> result = new ArrayList<>(); String name = fileVo.getName();
FTPClient ftpClient = ftpUtil.LoginFTP(); Integer pageNo = fileVo.getPageNo();
if (Objects.isNull(ftpClient)){ Integer pageSize = fileVo.getPageSize();
throw new RuntimeException("ftp connection failed!"); Page<FileInfo> page = new Page<>(pageNo, pageSize);
List<File> files = CollUtil.toList(FileUtil.ls(path));
// 文件名过滤
if (StrUtil.isNotBlank(name))
files = files.stream().filter(file -> StrUtil.containsIgnoreCase(file.getName(), name))
.collect(Collectors.toList());
page.setTotal(files.size());
// 分页
files = PageUtil.page(pageNo, pageSize, files);
List<FileInfo> records = new ArrayList<>();
for (File file : files) {
if (FileUtil.isDirectory(file)) continue;
FileInfo fileInfo = new FileInfo();
fileInfo.setFileName(file.getName());
fileInfo.setFilePath(path + StringPool.SLASH + file.getName());
fileInfo.setFileSize(FileUtil.readableFileSize(file));
fileInfo.setFileDate(DateUtil.formatDateTime(FileUtil.lastModifiedTime(file)));
records.add(fileInfo);
} }
page.setRecords(records);
return Result.OK(page);
}
@Override
public void downloadFile(String localPath, HttpServletResponse response) {
OutputStream outputStream = null;
InputStream inputStream = null;
try { try {
//切换被动模式 // 如果是目录 则直接退出方法
ftpClient.enterLocalPassiveMode(); if (FileUtil.isDirectory(localPath)) return;
ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);
// 设置编码当文件中存在中文且上传后文件乱码时可使用此配置项 // 判断是否存在此文件
ftpClient.setControlEncoding("UTF-8"); if (!FileUtil.exist(localPath)) return;
ftpClient.setFileTransferMode(FTPClient.STREAM_TRANSFER_MODE);
//切换工作文件路径 // 获取文件名
ftpClient.changeWorkingDirectory(path); String fileName = FileUtil.getName(localPath);
List<FTPFile> ftpFiles = Arrays.asList(ftpClient.listFiles());
if (CollectionUtils.isNotEmpty(ftpFiles)){ inputStream = FileUtil.getInputStream(localPath);
for (FTPFile ftpFile:ftpFiles) { outputStream = ExportUtil.stream(response, fileName);
if (ftpFile.isFile()){
FileInfo fileInfo = new FileInfo(); // 缓冲区大小
fileInfo.setFileName(ftpFile.getName()); byte[] buffer = new byte[4096];
fileInfo.setFilePath(path + StringPool.SLASH + ftpFile.getName()); int bytesRead;
fileInfo.setFileSize(String.format("%.2f", Double.valueOf(Double.valueOf(ftpFile.getSize())/1024)) + "KB");
fileInfo.setFileDate(DateUtils.formatDate(ftpFile.getTimestamp(),"yyyy-MM-dd")); // 将文件输出流写入到输出流中
result.add(fileInfo); while ((bytesRead = inputStream.read(buffer)) != -1) {
} outputStream.write(buffer, 0, bytesRead);
}
} }
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); log.error("文件{}下载失败 :{}", localPath, e.getMessage());
} finally { } finally {
try { try {
if (ftpClient != null){ if (ObjectUtil.isNotNull(inputStream))inputStream.close();
ftpClient.disconnect(); if (ObjectUtil.isNotNull(outputStream))outputStream.close();
}
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException(e); e.printStackTrace();
} }
} }
return result;
} }
/** /**
* 遍历查询当前路径下的文件夹信息 * 获取当前目录节点所有子孙节点Tree
* @param ftpClient
* @param list
* @param filePath "/"开始和结束
* @return
*/ */
public List<LogManage> findDirectory(FTPClient ftpClient, List<LogManage> list, Integer parentNum, String filePath, String fileName){ private List<LogManage> getChildren(LogManage parent){
try {
//切换被动模式
ftpClient.enterLocalPassiveMode();
ftpClient.changeWorkingDirectory(fileName);
List<FTPFile> ftpFiles = Arrays.asList(ftpClient.listDirectories());
if (CollectionUtils.isNotEmpty(ftpFiles)){
int num = 1;
for (FTPFile file : ftpFiles) {
if (file.isDirectory()) {
LogManage logManage = new LogManage();
logManage.setName(file.getName());
logManage.setOrderNum(parentNum*10+num);
logManage.setParentNum(parentNum);
logManage.setPath(filePath + StringPool.SLASH + file.getName());
list.add(logManage);
// 需要加此判断否则ftp默认将项目文件所在目录之下的目录./项目文件所在目录向上一级目录下的目录../都纳入递归这样下去就陷入一个死循环了需将其过滤掉
if (!".".equals(file.getName()) && !"..".equals(file.getName())) {
findDirectory(ftpClient, list, parentNum*10+num, filePath + StringPool.SLASH + file.getName(), file.getName());
ftpClient.changeToParentDirectory();
}
num++;
}
}
}
} catch (IOException e) {
throw new RuntimeException(e);
}
return list;
}
/**
* 将当前的文件夹转换成树形结构
* @param logManages
* @return
*/
public List<LogManage> LogManageTree(List<LogManage> logManages){
if (logManages == null) {
return null;
}
List<LogManage> result = new LinkedList<>(); List<LogManage> result = new LinkedList<>();
Integer TOP_NODE_ID = 0; String parentPath = parent.getPath();
logManages.forEach(logManage -> { // 如果是文件 则直接返回空集合
Integer pid = logManage.getParentNum(); if (FileUtil.isFile(parentPath)) return result;
if (pid == null || TOP_NODE_ID.equals(pid)) { List<File> files = ListUtil.toList(FileUtil.ls(parentPath));
result.add(logManage); // 如果当前目录不存在子文件 则返回空集合
return; if (CollUtil.isEmpty(files)) return result;
} int parentOrderNum = parent.getOrderNum();
for (LogManage manage : logManages) { int num = parentOrderNum * 10 + 1;
Integer id = manage.getOrderNum(); for (File file : files) {
if (id != null && id.equals(pid)) { // 过滤掉文件 只收集目录
if (manage.getChildren() == null) { if (FileUtil.isFile(file)) continue;
manage.initChildren(); LogManage logManage = new LogManage();
} logManage.setName(file.getName());
logManage.setHashParent(true); logManage.setOrderNum(num++);
manage.getChildren().add(logManage); logManage.setHashParent(true);
manage.setHashChild(true); logManage.setParentNum(parentOrderNum);
return; logManage.setPath(parentPath + StringPool.SLASH + file.getName());
} List<LogManage> children = getChildren(logManage);
} logManage.setHashChild(CollUtil.isNotEmpty(children));
}); logManage.setChildren(children);
result.add(logManage);
}
return result; return result;
} }
} }

View File

@ -15,4 +15,5 @@ spring:
config: config:
import: import:
- optional:nacos:armd.yaml - optional:nacos:armd.yaml
- optional:nacos:armd-@profile.name@.yaml - optional:nacos:armd-@profile.name@.yaml
- optional:nacos:armd-analysis-@profile.name@.yaml