diff --git a/bookshelfplus-frontend/views/dashboard/admin/FileManage_Upload.html b/bookshelfplus-frontend/views/dashboard/admin/FileManage_Upload.html
index 04d5219..2bcf2a8 100644
--- a/bookshelfplus-frontend/views/dashboard/admin/FileManage_Upload.html
+++ b/bookshelfplus-frontend/views/dashboard/admin/FileManage_Upload.html
@@ -374,9 +374,35 @@
if (status === "success") {
console.log("data", data);
// 取得预授权URL,使用该URL进行文件上传
- uploadFile(file, data.url, data.fileId);
+ uploadFile(file, data.url, data.fileId, data.fileObjectId);
} else {
- alert(`出错啦!${data.errMsg} (错误码: ${data.errCode}) `);
+ if (data.errCode == "60001") {
+ // 文件已存在
+ console.log(`出错啦!${data.errMsg} (错误码: ${data.errCode}) `);
+
+ // 再次发送请求,查询这个已存在文件的 fileId
+ postRequest("/file/getFileByHash", { token: localStorageUtils.getToken(), fileSha1: fileInfo.fileSha1 })
+ .then(function (responseData) {
+ var axiosData = responseData.data;
+ var status = axiosData.status;
+ var data = axiosData.data;
+ if (status === "success") {
+ console.log(data);
+
+ // 查询到之后,询问用户是否跳转到文件详情页
+ var isRedirect = confirm(`文件已存在,是否前往查看详情?\n(文件ID: ${data.id})`);
+ if (isRedirect)
+ location.href = `<%= pageUrl %>../detail?fileId=${data.id}`;
+ } else {
+ alert(`出错啦!${data.errMsg} (错误码: ${data.errCode}) `);
+ }
+ }).catch(function (error) {
+ console.log(error);
+ alert("无法连接到服务器,请检查网络连接!");
+ });
+ } else {
+ alert(`出错啦!${data.errMsg} (错误码: ${data.errCode}) `);
+ }
}
}).catch(function (error) {
console.log(error);
@@ -387,7 +413,7 @@
//##############################################
//传入预授权 URL ,将文件上传到这个地址
//##############################################
- function uploadFile(file, preSignedUrl, fileId) {
+ function uploadFile(file, preSignedUrl, fileId, fileObjectId) {
// refer: https://cloud.tencent.com/document/product/436/35651
// 获取到 Url 后,前端可以这样 ajax 上传
@@ -408,13 +434,16 @@
console.log('上传成功', xhr.status, xhr.statusText);
// 等待进度条走到 100% 否则小文件进度条还没有走完就提示上传完成会让人感觉有点奇怪
setTimeout(function () {
- alert("上传成功!");
- if ($("#checkbox-auto-upload").is(":checked")) {
- window.location.reload();
- } else {
- // location.href = "<%= pageUrl %>../";
- location.href = "<%= pageUrl %>../detail?id=" + fileId;
- }
+ // 上传成功触发一次 “刷新文件对象上传状态”,避免因为云函数回调不成功导致文件对象上传状态没有及时更新
+ refreshFileObjectStatus(fileObjectId, function () {
+ alert("上传成功!");
+ if ($("#checkbox-auto-upload").is(":checked")) {
+ window.location.reload();
+ } else {
+ // location.href = "<%= pageUrl %>../";
+ location.href = "<%= pageUrl %>../detail?id=" + fileId;
+ }
+ });
}, 300);
};
xhr.onerror = function (e) {
@@ -428,7 +457,7 @@
function getFileAssociatorList(fileSha1) {
var fileAssociator = document.getElementById("fileAssociator");
// 下拉框列表
- postRequest("/file/list/MatchfileHash", { token: localStorageUtils.getToken(), fileSha1: fileSha1 })
+ postRequest("/file/list/MatchfileHashWithNullValue", { token: localStorageUtils.getToken(), fileSha1: fileSha1 })
.then(function (responseData) {
var axiosData = responseData.data;
var status = axiosData.status;
@@ -452,4 +481,25 @@
alert("无法连接到服务器,请检查网络连接!");
});
}
+
+
\ No newline at end of file
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Common/Error/BusinessErrorCode.java b/bookshelfplus/src/main/java/plus/bookshelf/Common/Error/BusinessErrorCode.java
index 7ce956f..a163872 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Common/Error/BusinessErrorCode.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Common/Error/BusinessErrorCode.java
@@ -28,6 +28,9 @@ public enum BusinessErrorCode implements CommonError {
BOOK_FAVORITES_ALREADY_EXIST(50002, "书籍已经在收藏夹中"),
BOOK_FAVORITES_NOT_EXIST(50003, "书籍不在收藏夹中"),
+ // 60000开头为文件、文件对象相关错误定义
+ FILE_ALREADY_EXIST(60001, "文件已存在"),
+
// 占位
PLACE_HOLDER(99999, "这是一个占位符错误");
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Controller/Controller/FileController.java b/bookshelfplus/src/main/java/plus/bookshelf/Controller/Controller/FileController.java
index aad4af6..23dd19c 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Controller/Controller/FileController.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Controller/Controller/FileController.java
@@ -100,10 +100,10 @@ public class FileController extends BaseController {
}
@ApiOperation(value = "【管理员】查询文件列表(匹配文件哈希)", notes = "查询文件列表,返回文件哈希为空或者相同的文件")
- @RequestMapping(value = "list/MatchfileHash", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
+ @RequestMapping(value = "list/MatchfileHashWithNullValue", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
- public CommonReturnType matchfileHash(@RequestParam(value = "token", required = false) String token,
- @RequestParam(value = "fileSha1", required = true) String fileSha1) throws InvocationTargetException, IllegalAccessException, BusinessException {
+ public CommonReturnType matchfileHashWithNullValue(@RequestParam(value = "token", required = false) String token,
+ @RequestParam(value = "fileSha1", required = true) String fileSha1) throws InvocationTargetException, IllegalAccessException, BusinessException {
UserModel userModel = userService.getUserByToken(redisTemplate, token);
if (userModel == null || !Objects.equals(userModel.getGroup(), "ADMIN")) {
@@ -119,6 +119,22 @@ public class FileController extends BaseController {
return CommonReturnType.create(fileVOS);
}
+ @ApiOperation(value = "【管理员】通过文件SHA1哈希查找文件Id", notes = "查询文件列表,返回文件哈希匹配的文件Id")
+ @RequestMapping(value = "getFileByHash", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
+ @ResponseBody
+ public CommonReturnType getFileByHash(@RequestParam(value = "token", required = false) String token,
+ @RequestParam(value = "fileSha1", required = true) String fileSha1) throws InvocationTargetException, IllegalAccessException, BusinessException {
+
+ UserModel userModel = userService.getUserByToken(redisTemplate, token);
+ if (userModel == null || !Objects.equals(userModel.getGroup(), "ADMIN")) {
+ throw new BusinessException(BusinessErrorCode.OPERATION_NOT_ALLOWED, "非管理员用户无权进行此操作");
+ }
+
+ FileModel fileModel = fileService.selectBySha1(fileSha1);
+ FileVO fileVO = convertFileVOFromModel(fileModel);
+ return CommonReturnType.create(fileVO);
+ }
+
/**
* 创建文件操作预授权URL
*
@@ -182,13 +198,17 @@ public class FileController extends BaseController {
switch (httpMethodName) {
case PUT:
// 上传文件
- if (isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件已存在");
+ if (isExist) throw new BusinessException(BusinessErrorCode.FILE_ALREADY_EXIST, "文件已存在");
- Integer realFileId = fileObjectService.uploadFile(fileId, fileName, bookSaveFolder + fileSha1, fileSize,
+ Integer[] integers = fileObjectService.uploadFile(fileId, fileName, bookSaveFolder + fileSha1, fileSize,
fileSha1, fileExt, FileStorageMediumEnum.QCLOUD_COS, "", lastModified);
+ Integer realFileId = integers[0];
+ Integer fileObjectId = integers[1];
+
// fileId 可能为 0 (创建新文件)
// realFileId 是从数据库中查询出来的,真实的文件id
resultMap.put("fileId", realFileId);
+ resultMap.put("fileObjectId", fileObjectId);
url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileSha1, expireMinute, urlGUID);
break;
case GET:
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileDOMapper.java b/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileDOMapper.java
index 288b228..0865bb5 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileDOMapper.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileDOMapper.java
@@ -61,12 +61,19 @@ public interface FileDOMapper {
FileDO[] selectAll();
/**
- * 查询系统中的所有文件
+ * 查询系统中所有 SHA1匹配 和 未设置SHA1 的文件
*
* @return
*/
FileDO[] selectBySha1WithNullValue(String fileSha1);
+ /**
+ * 查询系统中一个 SHA1匹配 的文件
+ *
+ * @return
+ */
+ FileDO selectBySha1(String fileSha1);
+
/**
* 列出文件支持的下载方式
*
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileObjectDOMapper.java b/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileObjectDOMapper.java
index 528f629..4ee2b79 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileObjectDOMapper.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Dao/Mapper/FileObjectDOMapper.java
@@ -75,4 +75,11 @@ public interface FileObjectDOMapper {
* @return
*/
FileObjectDO[] selectFileObjectByBookId(Integer bookId);
+
+ /**
+ * 获取上一次插入的主键Id
+ *
+ * @return
+ */
+ int getLastInsertId();
}
\ No newline at end of file
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileObjectServiceImpl.java b/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileObjectServiceImpl.java
index 7984f6a..d4e23c3 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileObjectServiceImpl.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileObjectServiceImpl.java
@@ -116,7 +116,7 @@ public class FileObjectServiceImpl implements FileObjectService {
* @param fileSize 文件大小
* @param fileSHA1 文件SHA1
* @param fileExt 文件扩展名
- * @param fileNameWithoutExt 文件名(不包含扩展名)
+ * @param fileName 文件名(不包含扩展名)
* @param fileStorageMediumEnum 文件存储介质
* @param source 文件来源
* @return 返回文件Id
@@ -126,9 +126,9 @@ public class FileObjectServiceImpl implements FileObjectService {
*/
@Override
@Transactional
- public Integer uploadFile(Integer fileId, String fileName, String filePath, Long fileSize, String fileSHA1,
- String fileExt, FileStorageMediumEnum fileStorageMediumEnum,
- String source, Long lastModified
+ public Integer[] uploadFile(Integer fileId, String fileName, String filePath, Long fileSize, String fileSHA1,
+ String fileExt, FileStorageMediumEnum fileStorageMediumEnum,
+ String source, Long lastModified
) throws InvocationTargetException, IllegalAccessException, BusinessException {
if (fileId == 0) {
@@ -179,7 +179,11 @@ public class FileObjectServiceImpl implements FileObjectService {
if (!isSuccess) {
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "文件对象创建失败");
}
- return fileId;
+
+ int lastInsertId = fileObjectDOMapper.getLastInsertId();
+
+ // fileId, fileObjectId
+ return new Integer[]{fileId, lastInsertId};
}
/**
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileServiceImpl.java b/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileServiceImpl.java
index ea33b98..6c4fc22 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileServiceImpl.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Service/Impl/FileServiceImpl.java
@@ -8,11 +8,9 @@ import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Dao.DO.FileDO;
-import plus.bookshelf.Dao.DO.FileObjectDO;
import plus.bookshelf.Dao.Mapper.FileDOMapper;
import plus.bookshelf.Dao.Mapper.FileObjectDOMapper;
import plus.bookshelf.Service.Model.FileModel;
-import plus.bookshelf.Service.Model.FileObjectModel;
import plus.bookshelf.Service.Service.CosPresignedUrlGenerateLogService;
import plus.bookshelf.Service.Service.FileService;
@@ -102,6 +100,18 @@ public class FileServiceImpl implements FileService {
return fileModels;
}
+ /**
+ * 列出一个 SHA1匹配 的文件
+ *
+ * @return
+ */
+ @Override
+ public FileModel selectBySha1(String fileSha1) {
+ FileDO fileDO = fileDOMapper.selectBySha1(fileSha1);
+ FileModel fileModel = convertFromDataObject(fileDO);
+ return fileModel;
+ }
+
private FileModel convertFromDataObject(FileDO fileDO) {
if (fileDO == null) {
return null;
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileObjectService.java b/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileObjectService.java
index d79a3b6..4996a6a 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileObjectService.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileObjectService.java
@@ -55,7 +55,7 @@ public interface FileObjectService {
* @throws BusinessException
*/
@Transactional
- Integer uploadFile(Integer fileId, String fileName, String filePath, Long fileSize, String fileSHA1, String fileExt, FileStorageMediumEnum fileStorageMediumEnum, String source, Long lastModified) throws InvocationTargetException, IllegalAccessException, BusinessException;
+ Integer[] uploadFile(Integer fileId, String fileName, String filePath, Long fileSize, String fileSHA1, String fileExt, FileStorageMediumEnum fileStorageMediumEnum, String source, Long lastModified) throws InvocationTargetException, IllegalAccessException, BusinessException;
/**
* 修改文件对象上传状态信息
diff --git a/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileService.java b/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileService.java
index c7bb404..87daf1b 100644
--- a/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileService.java
+++ b/bookshelfplus/src/main/java/plus/bookshelf/Service/Service/FileService.java
@@ -32,6 +32,14 @@ public interface FileService {
*/
List selectBySha1WithNullValue(String token) throws InvocationTargetException, IllegalAccessException, BusinessException;
+ /**
+ * 列出一个 SHA1匹配 的文件
+ *
+ * @param fileSha1
+ * @return
+ */
+ FileModel selectBySha1(String fileSha1);
+
/**
* 添加文件信息
* 返回是否添加成功
diff --git a/bookshelfplus/src/main/resources/mapping/FileDOMapper.xml b/bookshelfplus/src/main/resources/mapping/FileDOMapper.xml
index 4208e53..8bc020e 100644
--- a/bookshelfplus/src/main/resources/mapping/FileDOMapper.xml
+++ b/bookshelfplus/src/main/resources/mapping/FileDOMapper.xml
@@ -223,6 +223,12 @@
from file_info
where file_sha1 = #{fileSha1,jdbcType=VARCHAR} or file_sha1 is null or file_sha1 = ''
+
diff --git a/bookshelfplus/src/main/resources/mapping/FileObjectDOMapper.xml b/bookshelfplus/src/main/resources/mapping/FileObjectDOMapper.xml
index 94e60d8..8f5194c 100644
--- a/bookshelfplus/src/main/resources/mapping/FileObjectDOMapper.xml
+++ b/bookshelfplus/src/main/resources/mapping/FileObjectDOMapper.xml
@@ -176,4 +176,7 @@
WHERE file_id IN (SELECT id AS file_id FROM `file_info` WHERE book_id = 1)
AND upload_status = 'SUCCESS'
+
\ No newline at end of file