知识库历史文件
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package org.xyzh.file.controller;
|
||||
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
@@ -94,9 +97,10 @@ public class FileController {
|
||||
|
||||
ResultDomain<TbSysFileDTO> fileInfo = fileService.getFileById(fileId);
|
||||
String filename = fileInfo.getData() != null ? fileInfo.getData().getName() : "download";
|
||||
String encodedFilename = URLEncoder.encode(filename, StandardCharsets.UTF_8).replace("+", "%20");
|
||||
|
||||
return ResponseEntity.ok()
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + filename + "\"")
|
||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFilename + "\"; filename*=UTF-8''" + encodedFilename)
|
||||
.contentType(MediaType.APPLICATION_OCTET_STREAM)
|
||||
.body(result.getData());
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ import org.springframework.util.DigestUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.xyzh.api.file.dto.TbSysFileDTO;
|
||||
import org.xyzh.api.file.service.FileService;
|
||||
import org.xyzh.common.auth.utils.LoginUtil;
|
||||
import org.xyzh.common.core.domain.LoginDomain;
|
||||
import org.xyzh.common.core.domain.ResultDomain;
|
||||
import org.xyzh.file.config.MinioConfig;
|
||||
import org.xyzh.file.mapper.FileMapper;
|
||||
@@ -53,65 +55,7 @@ public class FileServiceImpl implements FileService {
|
||||
if (file == null || file.isEmpty()) {
|
||||
return ResultDomain.failure("文件不能为空");
|
||||
}
|
||||
|
||||
// 生成文件信息
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String extension = getFileExtension(originalFilename);
|
||||
String contentType = file.getContentType();
|
||||
long size = file.getSize();
|
||||
|
||||
// 生成唯一的对象名称
|
||||
String objectName = generateObjectName(originalFilename, module);
|
||||
|
||||
// 计算文件MD5
|
||||
String md5Hash = calculateMD5(file.getBytes());
|
||||
|
||||
// 上传到MinIO
|
||||
String bucketName = minioConfig.getBucketName();
|
||||
boolean uploadSuccess = minioUtil.uploadFile(
|
||||
bucketName,
|
||||
objectName,
|
||||
file.getInputStream(),
|
||||
size,
|
||||
contentType
|
||||
);
|
||||
|
||||
if (!uploadSuccess) {
|
||||
return ResultDomain.failure("文件上传到MinIO失败");
|
||||
}
|
||||
|
||||
// 保存到数据库
|
||||
TbSysFileDTO fileDTO = new TbSysFileDTO();
|
||||
String fileId = UUID.randomUUID().toString();
|
||||
fileDTO.setOptsn(UUID.randomUUID().toString());
|
||||
fileDTO.setFileId(fileId);
|
||||
fileDTO.setName(originalFilename);
|
||||
fileDTO.setPath(objectName);
|
||||
fileDTO.setSize(size);
|
||||
fileDTO.setType(extension);
|
||||
fileDTO.setStorageType("MINIO");
|
||||
fileDTO.setMimeType(contentType);
|
||||
// URL 设为 NULL,前端通过后端接口 /api/file/download/{fileId} 下载
|
||||
fileDTO.setUrl(null);
|
||||
fileDTO.setStatus("NORMAL");
|
||||
fileDTO.setModule(module);
|
||||
fileDTO.setBusinessId(businessId);
|
||||
fileDTO.setObjectName(objectName);
|
||||
fileDTO.setBucketName(bucketName);
|
||||
fileDTO.setMd5Hash(md5Hash);
|
||||
fileDTO.setExtension(extension);
|
||||
fileDTO.setCreateTime(new java.util.Date());
|
||||
|
||||
int result = fileMapper.insertFile(fileDTO);
|
||||
if (result <= 0) {
|
||||
// 如果数据库保存失败,删除MinIO中的文件
|
||||
minioUtil.deleteFile(bucketName, objectName);
|
||||
return ResultDomain.failure("文件信息保存失败");
|
||||
}
|
||||
|
||||
logger.info("文件上传成功: {}, 大小: {} bytes", originalFilename, size);
|
||||
return ResultDomain.success("文件上传成功", fileDTO);
|
||||
|
||||
return uploadFileBytesWithUser(file.getBytes(), file.getOriginalFilename(), file.getContentType(), module, businessId, getCurrentUserId());
|
||||
} catch (Exception e) {
|
||||
logger.error("文件上传失败", e);
|
||||
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||
@@ -283,16 +227,6 @@ public class FileServiceImpl implements FileService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 上传新版本文件(用于文件更新,fileRootId保持一致,version递增)
|
||||
* @param file 文件对象
|
||||
* @param module 所属模块
|
||||
* @param businessId 业务ID
|
||||
* @param fileRootId 文件根ID(多版本一致)
|
||||
* @return ResultDomain<TbSysFileDTO> 上传结果,包含新版本文件信息
|
||||
* @author yslg
|
||||
* @since 2025-12-18
|
||||
*/
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileVersion(MultipartFile file, String module, String businessId, String fileRootId) {
|
||||
try {
|
||||
@@ -302,96 +236,105 @@ public class FileServiceImpl implements FileService {
|
||||
if (fileRootId == null || fileRootId.isEmpty()) {
|
||||
return ResultDomain.failure("文件根ID不能为空");
|
||||
}
|
||||
return uploadFileBytesVersionWithUser(file.getBytes(), file.getOriginalFilename(), file.getContentType(), module, businessId, fileRootId, getCurrentUserId());
|
||||
} catch (Exception e) {
|
||||
logger.error("新版本文件上传失败", e);
|
||||
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId) {
|
||||
return uploadFileBytesWithUser(fileBytes, fileName, contentType, module, businessId, getCurrentUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileBytesWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String uploaderUserId) {
|
||||
try {
|
||||
if (fileBytes == null || fileBytes.length == 0) {
|
||||
return ResultDomain.failure("文件不能为空");
|
||||
}
|
||||
|
||||
String extension = getFileExtension(fileName);
|
||||
long size = fileBytes.length;
|
||||
String objectName = generateObjectName(fileName, module);
|
||||
String md5Hash = calculateMD5(fileBytes);
|
||||
|
||||
String bucketName = minioConfig.getBucketName();
|
||||
java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(fileBytes);
|
||||
boolean uploadSuccess = minioUtil.uploadFile(bucketName, objectName, inputStream, size, contentType);
|
||||
|
||||
if (!uploadSuccess) {
|
||||
return ResultDomain.failure("文件上传到MinIO失败");
|
||||
}
|
||||
|
||||
TbSysFileDTO fileDTO = new TbSysFileDTO();
|
||||
String fileId = UUID.randomUUID().toString().replace("-", "");
|
||||
fileDTO.setOptsn(UUID.randomUUID().toString());
|
||||
fileDTO.setFileId(fileId);
|
||||
fileDTO.setName(fileName);
|
||||
fileDTO.setPath(objectName);
|
||||
fileDTO.setUrl(null);
|
||||
fileDTO.setSize(size);
|
||||
fileDTO.setMimeType(contentType);
|
||||
fileDTO.setExtension(extension);
|
||||
fileDTO.setMd5Hash(md5Hash);
|
||||
fileDTO.setModule(module);
|
||||
fileDTO.setBusinessId(businessId);
|
||||
fileDTO.setStorageType("MINIO");
|
||||
fileDTO.setObjectName(objectName);
|
||||
fileDTO.setBucketName(bucketName);
|
||||
fileDTO.setVersion(1);
|
||||
fileDTO.setFileRootId(fileId);
|
||||
fileDTO.setCreator(uploaderUserId);
|
||||
fileDTO.setUploader(uploaderUserId);
|
||||
fileDTO.setCreateTime(new java.util.Date());
|
||||
|
||||
int result = fileMapper.insertFile(fileDTO);
|
||||
if (result <= 0) {
|
||||
minioUtil.deleteFile(bucketName, objectName);
|
||||
return ResultDomain.failure("文件信息保存失败");
|
||||
}
|
||||
|
||||
logger.info("字节数组文件上传成功: {}, uploader: {}", fileName, uploaderUserId);
|
||||
return ResultDomain.success("文件上传成功", fileDTO);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("字节数组文件上传失败", e);
|
||||
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileBytesVersion(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId) {
|
||||
return uploadFileBytesVersionWithUser(fileBytes, fileName, contentType, module, businessId, fileRootId, getCurrentUserId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileBytesVersionWithUser(byte[] fileBytes, String fileName, String contentType, String module, String businessId, String fileRootId, String uploaderUserId) {
|
||||
try {
|
||||
if (fileBytes == null || fileBytes.length == 0) {
|
||||
return ResultDomain.failure("文件不能为空");
|
||||
}
|
||||
if (fileRootId == null || fileRootId.isEmpty()) {
|
||||
return ResultDomain.failure("文件根ID不能为空");
|
||||
}
|
||||
|
||||
// 1. 获取当前最大版本号
|
||||
Integer maxVersion = fileMapper.selectMaxVersionByFileRootId(fileRootId);
|
||||
int newVersion = (maxVersion != null ? maxVersion : 0) + 1;
|
||||
|
||||
// 2. 生成文件信息
|
||||
String originalFilename = file.getOriginalFilename();
|
||||
String extension = getFileExtension(originalFilename);
|
||||
String contentType = file.getContentType();
|
||||
long size = file.getSize();
|
||||
|
||||
// 3. 生成唯一的对象名称
|
||||
String objectName = generateObjectName(originalFilename, module);
|
||||
|
||||
// 4. 计算文件MD5
|
||||
String md5Hash = calculateMD5(file.getBytes());
|
||||
|
||||
// 5. 上传到MinIO
|
||||
String bucketName = minioConfig.getBucketName();
|
||||
boolean uploadSuccess = minioUtil.uploadFile(
|
||||
bucketName,
|
||||
objectName,
|
||||
file.getInputStream(),
|
||||
size,
|
||||
contentType
|
||||
);
|
||||
|
||||
if (!uploadSuccess) {
|
||||
return ResultDomain.failure("文件上传到MinIO失败");
|
||||
}
|
||||
|
||||
// 6. 构建文件访问URL
|
||||
String fileUrl = minioConfig.buildFileUrl(objectName);
|
||||
|
||||
// 7. 保存到数据库(新版本记录)
|
||||
TbSysFileDTO fileDTO = new TbSysFileDTO();
|
||||
fileDTO.setOptsn(UUID.randomUUID().toString());
|
||||
fileDTO.setFileId(UUID.randomUUID().toString());
|
||||
fileDTO.setFileRootId(fileRootId);
|
||||
fileDTO.setVersion(newVersion);
|
||||
fileDTO.setName(originalFilename);
|
||||
fileDTO.setPath(objectName);
|
||||
fileDTO.setSize(size);
|
||||
fileDTO.setType(extension);
|
||||
fileDTO.setStorageType("MINIO");
|
||||
fileDTO.setMimeType(contentType);
|
||||
fileDTO.setUrl(fileUrl);
|
||||
fileDTO.setStatus("NORMAL");
|
||||
fileDTO.setModule(module);
|
||||
fileDTO.setBusinessId(businessId);
|
||||
fileDTO.setObjectName(objectName);
|
||||
fileDTO.setBucketName(bucketName);
|
||||
fileDTO.setMd5Hash(md5Hash);
|
||||
fileDTO.setExtension(extension);
|
||||
fileDTO.setCreateTime(new java.util.Date());
|
||||
|
||||
int result = fileMapper.insertFile(fileDTO);
|
||||
if (result <= 0) {
|
||||
// 如果数据库保存失败,删除MinIO中的文件
|
||||
minioUtil.deleteFile(bucketName, objectName);
|
||||
return ResultDomain.failure("文件信息保存失败");
|
||||
}
|
||||
|
||||
logger.info("新版本文件上传成功: {}, version: {}, fileRootId: {}", originalFilename, newVersion, fileRootId);
|
||||
return ResultDomain.success("文件上传成功", fileDTO);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("新版本文件上传失败", e);
|
||||
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultDomain<TbSysFileDTO> uploadFileBytes(byte[] fileBytes, String fileName, String contentType, String module, String businessId) {
|
||||
try {
|
||||
if (fileBytes == null || fileBytes.length == 0) {
|
||||
return ResultDomain.failure("文件不能为空");
|
||||
}
|
||||
|
||||
// 生成文件信息
|
||||
String extension = getFileExtension(fileName);
|
||||
long size = fileBytes.length;
|
||||
|
||||
// 生成唯一的对象名称
|
||||
// 3. 生成唯一的对象名称
|
||||
String objectName = generateObjectName(fileName, module);
|
||||
|
||||
// 计算文件MD5
|
||||
// 4. 计算文件MD5
|
||||
String md5Hash = calculateMD5(fileBytes);
|
||||
|
||||
// 上传到MinIO
|
||||
// 5. 上传到MinIO
|
||||
String bucketName = minioConfig.getBucketName();
|
||||
java.io.ByteArrayInputStream inputStream = new java.io.ByteArrayInputStream(fileBytes);
|
||||
boolean uploadSuccess = minioUtil.uploadFile(
|
||||
@@ -405,41 +348,45 @@ public class FileServiceImpl implements FileService {
|
||||
if (!uploadSuccess) {
|
||||
return ResultDomain.failure("文件上传到MinIO失败");
|
||||
}
|
||||
|
||||
// 6. 构建文件访问URL
|
||||
String fileUrl = minioConfig.buildFileUrl(objectName);
|
||||
|
||||
// 创建文件DTO
|
||||
// 7. 保存到数据库(新版本记录)
|
||||
TbSysFileDTO fileDTO = new TbSysFileDTO();
|
||||
String fileId = UUID.randomUUID().toString().replace("-", "");
|
||||
fileDTO.setOptsn(UUID.randomUUID().toString());
|
||||
fileDTO.setFileId(fileId);
|
||||
fileDTO.setFileId(UUID.randomUUID().toString());
|
||||
fileDTO.setFileRootId(fileRootId);
|
||||
fileDTO.setVersion(newVersion);
|
||||
fileDTO.setName(fileName);
|
||||
fileDTO.setPath(objectName);
|
||||
// URL 设为 NULL,前端通过后端接口 /api/file/download/{fileId} 下载
|
||||
fileDTO.setUrl(null);
|
||||
fileDTO.setSize(size);
|
||||
fileDTO.setType(extension);
|
||||
fileDTO.setStorageType("MINIO");
|
||||
fileDTO.setMimeType(contentType);
|
||||
fileDTO.setExtension(extension);
|
||||
fileDTO.setMd5Hash(md5Hash);
|
||||
fileDTO.setUrl(fileUrl);
|
||||
fileDTO.setStatus("NORMAL");
|
||||
fileDTO.setModule(module);
|
||||
fileDTO.setBusinessId(businessId);
|
||||
fileDTO.setStorageType("MINIO");
|
||||
fileDTO.setObjectName(objectName);
|
||||
fileDTO.setBucketName(bucketName);
|
||||
fileDTO.setVersion(1);
|
||||
fileDTO.setFileRootId(fileId);
|
||||
fileDTO.setMd5Hash(md5Hash);
|
||||
fileDTO.setExtension(extension);
|
||||
fileDTO.setCreator(uploaderUserId);
|
||||
fileDTO.setUploader(uploaderUserId);
|
||||
fileDTO.setCreateTime(new java.util.Date());
|
||||
|
||||
// 保存到数据库
|
||||
int result = fileMapper.insertFile(fileDTO);
|
||||
if (result <= 0) {
|
||||
minioUtil.deleteFile(bucketName, objectName);
|
||||
return ResultDomain.failure("文件信息保存失败");
|
||||
}
|
||||
|
||||
logger.info("字节数组文件上传成功: {}", fileName);
|
||||
logger.info("新版本文件上传成功(bytes): {}, version: {}, fileRootId: {}, uploader: {}", fileName, newVersion, fileRootId, uploaderUserId);
|
||||
return ResultDomain.success("文件上传成功", fileDTO);
|
||||
|
||||
} catch (Exception e) {
|
||||
logger.error("字节数组文件上传失败", e);
|
||||
logger.error("新版本文件上传失败(bytes)", e);
|
||||
return ResultDomain.failure("文件上传失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -471,4 +418,19 @@ public class FileServiceImpl implements FileService {
|
||||
private String calculateMD5(byte[] data) {
|
||||
return DigestUtils.md5DigestAsHex(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户ID(支持未登录场景)
|
||||
*/
|
||||
private String getCurrentUserId() {
|
||||
try {
|
||||
LoginDomain loginDomain = LoginUtil.getCurrentLogin();
|
||||
if (loginDomain != null && loginDomain.getUser() != null) {
|
||||
return loginDomain.getUser().getUserId();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug("获取当前登录用户失败: {}", e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@
|
||||
<if test="bucketName != null">, bucket_name</if>
|
||||
<if test="md5Hash != null">, md5_hash</if>
|
||||
<if test="extension != null">, extension</if>
|
||||
<if test="fileRootId != null">, file_root_id</if>
|
||||
<if test="version != null">, version</if>
|
||||
) VALUES (
|
||||
<!-- 必填字段值 -->
|
||||
#{optsn}, #{fileId}, #{name}, #{path}, #{size}
|
||||
@@ -86,6 +88,8 @@
|
||||
<if test="bucketName != null">, #{bucketName}</if>
|
||||
<if test="md5Hash != null">, #{md5Hash}</if>
|
||||
<if test="extension != null">, #{extension}</if>
|
||||
<if test="fileRootId != null">, #{fileRootId}</if>
|
||||
<if test="version != null">, #{version}</if>
|
||||
)
|
||||
</insert>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user