1
0
mirror of https://gitee.com/bookshelfplus/bookshelfplus synced 2025-09-01 22:53:29 +08:00
Code Issues Projects Releases Wiki Activity GitHub Gitee

删除文件对象功能完成;其他小调整

This commit is contained in:
2022-04-22 21:36:14 +08:00
parent 3757e19b7d
commit bce782b356
12 changed files with 437 additions and 274 deletions

View File

@@ -5,6 +5,8 @@ import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.Headers;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.exception.CosServiceException;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.GeneratePresignedUrlRequest;
@@ -84,6 +86,13 @@ public class QCloudCosUtils {
return _cosClient;
}
/**
* 判断文件是否存在
*
* @param folder
* @param objectKey
* @return
*/
public Boolean doesObjectExist(String folder, String objectKey) {
return doesObjectExist(folder + objectKey);
}
@@ -97,6 +106,36 @@ public class QCloudCosUtils {
return cosClient.doesObjectExist(bucketName, key);
}
/**
* 删除文件
*
* @param folder
* @param objectKey
* @return
*/
public Boolean deleteObject(String folder, String objectKey) {
return deleteObject(folder + objectKey);
}
public Boolean deleteObject(String filePath) {
COSClient cosClient = createCOSClient();
// 存储桶的命名格式为 BucketName-APPID此处填写的存储桶名称必须为此格式
String bucketName = qCloudCosConfig.getBucketName();
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
String key = qCloudCosConfig.getKeyName() + filePath;
// refer: https://cloud.tencent.com/document/product/436/65939#.E5.88.A0.E9.99.A4.E5.AF.B9.E8.B1.A1
try {
cosClient.deleteObject(bucketName, key);
return true;
} catch (CosServiceException e) {
e.printStackTrace();
} catch (CosClientException e) {
e.printStackTrace();
}
return false;
}
/**
* 生成预签名URL
* <p>

View File

@@ -1,20 +1,16 @@
package plus.bookshelf.Controller.Controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qcloud.cos.http.HttpMethodName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import plus.bookshelf.Common.Enum.FileStorageMediumEnum;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
import plus.bookshelf.Common.FileManager.QCloudCosUtils;
import plus.bookshelf.Common.Response.CommonReturnType;
import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Controller.VO.FileObjectVO;
@@ -144,180 +140,6 @@ public class FileController extends BaseController {
return CommonReturnType.create(fileVO);
}
/**
* 创建文件操作预授权URL
*
* @param httpMethod 请求的 HTTP 方法,上传请求用 PUT下载请求用 GET删除请求用 DELETE
* @param token 当前登录用户的 token
* @param fileName 文件名
* @param expireMinute 过期时间(分钟)
* @return
* @throws BusinessException
*/
@ApiOperation(value = "【用户|管理员】创建腾讯云 COS 预授权 URL", notes = "")
@RequestMapping(value = "/cos/{httpMethod}", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType cos(@PathVariable(value = "httpMethod") String httpMethod,
@RequestParam(value = "token") String token,
@RequestParam(value = "fileSha1") String fileSha1,
@RequestParam(value = "expireMinute", required = false) Integer expireMinute,
// 以下为 PUT 请求必传参数
@RequestParam(value = "fileName", required = false) String fileName, // 不含扩展名
@RequestParam(value = "fileSize", required = false) Long fileSize,
// @RequestParam(value = "fileType", required = false) String fileType,
@RequestParam(value = "lastModified", required = false) Long lastModified,
@RequestParam(value = "fileExt", required = false) String fileExt,
@RequestParam(value = "fileId", required = false) Integer fileId, // 关联的文件ID创建新文件则为0
// 以下为 GET 请求必传参数
@RequestParam(value = "fileNameAndExt", required = false) String fileNameAndExt,
@RequestParam(value = "visitorId", required = false) String visitorFingerprint
) throws BusinessException, InvocationTargetException, IllegalAccessException {
if (expireMinute == null) {
expireMinute = 30;
} else if (expireMinute > 60) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "expireMinute 参数不能大于 60");
} else if (expireMinute < 1) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "expireMinute 参数不能小于 1");
}
// 已经在 getUserByToken 方法中判断了 token 为空、不合法;用户不存在情况,此处无需再判断
UserModel userModel = userService.getUserByToken(redisTemplate, token);
// 判断httpMethod 是否合法
HttpMethodName httpMethodName;
try {
httpMethodName = HttpMethodName.valueOf(httpMethod.toUpperCase());
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数不合法");
}
QCloudCosUtils qCloudCosUtils = new QCloudCosUtils(qCloudCosConfig, cosPresignedUrlGenerateLogService);
// 当次生成下载链接的全局唯一Id
String urlGUID = NanoIdUtils.randomNanoId();
String bookSaveFolder = QCloudCosUtils.BOOK_SAVE_FOLDER;
// 判断对象是否存在
Boolean isExist = qCloudCosUtils.doesObjectExist(bookSaveFolder, fileSha1);
String url = null;
Map resultMap = new HashMap();
resultMap.put("guid", urlGUID);
switch (httpMethodName) {
case PUT:
// 上传文件
if (isExist) throw new BusinessException(BusinessErrorCode.FILE_ALREADY_EXIST, "文件已存在");
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:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
if (visitorFingerprint == null || !visitorFingerprintLogService.saveFingerprint("FailureFeedback", userModel.getId(), visitorFingerprint)) {
throw new BusinessException(BusinessErrorCode.OPERATION_NOT_ALLOWED, "参数错误,请联系管理员处理");
}
url = qCloudCosUtils.generatePresignedUrlForGET(userModel.getId(), bookSaveFolder, fileSha1, expireMinute, urlGUID, fileNameAndExt);
break;
case DELETE:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileSha1, expireMinute, urlGUID);
break;
default:
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数暂不支持");
}
resultMap.put("url", url);
return CommonReturnType.create(resultMap);
}
/**
* 腾讯云 COS 文件上传成功回调方法
*
* @param eventStr
* @param contextStr
* @return
* @throws BusinessException
*/
@ApiOperation(value = "【COS】腾讯云 COS 文件上传成功回调", notes = "客户端向腾讯云 COS 存储桶上传文件完毕,有云函数触发此请求")
@RequestMapping(value = "/upload/cos-check-file-state", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType cosCheckFileStatus(
// @RequestParam() Map<String, String> params,
@RequestParam(value = "event") String eventStr,
@RequestParam(value = "context", required = false) String contextStr
) throws BusinessException, InvocationTargetException, IllegalAccessException {
JSONObject eventObject;
try {
eventObject = JSON.parseObject(eventStr);
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "event参数不合法");
}
String cosBucketName, appid, cosRegion, eventName, key;
try {
// 获取 Records 节点
JSONArray records = eventObject.getJSONArray("Records");
JSONObject record = records.getJSONObject(0);
JSONObject cos = record.getJSONObject("cos");
JSONObject cosBucket = cos.getJSONObject("cosBucket");
appid = cosBucket.getString("appid");
cosBucketName = cosBucket.getString("name");
if (Objects.equals(appid, "1253970026") && Objects.equals(cosBucketName, "testpic")) {
// 执行的是腾讯云云函数的测试请求
return CommonReturnType.create("您的云函数配置成功。");
}
cosRegion = cosBucket.getString("cosRegion");
JSONObject cosObject = cos.getJSONObject("cosObject");
key = cosObject.getString("key");
// 获取 /1000000000/bookshelfplus/fileSha1 中的 fileSha1 部分
key = key.substring(key.indexOf("/", key.indexOf("/", key.indexOf("/") + 1) + 1) + 1);
JSONObject event = record.getJSONObject("event");
eventName = event.getString("eventName");
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "JSON解析出错");
}
// 判断是否是由系统的存储桶触发
if (qCloudCosConfig.getBucketName().equals(cosBucketName + "-" + appid) &&
qCloudCosConfig.getRegionName().equals(cosRegion) &&
"cos:ObjectCreated:Put".equals(eventName)) {
// 是由系统的存储桶触发的,则认为是文件上传成功
// 通过文件 key 获取文件对象
FileObjectModel fileObject = fileObjectService.getFileObjectByFilePath(QCloudCosUtils.BOOK_SAVE_FOLDER + key);
// 如果找不到,就抛出异常
if (fileObject == null) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在!");
}
// 更新文件对象状态
Boolean isSuccess1 = fileObjectService.updateFileStatus(fileObject.getId(), "SUCCESS");
if (!isSuccess1) {
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "更新文件状态失败");
}
} else {
// 不是由系统的存储桶触发的
return CommonReturnType.create("Not triggered by the bucket specified in the configuration file, skip.");
}
return CommonReturnType.create("success");
}
private FileVO convertFileVOFromModel(FileModel fileModel) {
if (fileModel == null) {
return null;
@@ -329,68 +151,3 @@ public class FileController extends BaseController {
return fileVO;
}
}
/*
示例返回
event
{
"Records": [
{
"cos": {
"cosBucket": {
"appid": "1302260381",
"cosRegion": "ap-shanghai",
"name": "bookshelfplus",
"region": "sh",
"s3Region": "ap-shanghai"
},
"cosNotificationId": "unkown",
"cosObject": {
"key": "/1302260381/bookshelfplus/!!!!!!!",
"meta": {
"Content-Type": "text/plain",
"ETag": "\"0d7316832fef232e5dcdcf81f39bfdba\"",
"x-cos-request-id": "NjI1OTNmOWNfNGIzN2YyMDlfMmJhZjVfNDJkZTBmYQ==",
"x-cos-storage-class": "Standard"
},
"size": 557,
"url": "http://bookshelfplus-1302260381.cos.ap-shanghai.myqcloud.com/%21%21%21%21%21%21%21",
"vid": ""
},
"cosSchemaVersion": "1.0"
},
"event": {
"eventName": "cos:ObjectCreated:Put",
"eventQueue": "qcs:0:scf:ap-shanghai:appid/1302260381:default.bookshelf-scf.$DEFAULT",
"eventSource": "qcs::cos",
"eventTime": 1650016156,
"eventVersion": "1.0",
"reqid": 0,
"requestParameters": {
"requestHeaders": {
"Authorization": "q-sign-algorithm=sha1&q-ak=AKIDgEWYJo2yd7KGvIPFn45pJWT9YgX8RTEi&q-sign-time=1650016155;1650017955&q-key-time=1650016155;1650017955&q-header-list=host&q-url-param-list=by;guid;userid&q-signature=0ceb85180d6b0b665662d5d139d4276cdc0fbbbd"
},
"requestSourceIP": "117.154.65.144"
},
"reservedInfo": ""
}
}
]
}
context
{
"callbackWaitsForEmptyEventLoop": true,
"memory_limit_in_mb": 512,
"time_limit_in_ms": 3000,
"request_id": "279ba5cc-e435-4af9-8ede-baa71373d75b",
"environment": "{\"SCF_NAMESPACE\":\"default\"}",
"environ": "SCF_NAMESPACE=default;SCF_NAMESPACE=default",
"function_version": "$LATEST",
"function_name": "bookshelf-scf",
"namespace": "default",
"tencentcloud_region": "ap-shanghai",
"tencentcloud_appid": "1302260381",
"tencentcloud_uin": "100014397291"
}
*/

View File

@@ -1,14 +1,17 @@
package plus.bookshelf.Controller.Controller;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qcloud.cos.http.HttpMethodName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import plus.bookshelf.Common.Enum.FileStorageMediumEnum;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
@@ -18,16 +21,12 @@ import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Controller.VO.FileObjectVO;
import plus.bookshelf.Service.Impl.*;
import plus.bookshelf.Service.Model.FailureFeedbackModel;
import plus.bookshelf.Service.Model.FileModel;
import plus.bookshelf.Service.Model.FileObjectModel;
import plus.bookshelf.Service.Model.UserModel;
import plus.bookshelf.Service.Service.CosPresignedUrlGenerateLogService;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Objects;
import java.util.*;
@Api(tags = "文件对象管理")
@Controller("file/object")
@@ -37,15 +36,15 @@ public class FileObjectController extends BaseController {
@Autowired
QCloudCosConfig qCloudCosConfig;
@Autowired
CosPresignedUrlGenerateLogService cosPresignedUrlGenerateLogService;
@Autowired
UserServiceImpl userService;
@Autowired
FileServiceImpl fileService;
@Autowired
CosPresignedUrlGenerateLogService cosPresignedUrlGenerateLogService;
@Autowired
FileObjectServiceImpl fileObjectService;
@@ -178,6 +177,199 @@ public class FileObjectController extends BaseController {
return CommonReturnType.create(isSuccess);
}
@ApiOperation(value = "【管理员】删除文件对象", notes = "管理员在后台删除文件对象")
@RequestMapping(value = "delete", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
@Transactional
public CommonReturnType deleteFileObject(@RequestParam(value = "token", required = false) String token,
@RequestParam(required = true, value = "id") Integer fileObjectId) throws BusinessException {
// 已经在 getUserByToken 方法中判断了 token 为空、不合法;用户不存在情况,此处无需再判断
UserModel userModel = userService.getUserByToken(redisTemplate, token);
// 删除书籍
Integer affectRows = fileObjectService.deleteFileObject(fileObjectId);
if (affectRows > 0) {
return CommonReturnType.create("success");
} else {
return CommonReturnType.create("failed");
}
}
/**
* 创建文件操作预授权URL
*
* @param httpMethod 请求的 HTTP 方法,上传请求用 PUT下载请求用 GET删除请求用 DELETE
* @param token 当前登录用户的 token
* @param fileName 文件名
* @param expireMinute 过期时间(分钟)
* @return
* @throws BusinessException
*/
@ApiOperation(value = "【用户|管理员】创建腾讯云 COS 预授权 URL", notes = "")
@RequestMapping(value = "/cos/{httpMethod}", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType cos(@PathVariable(value = "httpMethod") String httpMethod,
@RequestParam(value = "token") String token,
@RequestParam(value = "fileSha1") String fileSha1,
@RequestParam(value = "expireMinute", required = false) Integer expireMinute,
// 以下为 PUT 请求必传参数
@RequestParam(value = "fileName", required = false) String fileName, // 不含扩展名
@RequestParam(value = "fileSize", required = false) Long fileSize,
// @RequestParam(value = "fileType", required = false) String fileType,
@RequestParam(value = "lastModified", required = false) Long lastModified,
@RequestParam(value = "fileExt", required = false) String fileExt,
@RequestParam(value = "fileId", required = false) Integer fileId, // 关联的文件ID创建新文件则为0
// 以下为 GET 请求必传参数
@RequestParam(value = "fileNameAndExt", required = false) String fileNameAndExt,
@RequestParam(value = "visitorId", required = false) String visitorFingerprint
) throws BusinessException, InvocationTargetException, IllegalAccessException {
if (expireMinute == null) {
expireMinute = 30;
} else if (expireMinute > 60) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "expireMinute 参数不能大于 60");
} else if (expireMinute < 1) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "expireMinute 参数不能小于 1");
}
// 已经在 getUserByToken 方法中判断了 token 为空、不合法;用户不存在情况,此处无需再判断
UserModel userModel = userService.getUserByToken(redisTemplate, token);
// 判断httpMethod 是否合法
HttpMethodName httpMethodName;
try {
httpMethodName = HttpMethodName.valueOf(httpMethod.toUpperCase());
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数不合法");
}
QCloudCosUtils qCloudCosUtils = new QCloudCosUtils(qCloudCosConfig, cosPresignedUrlGenerateLogService);
// 当次生成下载链接的全局唯一Id
String urlGUID = NanoIdUtils.randomNanoId();
String bookSaveFolder = QCloudCosUtils.BOOK_SAVE_FOLDER;
// 判断对象是否存在
Boolean isExist = qCloudCosUtils.doesObjectExist(bookSaveFolder, fileSha1);
String url = null;
Map resultMap = new HashMap();
resultMap.put("guid", urlGUID);
switch (httpMethodName) {
case PUT:
// 上传文件
if (isExist) throw new BusinessException(BusinessErrorCode.FILE_ALREADY_EXIST, "文件已存在");
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:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
if (visitorFingerprint == null || !visitorFingerprintLogService.saveFingerprint("FailureFeedback", userModel.getId(), visitorFingerprint)) {
throw new BusinessException(BusinessErrorCode.OPERATION_NOT_ALLOWED, "参数错误,请联系管理员处理");
}
url = qCloudCosUtils.generatePresignedUrlForGET(userModel.getId(), bookSaveFolder, fileSha1, expireMinute, urlGUID, fileNameAndExt);
break;
case DELETE:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileSha1, expireMinute, urlGUID);
break;
default:
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数暂不支持");
}
resultMap.put("url", url);
return CommonReturnType.create(resultMap);
}
/**
* 腾讯云 COS 文件上传成功回调方法
*
* @param eventStr
* @param contextStr
* @return
* @throws BusinessException
*/
@ApiOperation(value = "【COS】腾讯云 COS 文件上传成功回调", notes = "客户端向腾讯云 COS 存储桶上传文件完毕,有云函数触发此请求")
@RequestMapping(value = "/upload/cos-check-file-state", method = {RequestMethod.POST}, consumes = {CONTENT_TYPE_FORMED})
@ResponseBody
public CommonReturnType cosCheckFileStatus(
// @RequestParam() Map<String, String> params,
@RequestParam(value = "event") String eventStr,
@RequestParam(value = "context", required = false) String contextStr
) throws BusinessException, InvocationTargetException, IllegalAccessException {
JSONObject eventObject;
try {
eventObject = JSON.parseObject(eventStr);
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "event参数不合法");
}
String cosBucketName, appid, cosRegion, eventName, key;
try {
// 获取 Records 节点
JSONArray records = eventObject.getJSONArray("Records");
JSONObject record = records.getJSONObject(0);
JSONObject cos = record.getJSONObject("cos");
JSONObject cosBucket = cos.getJSONObject("cosBucket");
appid = cosBucket.getString("appid");
cosBucketName = cosBucket.getString("name");
if (Objects.equals(appid, "1253970026") && Objects.equals(cosBucketName, "testpic")) {
// 执行的是腾讯云云函数的测试请求
return CommonReturnType.create("您的云函数配置成功。");
}
cosRegion = cosBucket.getString("cosRegion");
JSONObject cosObject = cos.getJSONObject("cosObject");
key = cosObject.getString("key");
// 获取 /1000000000/bookshelfplus/fileSha1 中的 fileSha1 部分
key = key.substring(key.indexOf("/", key.indexOf("/", key.indexOf("/") + 1) + 1) + 1);
JSONObject event = record.getJSONObject("event");
eventName = event.getString("eventName");
} catch (Exception e) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "JSON解析出错");
}
// 判断是否是由系统的存储桶触发
if (qCloudCosConfig.getBucketName().equals(cosBucketName + "-" + appid) &&
qCloudCosConfig.getRegionName().equals(cosRegion) &&
"cos:ObjectCreated:Put".equals(eventName)) {
// 是由系统的存储桶触发的,则认为是文件上传成功
// 通过文件 key 获取文件对象
FileObjectModel fileObject = fileObjectService.getFileObjectByFilePath(QCloudCosUtils.BOOK_SAVE_FOLDER + key);
// 如果找不到,就抛出异常
if (fileObject == null) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在!");
}
// 更新文件对象状态
Boolean isSuccess1 = fileObjectService.updateFileStatus(fileObject.getId(), "SUCCESS");
if (!isSuccess1) {
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "更新文件状态失败");
}
} else {
// 不是由系统的存储桶触发的
return CommonReturnType.create("Not triggered by the bucket specified in the configuration file, skip.");
}
return CommonReturnType.create("success");
}
public static FileObjectVO convertFileObjectVOFromModel(FileObjectModel fileObjectModel) {
if (fileObjectModel == null) {
return null;
@@ -192,3 +384,68 @@ public class FileObjectController extends BaseController {
return fileObjectVO;
}
}
/*
示例返回
event
{
"Records": [
{
"cos": {
"cosBucket": {
"appid": "1302260381",
"cosRegion": "ap-shanghai",
"name": "bookshelfplus",
"region": "sh",
"s3Region": "ap-shanghai"
},
"cosNotificationId": "unkown",
"cosObject": {
"key": "/1302260381/bookshelfplus/!!!!!!!",
"meta": {
"Content-Type": "text/plain",
"ETag": "\"0d7316832fef232e5dcdcf81f39bfdba\"",
"x-cos-request-id": "NjI1OTNmOWNfNGIzN2YyMDlfMmJhZjVfNDJkZTBmYQ==",
"x-cos-storage-class": "Standard"
},
"size": 557,
"url": "http://bookshelfplus-1302260381.cos.ap-shanghai.myqcloud.com/%21%21%21%21%21%21%21",
"vid": ""
},
"cosSchemaVersion": "1.0"
},
"event": {
"eventName": "cos:ObjectCreated:Put",
"eventQueue": "qcs:0:scf:ap-shanghai:appid/1302260381:default.bookshelf-scf.$DEFAULT",
"eventSource": "qcs::cos",
"eventTime": 1650016156,
"eventVersion": "1.0",
"reqid": 0,
"requestParameters": {
"requestHeaders": {
"Authorization": "q-sign-algorithm=sha1&q-ak=AKIDgEWYJo2yd7KGvIPFn45pJWT9YgX8RTEi&q-sign-time=1650016155;1650017955&q-key-time=1650016155;1650017955&q-header-list=host&q-url-param-list=by;guid;userid&q-signature=0ceb85180d6b0b665662d5d139d4276cdc0fbbbd"
},
"requestSourceIP": "117.154.65.144"
},
"reservedInfo": ""
}
}
]
}
context
{
"callbackWaitsForEmptyEventLoop": true,
"memory_limit_in_mb": 512,
"time_limit_in_ms": 3000,
"request_id": "279ba5cc-e435-4af9-8ede-baa71373d75b",
"environment": "{\"SCF_NAMESPACE\":\"default\"}",
"environ": "SCF_NAMESPACE=default;SCF_NAMESPACE=default",
"function_version": "$LATEST",
"function_name": "bookshelf-scf",
"namespace": "default",
"tencentcloud_region": "ap-shanghai",
"tencentcloud_appid": "1302260381",
"tencentcloud_uin": "100014397291"
}
*/

View File

@@ -8,10 +8,13 @@ import org.springframework.transaction.annotation.Transactional;
import plus.bookshelf.Common.Enum.FileStorageMediumEnum;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
import plus.bookshelf.Common.FileManager.QCloudCosUtils;
import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Dao.DO.FileObjectDO;
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.FileObjectService;
import java.lang.reflect.InvocationTargetException;
@@ -35,6 +38,12 @@ public class FileObjectServiceImpl implements FileObjectService {
@Autowired
FileServiceImpl fileService;
@Autowired
QCloudCosConfig qCloudCosConfig;
@Autowired
CosPresignedUrlGenerateLogService cosPresignedUrlGenerateLogService;
/**
* 通过书本Id获取关联文件进而获取所有关联文件对应的文件对象
*
@@ -252,4 +261,41 @@ public class FileObjectServiceImpl implements FileObjectService {
return fileObjectModels;
}
/**
* 删除文件对象
*
* @param fileObjectId
* @return
* @throws BusinessException
*/
@Override
public Integer deleteFileObject(Integer fileObjectId) throws BusinessException {
if (fileObjectId == null || fileObjectId == 0) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件对象 Id 不能为空");
}
FileObjectDO fileObjectDO = fileObjectDOMapper.selectByPrimaryKey(fileObjectId);
if (fileObjectDO == null) {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件对象不存在,或许您已经删掉这个文件了,刷新下页面吧");
}
// 删除对象存储中的文件
QCloudCosUtils qCloudCosUtils = new QCloudCosUtils(qCloudCosConfig, cosPresignedUrlGenerateLogService);
Boolean isSuccess = qCloudCosUtils.deleteObject(fileObjectDO.getFilePath());
if (!isSuccess) {
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "删除文件对象失败,请稍后重试");
}
// 确认文件是否被删除
Boolean isStillExist = qCloudCosUtils.doesObjectExist(fileObjectDO.getFilePath());
if (isStillExist) {
//
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "删除腾讯云COS存储桶中文件出现异常请稍后重试");
}
// 删除数据库中记录
int affecctRows = fileObjectDOMapper.deleteByPrimaryKey(fileObjectId);
return affecctRows;
}
}

View File

@@ -93,4 +93,13 @@ public interface FileObjectService {
* @throws BusinessException
*/
List<FileObjectModel> getFileObjectListByFileId(Integer fileId) throws InvocationTargetException, IllegalAccessException, BusinessException;
/**
* 删除文件对象
*
* @param fileObjectId
* @return
* @throws BusinessException
*/
Integer deleteFileObject(Integer fileObjectId) throws BusinessException;
}