提交代码

This commit is contained in:
jiang 2024-11-20 09:47:52 +08:00
parent 47cc8679b0
commit 202448fc38
7 changed files with 759 additions and 67 deletions

View File

@ -2,6 +2,8 @@ package com.bonus.ai.controller;
import com.bonus.ai.domain.DataSetBasicFileEntity;
import com.bonus.ai.service.DataSetBasicFileService;
import com.bonus.common.core.constant.HttpStatus;
import com.bonus.common.core.utils.Base64Utils;
import com.bonus.common.core.utils.poi.ExcelUtil;
import com.bonus.common.core.web.controller.BaseController;
import com.bonus.common.core.web.domain.AjaxResult;
@ -9,11 +11,16 @@ import com.bonus.common.core.web.page.TableDataInfo;
import com.bonus.common.log.annotation.SysLog;
import com.bonus.common.log.enums.OperaType;
import com.bonus.common.security.annotation.RequiresPermissions;
import org.aspectj.weaver.loadtime.Aj;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
@ -42,6 +49,44 @@ public class DataSetBasicFileController extends BaseController
List<DataSetBasicFileEntity> list = dataSetBasicFileService.selectDataSetBasicFileList(entity);
return getDataTable(list);
}catch (Exception e){
e.printStackTrace();
return getDataTable(new ArrayList<>());
}
}
/**
* 查询文件基础列表
*/
@RequiresPermissions("dataCenter:dataSetBasicFile:list")
@GetMapping("/delList")
public TableDataInfo delList(DataSetBasicFileEntity entity)
{
try {
startPage();
List<DataSetBasicFileEntity> list = dataSetBasicFileService.selectDataSetBasicDelFileList(entity);
return getDataTable(list);
}catch (Exception e){
e.printStackTrace();
return getDataTable(new ArrayList<>());
}
}
/**
* 查询文件基础列表
*/
@RequiresPermissions("dataCenter:dataSetBasicFile:isPublicList")
@GetMapping("/isPublicList")
public TableDataInfo isPublicList(DataSetBasicFileEntity entity)
{
try {
startPage();
List<DataSetBasicFileEntity> list = dataSetBasicFileService.selectDataSetBasicFileIsPublicList(entity);
return getDataTable(list);
}catch (Exception e){
e.printStackTrace();
return getDataTable(new ArrayList<>());
}
@ -103,6 +148,27 @@ public class DataSetBasicFileController extends BaseController
return dataSetBasicFileService.deleteDataSetBasicFileByFileIds(fileIds);
}
/**
* 删除文件基础
*/
@RequiresPermissions("dataCenter:dataSetBasicFile:dataRecovery")
@PostMapping("/dataRecovery/{fileIds}")
@SysLog(title = "文件基础", businessType = OperaType.DELETE,logType = 0,module = "文件基础",details = "导出文件基础列表")
public AjaxResult dataRecoveryFileByFileIds(@PathVariable Long[] fileIds)
{
return dataSetBasicFileService.dataRecoveryFileByFileIds(fileIds);
}
/**
* 文件上传
* @param file 文件流
* @param filename 文件名称
* @param chunk 分片序号
* @param totalChunks 总分片
* @param parentId 父类id
* @param fileUrl 文件地址
* @return 是否成功
*/
@PostMapping("/uploadFiles")
@SysLog(title = "文件基础", businessType = OperaType.DELETE,logType = 0,module = "文件基础",details = "导出文件基础列表")
@ -117,4 +183,41 @@ public class DataSetBasicFileController extends BaseController
return dataSetBasicFileService.uploadDataSetBasicFiles(file,filename,chunk,totalChunks,parentId,fileUrl);
}
/**
* 文件下载
* @param response 请求
* @param fileIds 文件id
*/
@PostMapping("/download/{fileIds}")
public void downloadFile(HttpServletResponse response, HttpServletRequest request, @PathVariable Long[] fileIds) {
dataSetBasicFileService.downloadFile(response,request,fileIds);
}
/**
* 批量修改文件共享状态
* @param fileIds 文件id
*/
@PostMapping("/sharedFilesByIds/{fileIds}")
public AjaxResult sharedFilesByIds(@PathVariable Long[] fileIds) {
return dataSetBasicFileService.sharedFilesByIds(fileIds);
}
/**
* 修改单个文件共享状态
* @param entity 实体
*/
@PostMapping("/changeIsPublic")
public AjaxResult changeIsPublic(@RequestBody DataSetBasicFileEntity entity) {
return dataSetBasicFileService.changeIsPublic(entity);
}
/**
* 获取文件树型结构
* @return
*/
@PostMapping("/getFileTerr")
public AjaxResult getFileTerr(){
return dataSetBasicFileService.getFileTerr();
}
}

