mirror of
https://gitee.com/bookshelfplus/bookshelfplus
synced 2025-09-01 22:53:29 +08:00
管理员上传文件到存储桶功能基本完成;可以前端计算文件SHA1;添加腾讯云生成SecretId、SecretKey文档
This commit is contained in:
@@ -1,18 +1,11 @@
|
||||
package plus.bookshelf;
|
||||
|
||||
import com.qcloud.cos.http.HttpMethodName;
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import plus.bookshelf.Common.FileManager.QCloudCosUtils;
|
||||
import plus.bookshelf.Config.QCloudCosConfig;
|
||||
|
||||
/**
|
||||
* Hello world!
|
||||
*/
|
||||
@SpringBootApplication(scanBasePackages = {"plus.bookshelf"})
|
||||
@RestController
|
||||
@MapperScan("plus.bookshelf.Dao.Mapper")
|
||||
@@ -24,19 +17,12 @@ public class App {
|
||||
|
||||
// 启动SpringBoot项目
|
||||
SpringApplication.run(App.class, args);
|
||||
|
||||
System.out.println("backend service started successfully.");
|
||||
}
|
||||
|
||||
@RequestMapping("/")
|
||||
public String Home() {
|
||||
return "首页";
|
||||
}
|
||||
|
||||
@Autowired
|
||||
QCloudCosConfig qCloudCosConfig;
|
||||
|
||||
@RequestMapping("/cos")
|
||||
public String cos() {
|
||||
QCloudCosUtils QCloudCosUtils = new QCloudCosUtils(qCloudCosConfig);
|
||||
return QCloudCosUtils.getUrl("user-login-token", HttpMethodName.POST, "mydemo.jpg", 5);
|
||||
return "backend service is running.";
|
||||
}
|
||||
}
|
||||
|
23
bookshelfplus/src/main/java/plus/bookshelf/AppListener.java
Normal file
23
bookshelfplus/src/main/java/plus/bookshelf/AppListener.java
Normal file
@@ -0,0 +1,23 @@
|
||||
package plus.bookshelf;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import plus.bookshelf.Common.FileManager.QCloudCosUtils;
|
||||
|
||||
@Component
|
||||
public class AppListener implements CommandLineRunner, DisposableBean {
|
||||
//应用启动成功后的回调
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
System.out.println("prepare to start ...");
|
||||
}
|
||||
|
||||
//应用启动关闭前的回调
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
System.out.println("prepare to close ...");
|
||||
QCloudCosUtils.destoryInstance();
|
||||
System.out.println("close success ...");
|
||||
}
|
||||
}
|
@@ -10,21 +10,34 @@ import com.qcloud.cos.http.HttpProtocol;
|
||||
import com.qcloud.cos.region.Region;
|
||||
import plus.bookshelf.Config.QCloudCosConfig;
|
||||
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.net.URL;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class QCloudCosUtils {
|
||||
|
||||
// 配置信息
|
||||
QCloudCosConfig qCloudCosConfig;
|
||||
|
||||
/**
|
||||
* 构造函数
|
||||
*
|
||||
* @param qCloudCosConfig
|
||||
*/
|
||||
public QCloudCosUtils(QCloudCosConfig qCloudCosConfig) {
|
||||
this.qCloudCosConfig = qCloudCosConfig;
|
||||
}
|
||||
|
||||
private static COSClient _cosClient = null;
|
||||
|
||||
// refer: https://cloud.tencent.com/document/product/436/35217#.E5.88.9B.E5.BB.BA-cosclient
|
||||
// 创建 COSClient 实例,这个实例用来后续调用请求
|
||||
COSClient createCOSClient() {
|
||||
if (_cosClient != null) {
|
||||
return _cosClient;
|
||||
}
|
||||
// 设置用户身份信息。
|
||||
// SECRETID 和 SECRETKEY 请登录访问管理控制台 https://console.cloud.tencent.com/cam/capi 进行查看和管理
|
||||
String secretId = qCloudCosConfig.getAccessKey();
|
||||
@@ -54,13 +67,19 @@ public class QCloudCosUtils {
|
||||
// clientConfig.setHttpProxyIp("httpProxyIp");
|
||||
// clientConfig.setHttpProxyPort(80);
|
||||
|
||||
// 生成 cos 客户端。
|
||||
return new COSClient(cred, clientConfig);
|
||||
// 生成 cos 客户端
|
||||
_cosClient = new COSClient(cred, clientConfig);
|
||||
System.out.println("cosClient construct success.");
|
||||
return _cosClient;
|
||||
}
|
||||
|
||||
public String getUrl(String token, String objectKey) {
|
||||
// 如果不指定失效时间,默认为 30 分钟
|
||||
return getUrl(token, HttpMethodName.GET, objectKey, 30);
|
||||
public Boolean doesObjectExist(String objectKey) {
|
||||
COSClient cosClient = createCOSClient();
|
||||
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
|
||||
String bucketName = qCloudCosConfig.getBucketName();
|
||||
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
|
||||
String key = qCloudCosConfig.getKeyName() + objectKey;
|
||||
return cosClient.doesObjectExist(bucketName, key);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -74,9 +93,10 @@ public class QCloudCosUtils {
|
||||
* @param expireMinute 过期时间
|
||||
* @return
|
||||
*/
|
||||
public String getUrl(String token, HttpMethodName httpMethodName, String objectKey, Integer expireMinute) {
|
||||
public String generatePresignedUrl(String token, HttpMethodName httpMethodName, String objectKey, Integer expireMinute) {
|
||||
// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
|
||||
// 详细代码参见本页:简单操作 -> 创建 COSClient
|
||||
// COSClient cosClient = createCOSClient();
|
||||
COSClient cosClient = createCOSClient();
|
||||
|
||||
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
|
||||
@@ -92,24 +112,27 @@ public class QCloudCosUtils {
|
||||
Map<String, String> params = new HashMap<>();
|
||||
params.put("poweredBy", "bookshelf.plus");
|
||||
params.put("userToken", token);
|
||||
|
||||
String downloadGUID = NanoIdUtils.randomNanoId();
|
||||
params.put("downloadGUID", downloadGUID); // 当次生成下载链接的全局唯一Id
|
||||
params.put("温馨提示", "您的每一次下载都会被详细记录,请不要试图绕过系统获取文件下载直链,这是违法行为,请自重!");
|
||||
|
||||
// 填写本次请求的头部,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的头部
|
||||
Map<String, String> headers = new HashMap<>();
|
||||
// headers.put("header1", "value1");
|
||||
|
||||
// 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE
|
||||
HttpMethodName method = HttpMethodName.GET;
|
||||
HttpMethodName method = httpMethodName;
|
||||
|
||||
URL url = cosClient.generatePresignedUrl(bucketName, key, expirationDate, method, headers, params);
|
||||
System.out.println(url.toString());
|
||||
|
||||
// [TODO] 确认本进程不再使用 cosClient 实例之后,关闭之
|
||||
cosClient.shutdown();
|
||||
// System.out.println(url.toString());
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
public static void destoryInstance() {
|
||||
if (_cosClient != null) {
|
||||
// 确认本进程不再使用 cosClient 实例之后,关闭之
|
||||
_cosClient.shutdown();
|
||||
System.out.println("cosClient destory success.");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,84 @@
|
||||
package plus.bookshelf.Controller.Controller;
|
||||
|
||||
import com.qcloud.cos.http.HttpMethodName;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
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.Service.Impl.UserServiceImpl;
|
||||
import plus.bookshelf.Service.Model.UserModel;
|
||||
|
||||
@Api(tags = "文件管理")
|
||||
@Controller("file")
|
||||
@RequestMapping("/file")
|
||||
public class FileController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
QCloudCosConfig qCloudCosConfig;
|
||||
|
||||
@Autowired
|
||||
UserServiceImpl userService;
|
||||
|
||||
/**
|
||||
* 创建文件操作预授权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 = "fileName") String fileName,
|
||||
@RequestParam(value = "expireMinute", required = false) Integer expireMinute) throws BusinessException {
|
||||
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);
|
||||
|
||||
// 判断对象是否存在
|
||||
Boolean isExist = qCloudCosUtils.doesObjectExist(fileName);
|
||||
switch (httpMethodName) {
|
||||
case PUT:
|
||||
if (isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件已存在");
|
||||
break;
|
||||
case GET:
|
||||
case DELETE:
|
||||
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
|
||||
break;
|
||||
default:
|
||||
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数暂不支持");
|
||||
}
|
||||
|
||||
String url = qCloudCosUtils.generatePresignedUrl(token, httpMethodName, fileName, 30);
|
||||
|
||||
return CommonReturnType.create(url);
|
||||
}
|
||||
}
|
@@ -0,0 +1,236 @@
|
||||
package plus.bookshelf.Dao.DO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public class FileOperationDO {
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.user_id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private Integer userId;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.time
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private Date time;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.expire_minute
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private String expireMinute;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.method
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private String method;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.file_path
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private String filePath;
|
||||
|
||||
/**
|
||||
*
|
||||
* This field was generated by MyBatis Generator.
|
||||
* This field corresponds to the database column file_operation_log.url_guid
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
private String urlGuid;
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.id
|
||||
*
|
||||
* @return the value of file_operation_log.id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.id
|
||||
*
|
||||
* @param id the value for file_operation_log.id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.user_id
|
||||
*
|
||||
* @return the value of file_operation_log.user_id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public Integer getUserId() {
|
||||
return userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.user_id
|
||||
*
|
||||
* @param userId the value for file_operation_log.user_id
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setUserId(Integer userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.time
|
||||
*
|
||||
* @return the value of file_operation_log.time
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public Date getTime() {
|
||||
return time;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.time
|
||||
*
|
||||
* @param time the value for file_operation_log.time
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setTime(Date time) {
|
||||
this.time = time;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.expire_minute
|
||||
*
|
||||
* @return the value of file_operation_log.expire_minute
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public String getExpireMinute() {
|
||||
return expireMinute;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.expire_minute
|
||||
*
|
||||
* @param expireMinute the value for file_operation_log.expire_minute
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setExpireMinute(String expireMinute) {
|
||||
this.expireMinute = expireMinute == null ? null : expireMinute.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.method
|
||||
*
|
||||
* @return the value of file_operation_log.method
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public String getMethod() {
|
||||
return method;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.method
|
||||
*
|
||||
* @param method the value for file_operation_log.method
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setMethod(String method) {
|
||||
this.method = method == null ? null : method.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.file_path
|
||||
*
|
||||
* @return the value of file_operation_log.file_path
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public String getFilePath() {
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.file_path
|
||||
*
|
||||
* @param filePath the value for file_operation_log.file_path
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setFilePath(String filePath) {
|
||||
this.filePath = filePath == null ? null : filePath.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method returns the value of the database column file_operation_log.url_guid
|
||||
*
|
||||
* @return the value of file_operation_log.url_guid
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public String getUrlGuid() {
|
||||
return urlGuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method sets the value of the database column file_operation_log.url_guid
|
||||
*
|
||||
* @param urlGuid the value for file_operation_log.url_guid
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
public void setUrlGuid(String urlGuid) {
|
||||
this.urlGuid = urlGuid == null ? null : urlGuid.trim();
|
||||
}
|
||||
}
|
@@ -0,0 +1,53 @@
|
||||
package plus.bookshelf.Dao.Mapper;
|
||||
|
||||
import plus.bookshelf.Dao.DO.FileOperationDO;
|
||||
|
||||
public interface FileOperationDOMapper {
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int deleteByPrimaryKey(Integer id);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int insert(FileOperationDO record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int insertSelective(FileOperationDO record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
FileOperationDO selectByPrimaryKey(Integer id);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByPrimaryKeySelective(FileOperationDO record);
|
||||
|
||||
/**
|
||||
* This method was generated by MyBatis Generator.
|
||||
* This method corresponds to the database table file_operation_log
|
||||
*
|
||||
* @mbg.generated
|
||||
*/
|
||||
int updateByPrimaryKey(FileOperationDO record);
|
||||
}
|
Reference in New Issue
Block a user