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

通过书本ID获取所有文件对象信息;前端书籍详情页面直链下载功能完成;后端COS部分功能完善;下载文件设置"Content-Disposition"为"attachment; filename="

This commit is contained in:
2022-04-16 22:19:46 +08:00
parent 30c557d046
commit 372a22e2e4
7 changed files with 196 additions and 23 deletions

View File

@@ -2,10 +2,13 @@ package plus.bookshelf.Common.FileManager;
import com.qcloud.cos.COSClient;
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.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.GeneratePresignedUrlRequest;
import com.qcloud.cos.model.ResponseHeaderOverrides;
import com.qcloud.cos.region.Region;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
@@ -86,7 +89,7 @@ public class QCloudCosUtils {
// 存储桶的命名格式为 BucketName-APPID此处填写的存储桶名称必须为此格式
String bucketName = qCloudCosConfig.getBucketName();
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
String key = qCloudCosConfig.getKeyName() + objectKey;
String key = qCloudCosConfig.getKeyName() + folder + objectKey;
return cosClient.doesObjectExist(bucketName, key);
}
@@ -104,13 +107,12 @@ public class QCloudCosUtils {
public String generatePresignedUrl(Integer userId, HttpMethodName httpMethodName, String savePath, String objectKey, Integer expireMinute, String urlGUID) throws BusinessException {
// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
// 详细代码参见本页:简单操作 -> 创建 COSClient
// COSClient cosClient = createCOSClient();
COSClient cosClient = createCOSClient();
// 存储桶的命名格式为 BucketName-APPID此处填写的存储桶名称必须为此格式
String bucketName = qCloudCosConfig.getBucketName();
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
String key = qCloudCosConfig.getKeyName() + objectKey;
String key = qCloudCosConfig.getKeyName() + savePath + objectKey;
// 设置签名过期时间(可选), 若未进行设置则默认使用 ClientConfig 中的签名过期时间(1小时)
// 这里设置签名在 expireMinute 分钟后过期
@@ -142,6 +144,61 @@ public class QCloudCosUtils {
return url.toString();
}
/**
* 生成预签名URL (下载使用,用于下载时指定下载的文件名)
* <p>
* refer: https://cloud.tencent.com/document/product/436/35217
*
* @param userId 当前登录用户的 id
* @param savePath
* @param objectKey 文件对象的 key
* @param expireMinute 过期时间
* @param urlGUID
* @param fileNameForUser
* @return
* @throws BusinessException
*/
public String generatePresignedUrlForGET(Integer userId, String savePath, String objectKey, Integer expireMinute, String urlGUID, String fileNameForUser) throws BusinessException {
// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
// 详细代码参见本页:简单操作 -> 创建 COSClient
COSClient cosClient = createCOSClient();
// 存储桶的命名格式为 BucketName-APPID此处填写的存储桶名称必须为此格式
String bucketName = qCloudCosConfig.getBucketName();
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
String key = qCloudCosConfig.getKeyName() + savePath + objectKey;
GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 设置下载时返回的 http 头
ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
responseHeaders.setContentDisposition("attachment; filename=\"" + fileNameForUser + "\""); // 作为附件下载;设置返回头部里包含文件名信息
responseHeaders.setCacheControl("no-cache");
req.setResponseHeaders(responseHeaders);
// 设置签名过期时间(可选),若未进行设置,则默认使用 ClientConfig 中的签名过期时间(1小时)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 30L * 60L * 1000L);
req.setExpiration(expirationDate);
// 填写本次请求的参数,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的参数
Map<String, String> params = new HashMap<>();
req.addRequestParameter("by", "书栖网 bookshelf.plus");
req.addRequestParameter("userId", String.valueOf(userId));
req.addRequestParameter("guid", urlGUID);
// 填写本次请求的头部
// host 必填
req.putCustomRequestHeader(Headers.HOST, cosClient.getClientConfig().getEndpointBuilder().buildGeneralApiEndpoint(bucketName));
// req.putCustomRequestHeader("header1", "value1");
URL url = cosClient.generatePresignedUrl(req);
// 记录用户操作日志
cosPresignedUrlGenerateLogService.log(userId, expireMinute, HttpMethodName.GET.name(), key, urlGUID);
return url.toString();
}
/**
* 销毁 CosClient 对象方法
*/

View File

@@ -53,7 +53,7 @@ public class FileController extends BaseController {
@ApiOperation(value = "书籍下载页面获取文件提供的下载方式", notes = "")
@RequestMapping(value = "getFile", method = {RequestMethod.GET})
@ResponseBody
public CommonReturnType getFile(@RequestParam(value = "bookId", required = false) Integer bookId) throws BusinessException {
public CommonReturnType getFile(@RequestParam(value = "bookId", required = false) Integer bookId) throws BusinessException, InvocationTargetException, IllegalAccessException {
List<FileModel> fileModels = fileService.getFile(bookId);
List<FileVO> fileVOS = new ArrayList<>();
@@ -61,7 +61,19 @@ public class FileController extends BaseController {
FileVO fileVO = convertFileVOFromModel(fileModel);
fileVOS.add(fileVO);
}
return CommonReturnType.create(fileVOS);
List<FileObjectModel> fileObjectModels = fileObjectService.getFileObjectByBookId(bookId);
List<FileObjectVO> fileObjectVOS = new ArrayList<>();
for (FileObjectModel fileObjectModel : fileObjectModels) {
FileObjectVO fileObjectVO = convertFileObjectVOFromModel(fileObjectModel);
fileObjectVOS.add(fileObjectVO);
}
Map<String, Object> map = new HashMap<>();
map.put("file", fileVOS);
map.put("fileObject", fileObjectVOS);
return CommonReturnType.create(map);
}
@ApiOperation(value = "【管理员】查询文件列表", notes = "查询文件列表")
@@ -142,16 +154,19 @@ public class FileController extends BaseController {
@ResponseBody
public CommonReturnType cos(@PathVariable(value = "httpMethod") String httpMethod,
@RequestParam(value = "token") String token,
@RequestParam(value = "fileName") String fileName, // 不含扩展名
@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 = "fileSha1", required = false) String fileSha1,
@RequestParam(value = "fileExt", required = false) String fileExt,
@RequestParam(value = "fileId", required = false) Integer fileId // 关联的文件ID创建新文件则为0
@RequestParam(value = "fileId", required = false) Integer fileId, // 关联的文件ID创建新文件则为0
// 以下为 GET 请求必传参数
@RequestParam(value = "fileNameAndExt", required = false) String fileNameAndExt
) throws BusinessException, InvocationTargetException, IllegalAccessException {
if (expireMinute == null) {
expireMinute = 30;
@@ -180,26 +195,28 @@ public class FileController extends BaseController {
// 判断对象是否存在
Boolean isExist = qCloudCosUtils.doesObjectExist(bookSaveFolder, fileSha1);
switch (httpMethodName) {
String url = null;
switch (httpMethodName) {
case PUT:
// 上传文件
if (isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件已存在");
fileObjectService.uploadFile(fileId, fileName, bookSaveFolder + fileSha1, fileSize,
fileSha1, fileExt, fileName, FileStorageMediumEnum.QCLOUD_COS, "", lastModified);
url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileSha1, expireMinute, urlGUID);
break;
case GET:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
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 参数暂不支持");
}
String url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileSha1, 30, urlGUID);
Map map = new HashMap();
map.put("url", url);
map.put("guid", urlGUID);

View File

@@ -67,4 +67,12 @@ public interface FileObjectDOMapper {
* @return
*/
FileObjectDO selectByFilePath(String filePath);
/**
* 通过书本Id获取关联文件进而获取所有关联文件对应的文件对象
*
* @param bookId 书本Id
* @return
*/
FileObjectDO[] selectFileObjectByBookId(Integer bookId);
}

View File

@@ -36,6 +36,25 @@ public class FileObjectServiceImpl implements FileObjectService {
@Autowired
FileServiceImpl fileService;
/**
* 通过书本Id获取关联文件进而获取所有关联文件对应的文件对象
*
* @return
*/
@Override
public List<FileObjectModel> getFileObjectByBookId(Integer bookId) throws InvocationTargetException, IllegalAccessException {
FileObjectDO[] fileObjectDOS = fileObjectDOMapper.selectFileObjectByBookId(bookId);
List<FileObjectModel> fileObjectModels = new ArrayList<>();
for (FileObjectDO fileObjectDO : fileObjectDOS) {
FileObjectModel fileObjectModel = convertFromDataObject(fileObjectDO);
fileObjectModels.add(fileObjectModel);
}
return fileObjectModels;
}
/**
* 列出所有文件对象
*

View File

@@ -10,6 +10,16 @@ import java.util.List;
public interface FileObjectService {
/**
* 通过书本Id获取关联文件进而获取所有关联文件对应的文件对象
*
* @param bookId
* @return
* @throws InvocationTargetException
* @throws IllegalAccessException
*/
List<FileObjectModel> getFileObjectByBookId(Integer bookId) throws InvocationTargetException, IllegalAccessException;
/**
* 列出所有文件对象
*