View File

@ -1,6 +1,7 @@
package com.bonus.ai.domain;
import com.bonus.common.core.web.domain.BaseEntity;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
@ -39,7 +40,7 @@ public class DataSetBasicFileEntity extends BaseEntity {
* 文件大小以字符串形式存储文件的大小信息
* 通常用于显示文件的大小例如"15MB"
*/
private String fileSize;
private Long fileSize;
/**
* 是否是文件夹的标识

View File

@ -1,8 +1,10 @@
package com.bonus.ai.mapper;
import com.bonus.ai.domain.DataSetBasicFileEntity;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Set;
/**
* 文件基础Mapper接口
@ -20,6 +22,14 @@ public interface DataSetBasicFileMapper
*/
public DataSetBasicFileEntity selectDataSetBasicFileByFileId(Long fileId);
/**
* 查询文件基础
*
* @param parentId 文件基础主键
* @return 文件基础
*/
public List<DataSetBasicFileEntity> selectDataSetBasicFileByParentId(Long parentId);
/**
* 查询文件基础列表
*
@ -28,6 +38,22 @@ public interface DataSetBasicFileMapper
*/
public List<DataSetBasicFileEntity> selectDataSetBasicFileList(DataSetBasicFileEntity entity);
/**
* 查询共享文件
*
* @param entity 文件基础
* @return 文件基础集合
*/
public List<DataSetBasicFileEntity> selectDataSetBasicFileIsPublicList(DataSetBasicFileEntity entity);
/**
* 获取删除文件列表
*
* @param entity 文件基础
* @return 文件基础集合
*/
public List<DataSetBasicFileEntity> selectDataSetBasicDelFileList(DataSetBasicFileEntity entity);
/**
* 新增文件基础
*
@ -51,4 +77,18 @@ public interface DataSetBasicFileMapper
* @return 结果
*/
public int deleteDataSetBasicFileByFileIds(Long[] fileIds);
/**
* 批量删除文件基础
*
* @param fileIds 需要删除的数据主键集合
* @return 结果
*/
public int dataRecoveryFileByFileIds(Long[] fileIds);
/**
* 修改文件共享状态
* @param ancestors
*/
void updateSharedFilesByIds(@Param("ancestors")Set<Long> ancestors ,@Param("isPublic") String isPublic);
}

View File

@ -4,6 +4,8 @@ import com.bonus.ai.domain.DataSetBasicFileEntity;
import com.bonus.common.core.web.domain.AjaxResult;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@ -30,6 +32,21 @@ public interface DataSetBasicFileService
*/
public List<DataSetBasicFileEntity> selectDataSetBasicFileList(DataSetBasicFileEntity entity);
/**
* 查询共享文件
*
* @param entity 文件基础
* @return 文件基础集合
*/
public List<DataSetBasicFileEntity> selectDataSetBasicFileIsPublicList(DataSetBasicFileEntity entity);
/**
* 删除文件列表
*
* @param entity 文件基础
* @return 文件基础集合
*/
public List<DataSetBasicFileEntity> selectDataSetBasicDelFileList(DataSetBasicFileEntity entity);
/**
* 新增文件基础
*
@ -53,6 +70,13 @@ public interface DataSetBasicFileService
* @return 结果
*/
public AjaxResult deleteDataSetBasicFileByFileIds(Long[] fileIds);
/**
* 还原数据
*
* @param fileIds 需要删除的文件基础主键集合
* @return 结果
*/
public AjaxResult dataRecoveryFileByFileIds(Long[] fileIds);
/**
* 文件分片上传
@ -63,4 +87,29 @@ public interface DataSetBasicFileService
* @return
*/
AjaxResult uploadDataSetBasicFiles(MultipartFile file, String filename, int chunk, int totalChunks,String parentId, String fileUrl);
/**
* 下载文件
* @param response
* @param fileIds
*/
void downloadFile(HttpServletResponse response, HttpServletRequest request, Long[] fileIds);
/**
* 共享文件
* @param fileIds 文件id
*/
AjaxResult sharedFilesByIds(Long[] fileIds);
/**
* 修改单个文件的共享状态
* @param entity 实体
*/
AjaxResult changeIsPublic(DataSetBasicFileEntity entity);
/**
* 获取树形结构
* @return
*/
AjaxResult getFileTerr();
}

View File

@ -1,24 +1,31 @@
package com.bonus.ai.service.Impl;
import java.io.IOException;
import java.util.List;
import com.bonus.ai.domain.DataSetBasicFileEntity;
import com.bonus.ai.domain.TreeNode;
import com.bonus.ai.mapper.DataSetBasicFileMapper;
import com.bonus.ai.service.DataSetBasicFileService;
import com.bonus.ai.utils.MinioUtil;
import com.bonus.common.core.utils.DateUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.domain.SysFile;
import io.minio.PutObjectArgs;
import io.minio.Result;
import io.minio.errors.MinioException;
import io.minio.messages.Item;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Files;
import java.util.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/**
* 文件基础Service业务层处理
@ -27,13 +34,14 @@ import javax.annotation.Resource;
* @date 2024-11-14
*/
@Service
public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
{
public class DataSetBasicFileServiceImpl implements DataSetBasicFileService {
@Resource
private DataSetBasicFileMapper dataSetBasicFileMapper;
@Resource
private MinioUtil minioUtil;
/**
* 查询文件基础
*
@ -41,16 +49,15 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
* @return 文件基础
*/
@Override
public AjaxResult selectDataSetBasicFileByFileId(Long fileId)
{
public AjaxResult selectDataSetBasicFileByFileId(Long fileId) {
try {
DataSetBasicFileEntity aiBasicFile =dataSetBasicFileMapper.selectDataSetBasicFileByFileId(fileId);
DataSetBasicFileEntity aiBasicFile = dataSetBasicFileMapper.selectDataSetBasicFileByFileId(fileId);
if (ObjectUtils.isEmpty(aiBasicFile)) {
return AjaxResult.error();
}else {
} else {
return AjaxResult.success();
}
}catch (Exception e){
} catch (Exception e) {
return AjaxResult.error();
}
}
@ -62,11 +69,34 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
* @return 文件基础
*/
@Override
public List<DataSetBasicFileEntity> selectDataSetBasicFileList(DataSetBasicFileEntity aiBasicFile)
{
public List<DataSetBasicFileEntity> selectDataSetBasicFileList(DataSetBasicFileEntity aiBasicFile) {
aiBasicFile.setCreateBy(SecurityUtils.getUserId().toString());
return dataSetBasicFileMapper.selectDataSetBasicFileList(aiBasicFile);
}
/**
* 查询共享文件
*
* @param entity 文件基础
* @return 文件基础集合
*/
@Override
public List<DataSetBasicFileEntity> selectDataSetBasicFileIsPublicList(DataSetBasicFileEntity entity) {
return dataSetBasicFileMapper.selectDataSetBasicFileIsPublicList(entity);
}
/**
* 查询文件基础列表
*
* @param aiBasicFile 文件基础
* @return 文件基础
*/
@Override
public List<DataSetBasicFileEntity> selectDataSetBasicDelFileList(DataSetBasicFileEntity aiBasicFile) {
aiBasicFile.setCreateBy(SecurityUtils.getUserId().toString());
return dataSetBasicFileMapper.selectDataSetBasicDelFileList(aiBasicFile);
}
/**
* 新增文件基础
*
@ -74,13 +104,15 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
* @return 结果
*/
@Override
public AjaxResult insertDataSetBasicFile(DataSetBasicFileEntity aiBasicFile)
{
public AjaxResult insertDataSetBasicFile(DataSetBasicFileEntity aiBasicFile) {
aiBasicFile.setCreateTime(DateUtils.getNowDate());
try{
int rows = dataSetBasicFileMapper.insertDataSetBasicFile(aiBasicFile);
return rows>0?AjaxResult.success():AjaxResult.error();
}catch (Exception e){
aiBasicFile.setCreateBy(SecurityUtils.getUserId().toString());
aiBasicFile.setFileUrl(minioUtil.joinPath(SecurityUtils.getUserId().toString(), aiBasicFile.getFileUrl()));
aiBasicFile.setFileUrl(minioUtil.joinPath(aiBasicFile.getFileUrl(), aiBasicFile.getFileName()));
try {
int rows = dataSetBasicFileMapper.insertDataSetBasicFile(aiBasicFile);
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
} catch (Exception e) {
return AjaxResult.error();
}
}
@ -92,13 +124,12 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
* @return 结果
*/
@Override
public AjaxResult updateDataSetBasicFile(DataSetBasicFileEntity aiBasicFile)
{
public AjaxResult updateDataSetBasicFile(DataSetBasicFileEntity aiBasicFile) {
aiBasicFile.setUpdateTime(DateUtils.getNowDate());
try{
int rows = dataSetBasicFileMapper.updateDataSetBasicFile(aiBasicFile);
return rows>0?AjaxResult.success():AjaxResult.error();
}catch (Exception e){
try {
int rows = dataSetBasicFileMapper.updateDataSetBasicFile(aiBasicFile);
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
} catch (Exception e) {
return AjaxResult.error();
}
}
@ -110,12 +141,27 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
* @return 结果
*/
@Override
public AjaxResult deleteDataSetBasicFileByFileIds(Long[] fileIds)
{
try{
int rows = dataSetBasicFileMapper.deleteDataSetBasicFileByFileIds(fileIds);
return rows>0?AjaxResult.success():AjaxResult.error();
}catch (Exception e){
public AjaxResult deleteDataSetBasicFileByFileIds(Long[] fileIds) {
try {
int rows = dataSetBasicFileMapper.deleteDataSetBasicFileByFileIds(fileIds);
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
} catch (Exception e) {
return AjaxResult.error();
}
}
/**
* 批量删除文件基础
*
* @param fileIds 需要删除的文件基础主键
* @return 结果
*/
@Override
public AjaxResult dataRecoveryFileByFileIds(Long[] fileIds) {
try {
int rows = dataSetBasicFileMapper.dataRecoveryFileByFileIds(fileIds);
return rows > 0 ? AjaxResult.success() : AjaxResult.error();
} catch (Exception e) {
return AjaxResult.error();
}
}
@ -133,16 +179,402 @@ public class DataSetBasicFileServiceImpl implements DataSetBasicFileService
public AjaxResult uploadDataSetBasicFiles(MultipartFile file, String filename, int chunk, int totalChunks, String parentId, String fileUrl) {
try {
// 使用唯一路径保存分片到 MinIO
String objectName = SecurityUtils.getUserId().toString()+"/temp/"+filename+"/chunk_" + chunk;
String objectName = SecurityUtils.getUserId().toString() + "/temp/" + filename + "/chunk_" + chunk;
minioUtil.uploadFile(file, objectName);
// 检查是否是最后一个分片若是则合并
if (chunk == totalChunks) {
SysFile sysFile = minioUtil.mergeChunks(filename, totalChunks, minioUtil.joinPath(SecurityUtils.getUserId().toString(),fileUrl));
DataSetBasicFileEntity entity = minioUtil.mergeChunks(filename, totalChunks, minioUtil.joinPath(SecurityUtils.getUserId().toString(), fileUrl));
entity.setCreateBy(SecurityUtils.getUserId().toString());
entity.setCreateTime(DateUtils.getNowDate());
entity.setIsDirectory("0");
entity.setParentId(Long.valueOf(parentId));
dataSetBasicFileMapper.insertDataSetBasicFile(entity);
}
return AjaxResult.success();
} catch (Exception e) {
return AjaxResult.error();
e.printStackTrace();
return AjaxResult.error();
}
}
/**
* 下载文件
*
* @param response 请求
* @param fileIds 文件id
*/
@Override
public void downloadFile(HttpServletResponse response, HttpServletRequest request, Long[] fileIds) {
try {
// 获取文件信息列表
List<DataSetBasicFileEntity> list = getFilesByIds(fileIds);
boolean exists = list.stream().anyMatch(file -> "1".equals(file.getIsDirectory()));
// 如果文件列表中只有一个文件
if (list.size() == 1 && !exists) {
// 下载单个文件
downloadSingleFile(response, request, list.get(0));
} else {
// 下载多个文件可能需要压缩成一个文件
downloadMultipleFiles(response, list);
}
} catch (MinioException | IOException e) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
// 记录异常控制台或日志中
e.printStackTrace();
}
}
/**
* 共享文件
*
* @param fileIds 文件id
*/
@Override
public AjaxResult sharedFilesByIds(Long[] fileIds) {
List<DataSetBasicFileEntity> list = getFilesByIds(fileIds);
for (DataSetBasicFileEntity entity :list){
if ("1".equals(entity.getIsDirectory())){
for (Long fileId : fileIds) {
Set<Long> ancestors = getAncestorsByFileIds(fileId);
Set<Long> children = getFileWithChildren(fileId);
ancestors.addAll(children);
ancestors.add(fileId);
dataSetBasicFileMapper.updateSharedFilesByIds(ancestors,"1");
}
}else {
for (Long fileId : fileIds) {
Set<Long> ancestors = getAncestorsByFileIds(fileId);
ancestors.add(fileId);
dataSetBasicFileMapper.updateSharedFilesByIds(ancestors,"1");
}
}
}
return AjaxResult.success();
}
/**
* 修改单个文件的共享状态
*
* @param entity 实体
*/
@Override
public AjaxResult changeIsPublic(DataSetBasicFileEntity entity) {
DataSetBasicFileEntity file = dataSetBasicFileMapper.selectDataSetBasicFileByFileId(entity.getFileId());
if ("1".equals(file.getIsDirectory())){
Set<Long> ancestors = getAncestorsByFileIds(entity.getFileId());
Set<Long> children = getFileWithChildren(entity.getFileId());
children.add(entity.getFileId());
dataSetBasicFileMapper.updateSharedFilesByIds(children,entity.getIsPublic());
Set<Long> isPublic = getIsPublic(ancestors);
if (!isPublic.isEmpty()){
dataSetBasicFileMapper.updateSharedFilesByIds(isPublic,entity.getIsPublic());
}
}else {
Set<Long> fileId = new HashSet<>();
fileId.add(entity.getFileId());
Set<Long> ancestors = getAncestorsByFileIds(entity.getFileId());
fileId.addAll(ancestors);
dataSetBasicFileMapper.updateSharedFilesByIds(fileId,entity.getIsPublic());
Set<Long> isPublic = getIsPublic(ancestors);
if (!isPublic.isEmpty()){
dataSetBasicFileMapper.updateSharedFilesByIds(isPublic,entity.getIsPublic());
}
}
return null;
}
/**
* 获取树形结构
*
* @return
*/
@Override
public AjaxResult getFileTerr() {
DataSetBasicFileEntity entity = new DataSetBasicFileEntity();
entity.setIsDirectory("1");
entity.setCreateBy(SecurityUtils.getUserId().toString());
List<DataSetBasicFileEntity> allFiles = dataSetBasicFileMapper.selectDataSetBasicFileList(entity);
return AjaxResult.success(allFiles);
}
/**
* 递归树形结构
* @param allFiles
* @param parentId
* @return
*/
private List<TreeNode> buildTree(List<DataSetBasicFileEntity> allFiles, Long parentId) {
List<TreeNode> result = new ArrayList<>();
for (DataSetBasicFileEntity entity : allFiles) {
// 判断当前节点的 parentId 是否与给定的 parentId 相等
if (entity.getParentId().equals(parentId) && "1".equals(entity.getIsDirectory())) {
// 将当前实体转换成 TreeNode
TreeNode node = new TreeNode();
node.setId(entity.getFileId());
node.setLabel(entity.getFileName());
node.setParentId(entity.getParentId());
// 递归查找当前节点的子节点
node.setChildren(buildTree(allFiles, entity.getFileId()));
// 将该节点添加到结果列表中
result.add(node);
}
}
return result;
}
/**
* 获取同级目录是否是否存在共享数据
* @return
*/
public Set<Long> getIsPublic(Set<Long> ancestors){
// Set 转换为 List
List<Long> ancestorList = new ArrayList<>(ancestors);
Set<Long> isPublic = new HashSet<>();
for (int i = ancestorList.size() - 1; i >= 0; i--) {
List<DataSetBasicFileEntity> list = dataSetBasicFileMapper.selectDataSetBasicFileByParentId(ancestorList.get(i));
boolean exists = list.stream().anyMatch(file -> "1".equals(file.getIsPublic()));
if (exists){
return isPublic;
}else {
isPublic.add(ancestorList.get(i));
}
}
return isPublic;
}
/**
* 获取文件及其子节点
* @param fileId 文件 ID
* @return 当前文件及其所有子节点
*/
public Set<Long> getFileWithChildren(Long fileId) {
// 查询所有文件数据假设你已经根据需求修改了查询方法
DataSetBasicFileEntity entity =new DataSetBasicFileEntity();
entity.setCreateBy(SecurityUtils.getUserId().toString());
List<DataSetBasicFileEntity> allFiles = dataSetBasicFileMapper.selectDataSetBasicFileList(entity);
// 构建父子关系映射
Map<Long, List<Long>> parentToChildrenMap = new HashMap<>();
for (DataSetBasicFileEntity file : allFiles) {
parentToChildrenMap
.computeIfAbsent(file.getParentId(), k -> new ArrayList<>())
.add(file.getFileId());
}
// 使用递归或迭代方式获取所有子节点
Set<Long> childIds = new HashSet<>();
collectChildren(fileId, parentToChildrenMap, childIds);
return childIds;
}
private void collectChildren(Long parentId, Map<Long, List<Long>> parentToChildrenMap, Set<Long> childIds) {
// 获取当前父节点的所有子节点
List<Long> children = parentToChildrenMap.get(parentId);
if (children != null) {
for (Long childId : children) {
// 将当前子节点 ID 添加到结果集中
childIds.add(childId);
// 递归获取子节点的子节点
collectChildren(childId, parentToChildrenMap, childIds);
}
}
}
/**
* 根据多个 fileId 查询所有祖先节点
* @param fileId 起始节点 ID
* @return 每个文件对应的祖先节点列表 Map
*/
public Set<Long> getAncestorsByFileIds(Long fileId) {
Set<Long> ancestors = new HashSet<>();
Long currentId = fileId;
while (currentId != null && currentId != 0) {
DataSetBasicFileEntity entity = dataSetBasicFileMapper.selectDataSetBasicFileByFileId(currentId);
if (entity == null) {
break; // 没有更多父节点
}
ancestors.add(entity.getParentId());
// 更新当前节点为父节点
currentId = entity.getParentId();
}
return ancestors;
}
// 获取文件信息
private List<DataSetBasicFileEntity> getFilesByIds(Long[] fileIds) {
List<DataSetBasicFileEntity> list = new ArrayList<>();
for (long fileId : fileIds) {
DataSetBasicFileEntity entity = dataSetBasicFileMapper.selectDataSetBasicFileByFileId(fileId);
list.add(entity);
}
return list;
}
// 下载单个文件支持分片下载
private void downloadSingleFile(HttpServletResponse response, HttpServletRequest request, DataSetBasicFileEntity entity) throws IOException, MinioException {
String fileUrl = entity.getFileUrl();
File cachedFile = getDiskCachedFile(entity.getFileName());
if (cachedFile == null) {
InputStream fileStream = minioUtil.downloadFile(fileUrl);
cachedFile = cacheFile(fileStream, entity);
}
// 获取文件大小
long fileSize = entity.getFileSize();
String range = request.getHeader("Range");
if (range != null) {
handlePartialContent(response, range, cachedFile, fileSize, entity);
} else {
handleFullContent(response, cachedFile, fileSize, entity.getFileName());
}
}
// 获取磁盘缓存文件
private File getDiskCachedFile(String fileName) {
String tempDir = System.getProperty("java.io.tmpdir") + "cacheFile";
// 使用文件名的哈希值作为文件名的一部分并添加时间戳避免命名冲突
fileName = String.valueOf(fileName.hashCode()) + ".tmp";
// 构造临时文件路径
File tempFile = new File(tempDir, fileName);
// 检查文件是否存在且有效
if (tempFile.exists()) {
// 文件存在且有效返回缓存文件
return tempFile;
}
// 文件不存在或无效返回 null
return null;
}
// 缓存文件仅存储到磁盘
private File cacheFile(InputStream fileStream, DataSetBasicFileEntity entity) throws IOException {
// 获取系统的临时目录
String tempDir = System.getProperty("java.io.tmpdir") + "cacheFile";
File directory = new File(tempDir);
// 如果目录不存在则创建它
if (!directory.exists()) {
directory.mkdirs();
}
// 使用文件名的哈希值作为文件名的一部分并添加时间戳避免命名冲突
String fileHash = String.valueOf(entity.getFileName().hashCode());
String fileName = fileHash + ".tmp";
// 创建临时文件
File tempFile = new File(directory, fileName);
// 如果文件不存在则创建文件并将流写入
if (!tempFile.exists()) {
try (OutputStream fileOutputStream = Files.newOutputStream(tempFile.toPath())) {
IOUtils.copy(fileStream, fileOutputStream); // 将文件流写入临时文件
}
}
// 返回缓存的临时文件
return tempFile;
}
// 处理分片下载
private void handlePartialContent(HttpServletResponse response, String range, File cachedFile, long fileSize, DataSetBasicFileEntity entity) throws IOException {
String[] rangeValues = range.replace("bytes=", "").split("-");
long start = Long.parseLong(rangeValues[0]);
long end = (rangeValues.length > 1) ? Long.parseLong(rangeValues[1]) : fileSize - 1;
if (start >= fileSize || end >= fileSize) {
response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
response.setHeader("Content-Range", "bytes */" + fileSize);
return;
}
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/octet-stream");
String encodedFileName = URLEncoder.encode(entity.getFileName(), "UTF-8").replaceAll("\\+", "%20");
response.setHeader("Content-Disposition", "attachment; filename*=UTF-8''" + encodedFileName);
response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + fileSize);
response.setContentLengthLong(end - start + 1);
try (FileInputStream fileInputStream = new FileInputStream(cachedFile)) {
// 跳过起始字节
fileInputStream.skip(start);
// 使用 IOUtils.copy 进行文件复制
try (ServletOutputStream outputStream = response.getOutputStream()) {
// 将文件流直接复制到输出流
IOUtils.copyLarge(fileInputStream, outputStream, 0, end - start + 1);
outputStream.flush(); // 确保数据立即发送
}
} catch (IOException e) {
System.err.println("文件下载过程中出现错误:" + e.getMessage());
} finally {
// 检查是否需要删除临时文件
if (cachedFile.exists() && end + 1 == fileSize) {
boolean deleted = cachedFile.delete();
if (deleted) {
System.out.println("临时文件已成功删除:" + cachedFile.getAbsolutePath());
} else {
System.err.println("临时文件删除失败:" + cachedFile.getAbsolutePath());
}
}
}
}
// 处理完整文件下载
private void handleFullContent(HttpServletResponse response, File cachedFile, long fileSize, String fileName) throws IOException {
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
response.setContentLengthLong(fileSize);
try (FileInputStream fileStream = new FileInputStream(cachedFile);
ServletOutputStream outputStream = response.getOutputStream()) {
IOUtils.copy(fileStream, outputStream);
}
}
// 下载多个文件可以选择压缩成 ZIP
private void downloadMultipleFiles(HttpServletResponse response, List<DataSetBasicFileEntity> list) throws IOException, MinioException {
// 示例将多个文件打包成一个 ZIP 文件
response.setContentType("application/zip");
response.setHeader("Content-Disposition", "attachment; filename=files.zip");
try (ZipOutputStream zos = new ZipOutputStream(response.getOutputStream())) {
for (DataSetBasicFileEntity entity : list) {
if ("1".equals(entity.getIsDirectory())) {
Iterable<Result<Item>> objectList = minioUtil.listObjects(entity.getFileUrl());
// 遍历每个对象
for (Result<Item> itemResult : objectList) {
Item item = itemResult.get();
// 跳过目录如果 MinIO 中有虚拟目录
if (item.isDir()) {
continue;
}
// 获取文件路径和文件流
String objectName = item.objectName();
InputStream fileStream = minioUtil.downloadFile(item.objectName());
// ZIP 中创建对应的条目保持目录结构
String result = objectName.replace(entity.getFileUrl(), "");
ZipEntry zipEntry = new ZipEntry(entity.getFileName()+File.separator+result);
zos.putNextEntry(zipEntry);
IOUtils.copy(fileStream, zos);
zos.closeEntry();
fileStream.close();
}
} else {
InputStream fileStream = minioUtil.downloadFile(entity.getFileUrl());
// 创建 ZIP 条目
ZipEntry zipEntry = new ZipEntry(entity.getFileName());
zos.putNextEntry(zipEntry);
// 使用 IOUtils.copy 直接复制文件流
IOUtils.copy(fileStream, zos);
zos.closeEntry();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,6 +1,7 @@
package com.bonus.ai.utils;
import com.bonus.ai.config.MinioConfig;
import com.bonus.ai.domain.DataSetBasicFileEntity;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.domain.SysFile;
import io.minio.*;
@ -111,7 +112,7 @@ public class MinioUtil {
* @param folderPath 文件夹路径
* @return 合并后的文件
*/
public SysFile mergeChunks(String filename, int totalChunks ,String folderPath) {
public DataSetBasicFileEntity mergeChunks(String filename, int totalChunks ,String folderPath) {
try {
List<String> partNames = getPartNames(filename, totalChunks);
List<ComposeSource> sources = new ArrayList<>();
@ -119,30 +120,60 @@ public class MinioUtil {
sources.add(ComposeSource.builder().bucket(minioConfig.getBucketName()).object(partName).build());
}
String finalPath = joinPath(folderPath, filename);
// 异步合并文件
CompletableFuture.runAsync(() -> {
try {
minioClient.composeObject(ComposeObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(finalPath)
.sources(sources)
.build());
removeParts(partNames);
LOGGER.info("Merged and uploaded file: {}", finalPath);
} catch (Exception e) {
LOGGER.error("Error merging chunks asynchronously: {}", e.getMessage(), e);
}
});
return SysFile.builder()
.name(filename)
.url(folderPath).build();
minioClient.composeObject(ComposeObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(finalPath)
.sources(sources)
.build());
removeParts(partNames);
LOGGER.info("Merged and uploaded file: {}", finalPath);
// 获取合并后文件的详细信息
StatObjectResponse stat = minioClient.statObject(StatObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(finalPath)
.build());
DataSetBasicFileEntity entity = new DataSetBasicFileEntity();
entity.setFileName(filename);
entity.setFileUrl(finalPath);
entity.setFileSize(stat.size());
return entity;
} catch (Exception e) {
LOGGER.error("Error merging chunks: {}", e.getMessage(), e);
return null;
}
}
/**
* 下载指定文件 InputStream 形式返回
* @param objectName 存储对象名称文件名
* @return 文件的输入流
*/
public InputStream downloadFile(String objectName){
try {
// 返回读取的流
return minioClient.getObject(GetObjectArgs.builder()
.bucket(minioConfig.getBucketName())
.object(objectName)
.build());
} catch (Exception e) {
LOGGER.error("Error downloading file: {}", e.getMessage(), e);
return null;
}
}
/**
* 遍历文件夹下的文件
* @param folderPath 文件夹路径
* @return 返回条目
*/
public Iterable<Result<Item>> listObjects(String folderPath){
return minioClient.listObjects(
ListObjectsArgs.builder().bucket(minioConfig.getBucketName()).prefix(folderPath).recursive(true).build()
);
}
/**
* 获取分片文件名
*/

View File

@ -26,15 +26,11 @@
<select id="selectDataSetBasicFileList" parameterType="com.bonus.ai.domain.DataSetBasicFileEntity" resultMap="DataSetBasicFileResult">
<include refid="selectDataSetBasicFileVo"/>
<where>
<if test="parentId != null "> and parent_id = #{parentId}</if>
<if test="ancestors != null and ancestors != ''"> and ancestors = #{ancestors}</if>
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
<if test="fileUrl != null and fileUrl != ''"> and file_url = #{fileUrl}</if>
<if test="fileSize != null and fileSize != ''"> and file_size = #{fileSize}</if>
<if test="fileLastModifytime != null "> and file_last_modifytime = #{fileLastModifytime}</if>
<if test="uploadTime != null "> and upload_time = #{uploadTime}</if>
del_flag ='0' and create_by = #{createBy}
<if test="isDirectory != null and isDirectory != ''"> and is_directory = #{isDirectory}</if>
<if test="isPublic != null and isPublic != ''"> and is_public = #{isPublic}</if>
<if test="parentId != null and parentId != ''"> and parent_id = #{parentId}</if>
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
<if test="isPublic != null and isPublic != ''"> and is_public =#{isPublic}</if>
</where>
</select>
@ -43,6 +39,26 @@
where file_id = #{fileId}
</select>
<select id="selectDataSetBasicFileByParentId" resultMap="DataSetBasicFileResult">
<include refid="selectDataSetBasicFileVo"/>
where parent_id = #{parentId}
</select>
<select id="selectDataSetBasicDelFileList" parameterType="com.bonus.ai.domain.DataSetBasicFileEntity" resultMap="DataSetBasicFileResult">
<include refid="selectDataSetBasicFileVo"/>
<where>
del_flag ='1' and create_by = #{createBy}
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
</where>
</select>
<select id="selectDataSetBasicFileIsPublicList" parameterType="com.bonus.ai.domain.DataSetBasicFileEntity" resultMap="DataSetBasicFileResult">
<include refid="selectDataSetBasicFileVo"/>
<where>
del_flag ='0' and is_public = '1' and parent_id = #{parentId}
<if test="fileName != null and fileName != ''"> and file_name like concat('%', #{fileName}, '%')</if>
</where>
</select>
<insert id="insertDataSetBasicFile" parameterType="com.bonus.ai.domain.DataSetBasicFileEntity" useGeneratedKeys="true" keyProperty="fileId">
insert into ai_basic_file
<trim prefix="(" suffix=")" suffixOverrides=",">
@ -77,6 +93,11 @@
<if test="updateBy != null">#{updateBy},</if>
<if test="updateTime != null">#{updateTime},</if>
</trim>
ON DUPLICATE KEY UPDATE
file_url = VALUES(file_url),
file_size = VALUES(file_size),
create_time = VALUES(create_time),
create_by = VALUES(create_by)
</insert>
<update id="updateDataSetBasicFile" parameterType="com.bonus.ai.domain.DataSetBasicFileEntity">
@ -99,9 +120,24 @@
</trim>
where file_id = #{fileId}
</update>
<update id="updateSharedFilesByIds">
UPDATE ai_basic_file
SET is_public = #{isPublic}
WHERE file_id IN
<foreach item="fileId" collection="ancestors" open="(" separator="," close=")">
#{fileId}
</foreach>
</update>
<update id="dataRecoveryFileByFileIds">
update ai_basic_file set del_flag='0' where file_id in
<foreach item="fileId" collection="array" open="(" separator="," close=")">
#{fileId}
</foreach>
</update>
<delete id="deleteDataSetBasicFileByFileIds" parameterType="String">
delete from ai_basic_file where file_id in
update ai_basic_file set del_flag='1' where file_id in
<foreach item="fileId" collection="array" open="(" separator="," close=")">
#{fileId}
</foreach>