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

定时任务相关修改;添加schedule_task数据库表;BusinessErrorCode扩充;QCloudCosUtils调整(暂存)

This commit is contained in:
2022-04-10 22:09:12 +08:00
parent c84cd46197
commit 63d8192372
14 changed files with 726 additions and 12 deletions

View File

@@ -5,6 +5,7 @@ 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.Service.Impl.ScheduleTaskServiceImpl;
@SpringBootApplication(scanBasePackages = {"plus.bookshelf"})
@RestController
@@ -19,6 +20,10 @@ public class App {
SpringApplication.run(App.class, args);
System.out.println("backend service started successfully.");
// 启动定时任务
ScheduleTaskServiceImpl scheduleTaskService = new ScheduleTaskServiceImpl();
scheduleTaskService.setExecutor();
}
@RequestMapping("/")

View File

@@ -0,0 +1,15 @@
package plus.bookshelf.Common.Enum;
public enum ScheduleTaskActionEnum {
CHECK_FILE_IS_UPLOADED("checkFileIsUploaded");
private String action;
ScheduleTaskActionEnum(String action) {
this.action = action;
}
public String getAction() {
return action;
}
}

View File

@@ -4,6 +4,9 @@ public enum BusinessErrorCode implements CommonError {
// 通用错误类型 10001
PARAMETER_VALIDATION_ERROR(10001, "参数不合法"),
UNKNOWN_ERROR(10002, "未知错误"),
NOT_SUPPORT(10003, "操作或方法不支持"),
NOT_IMPLEMENT(10004, "方法未实现"),
FAULT_ERROR(10005, "致命错误"),
// 20000开头为用户信息相关错误定义
USER_NOT_EXIST(20001, "用户不存在"),

View File

@@ -8,11 +8,11 @@ import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.region.Region;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Service.Service.CosPresignedUrlGenerateLogService;
import javax.annotation.PreDestroy;
import java.net.URL;
import java.util.Date;
import java.util.HashMap;
@@ -20,6 +20,9 @@ import java.util.Map;
public class QCloudCosUtils {
// 定义常量
public static final String BOOK_SAVE_FOLDER = "book/"; //一定要以 / 结尾
// 配置信息
QCloudCosConfig qCloudCosConfig;
@@ -79,7 +82,7 @@ public class QCloudCosUtils {
return _cosClient;
}
public Boolean doesObjectExist(String objectKey) {
public Boolean doesObjectExist(String folder, String objectKey) {
COSClient cosClient = createCOSClient();
// 存储桶的命名格式为 BucketName-APPID此处填写的存储桶名称必须为此格式
String bucketName = qCloudCosConfig.getBucketName();
@@ -93,13 +96,13 @@ public class QCloudCosUtils {
* <p>
* refer: https://cloud.tencent.com/document/product/436/35217
*
* @param token 当前登录用户的 token
* @param userId 当前登录用户的 id
* @param httpMethodName 请求的 HTTP 方法,上传请求用 PUT下载请求用 GET删除请求用 DELETE
* @param objectKey 文件对象的 key
* @param expireMinute 过期时间
* @return
*/
public String generatePresignedUrl(Integer userId, HttpMethodName httpMethodName, String objectKey, Integer expireMinute) throws BusinessException {
public String generatePresignedUrl(Integer userId, HttpMethodName httpMethodName, String savePath, String objectKey, Integer expireMinute, String urlGUID) throws BusinessException {
// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
// 详细代码参见本页:简单操作 -> 创建 COSClient
// COSClient cosClient = createCOSClient();
@@ -118,8 +121,7 @@ public class QCloudCosUtils {
Map<String, String> params = new HashMap<>();
params.put("by", "书栖网 bookshelf.plus");
params.put("userId", String.valueOf(userId));
String urlGUID = NanoIdUtils.randomNanoId();
params.put("guid", urlGUID); // 当次生成下载链接的全局唯一Id
params.put("guid", urlGUID);
// 填写本次请求的头部,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的头部
Map<String, String> headers = new HashMap<>();
@@ -128,6 +130,10 @@ public class QCloudCosUtils {
// 请求的 HTTP 方法,上传请求用 PUT下载请求用 GET删除请求用 DELETE
HttpMethodName method = httpMethodName;
if (method.equals(HttpMethodName.DELETE)) {
throw new BusinessException(BusinessErrorCode.NOT_SUPPORT, "不支持DELETE方法请在后台文件管理页面删除文件而非通过此Api");
}
URL url = cosClient.generatePresignedUrl(bucketName, key, expirationDate, method, headers, params);
// System.out.println(url.toString());

View File

@@ -1,5 +1,6 @@
package plus.bookshelf.Controller.Controller;
import com.aventrix.jnanoid.jnanoid.NanoIdUtils;
import com.qcloud.cos.http.HttpMethodName;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -25,7 +26,9 @@ import plus.bookshelf.Service.Service.CosPresignedUrlGenerateLogService;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Api(tags = "文件管理")
@Controller("file")
@@ -130,13 +133,21 @@ public class FileController extends BaseController {
QCloudCosUtils qCloudCosUtils = new QCloudCosUtils(qCloudCosConfig, cosPresignedUrlGenerateLogService);
// 当次生成下载链接的全局唯一Id
String urlGUID = NanoIdUtils.randomNanoId();
String bookSaveFolder = QCloudCosUtils.BOOK_SAVE_FOLDER;
// 判断对象是否存在
Boolean isExist = qCloudCosUtils.doesObjectExist(fileName);
Boolean isExist = qCloudCosUtils.doesObjectExist(bookSaveFolder, fileName);
switch (httpMethodName) {
case PUT:
if (isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件已存在");
// 添加一个scheduleTask用于检测用户是否上传了文件然后更新数据库中信息
fileService.addScheduleTask(expireMinute, bookSaveFolder, urlGUID, userModel.getId());
break;
case GET:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
break;
case DELETE:
if (!isExist) throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "文件不存在");
break;
@@ -144,8 +155,11 @@ public class FileController extends BaseController {
throw new BusinessException(BusinessErrorCode.PARAMETER_VALIDATION_ERROR, "httpMethod 参数暂不支持");
}
String url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, fileName, 30);
String url = qCloudCosUtils.generatePresignedUrl(userModel.getId(), httpMethodName, bookSaveFolder, fileName, 30, urlGUID);
return CommonReturnType.create(url);
Map map = new HashMap();
map.put("url", url);
map.put("urlGUID", urlGUID);
return CommonReturnType.create(map);
}
}

View File

@@ -0,0 +1,269 @@
package plus.bookshelf.Dao.DO;
import java.util.Date;
public class ScheduleTaskDO {
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.id
*
* @mbg.generated
*/
private Integer id;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.create_time
*
* @mbg.generated
*/
private Date createTime;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.schedule_time
*
* @mbg.generated
*/
private Date scheduleTime;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.action
*
* @mbg.generated
*/
private String action;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.data
*
* @mbg.generated
*/
private String data;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.task_guid
*
* @mbg.generated
*/
private String taskGuid;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.associated_user_id
*
* @mbg.generated
*/
private Integer associatedUserId;
/**
*
* This field was generated by MyBatis Generator.
* This field corresponds to the database column schedule_task.fail_time
*
* @mbg.generated
*/
private Byte failTime;
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.id
*
* @return the value of schedule_task.id
*
* @mbg.generated
*/
public Integer getId() {
return id;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.id
*
* @param id the value for schedule_task.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 schedule_task.create_time
*
* @return the value of schedule_task.create_time
*
* @mbg.generated
*/
public Date getCreateTime() {
return createTime;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.create_time
*
* @param createTime the value for schedule_task.create_time
*
* @mbg.generated
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.schedule_time
*
* @return the value of schedule_task.schedule_time
*
* @mbg.generated
*/
public Date getScheduleTime() {
return scheduleTime;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.schedule_time
*
* @param scheduleTime the value for schedule_task.schedule_time
*
* @mbg.generated
*/
public void setScheduleTime(Date scheduleTime) {
this.scheduleTime = scheduleTime;
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.action
*
* @return the value of schedule_task.action
*
* @mbg.generated
*/
public String getAction() {
return action;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.action
*
* @param action the value for schedule_task.action
*
* @mbg.generated
*/
public void setAction(String action) {
this.action = action == null ? null : action.trim();
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.data
*
* @return the value of schedule_task.data
*
* @mbg.generated
*/
public String getData() {
return data;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.data
*
* @param data the value for schedule_task.data
*
* @mbg.generated
*/
public void setData(String data) {
this.data = data == null ? null : data.trim();
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.task_guid
*
* @return the value of schedule_task.task_guid
*
* @mbg.generated
*/
public String getTaskGuid() {
return taskGuid;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.task_guid
*
* @param taskGuid the value for schedule_task.task_guid
*
* @mbg.generated
*/
public void setTaskGuid(String taskGuid) {
this.taskGuid = taskGuid == null ? null : taskGuid.trim();
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.associated_user_id
*
* @return the value of schedule_task.associated_user_id
*
* @mbg.generated
*/
public Integer getAssociatedUserId() {
return associatedUserId;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.associated_user_id
*
* @param associatedUserId the value for schedule_task.associated_user_id
*
* @mbg.generated
*/
public void setAssociatedUserId(Integer associatedUserId) {
this.associatedUserId = associatedUserId;
}
/**
* This method was generated by MyBatis Generator.
* This method returns the value of the database column schedule_task.fail_time
*
* @return the value of schedule_task.fail_time
*
* @mbg.generated
*/
public Byte getFailTime() {
return failTime;
}
/**
* This method was generated by MyBatis Generator.
* This method sets the value of the database column schedule_task.fail_time
*
* @param failTime the value for schedule_task.fail_time
*
* @mbg.generated
*/
public void setFailTime(Byte failTime) {
this.failTime = failTime;
}
}

View File

@@ -59,4 +59,11 @@ public interface FileDOMapper {
* @return
*/
FileDO[] selectAll();
/**
* 获取上一次插入的主键Id
*
* @return
*/
int getLastInsertId();
}

View File

@@ -0,0 +1,70 @@
package plus.bookshelf.Dao.Mapper;
import org.springframework.stereotype.Repository;
import plus.bookshelf.Dao.DO.ScheduleTaskDO;
@Repository // 添加这个注解Autowired的时候idea就不会报错了
public interface ScheduleTaskDOMapper {
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
int deleteByPrimaryKey(Integer id);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
int insert(ScheduleTaskDO record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
int insertSelective(ScheduleTaskDO record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
ScheduleTaskDO selectByPrimaryKey(Integer id);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
int updateByPrimaryKeySelective(ScheduleTaskDO record);
/**
* This method was generated by MyBatis Generator.
* This method corresponds to the database table schedule_task
*
* @mbg.generated
*/
int updateByPrimaryKey(ScheduleTaskDO record);
/**
* 从数据库中取出需要处理的任务
*
* @return
*/
ScheduleTaskDO[] selectTodoTask();
/**
* 通过 GUID 获取任务
*
* @param taskGuid
* @return
*/
ScheduleTaskDO selectByGuid(String taskGuid);
}

View File

@@ -0,0 +1,122 @@
package plus.bookshelf.Service.Impl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import plus.bookshelf.Common.Enum.ScheduleTaskActionEnum;
import plus.bookshelf.Common.Error.BusinessErrorCode;
import plus.bookshelf.Common.Error.BusinessException;
import plus.bookshelf.Config.QCloudCosConfig;
import plus.bookshelf.Dao.DO.ScheduleTaskDO;
import plus.bookshelf.Dao.Mapper.ScheduleTaskDOMapper;
import plus.bookshelf.Service.Model.ScheduleTaskModel;
import plus.bookshelf.Service.Service.CosPresignedUrlGenerateLogService;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import static plus.bookshelf.Common.Enum.ScheduleTaskActionEnum.*;
@Service
public class ScheduleTaskServiceImpl {
@Autowired
QCloudCosConfig qCloudCosConfig;
@Autowired
CosPresignedUrlGenerateLogService cosPresignedUrlGenerateLogService;
@Autowired
ScheduleTaskDOMapper scheduleTaskDOMapper;
@Autowired
FileServiceImpl fileService;
public void setExecutor() {
// 创建定时任务 主要是待用户将文件上传成功到COS后
java.util.concurrent.ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
// 参数1、任务体 2、首次执行的延时时间
// 3、任务执行间隔 4、间隔时间单位
service.scheduleAtFixedRate(() -> {
try {
thingsTodo();
} catch (BusinessException e) {
e.printStackTrace();
}
}, 0, 3, TimeUnit.SECONDS);
}
@Transactional
public void thingsTodo() throws BusinessException {
// 检查上传文件后未收到客户端发来的上传完成消息的情况。
// 如果系统里面没有记录那么删除COS存储桶中用户上传的这个文件。
ScheduleTaskDO[] scheduleTaskDO = scheduleTaskDOMapper.selectTodoTask();
for (ScheduleTaskDO task : scheduleTaskDO) {
ScheduleTaskModel scheduleTaskModel = convertToModel(task);
switch (scheduleTaskModel.getAction()) {
case CHECK_FILE_IS_UPLOADED:
fileService.doScheduleTask(scheduleTaskModel);
break;
default:
throw new BusinessException(BusinessErrorCode.UNKNOWN_ERROR, "未知的定时任务类型");
}
}
// 输出
System.out.println("Task ScheduledExecutorService " + new Date());
}
/**
* 创建一个新的定时任务(存入数据库)
*
* @param scheduleTaskModel
* @return
*/
public Boolean insertScheduleTask(ScheduleTaskModel scheduleTaskModel) {
ScheduleTaskDO scheduleTaskDO = convertToDataObject(scheduleTaskModel);
int affectRows = scheduleTaskDOMapper.insertSelective(scheduleTaskDO);
return affectRows > 0;
}
/**
* 完成一个定时任务(从数据库中删除)
* 注意先删除,删除成功后才进行处理,避免自动触发和手动触发同时进行
*
* @param scheduleTaskId
* @return
*/
public Boolean doneScheduleTask(Integer scheduleTaskId) {
int affectRows = scheduleTaskDOMapper.deleteByPrimaryKey(scheduleTaskId);
return affectRows > 0;
}
/**
* 通过 Guid 查询任务
*
* @param guid
* @return
*/
public ScheduleTaskModel findTaskByGuid(String guid) {
ScheduleTaskDO scheduleTaskDO = scheduleTaskDOMapper.selectByGuid(guid);
return convertToModel(scheduleTaskDO);
}
private static ScheduleTaskDO convertToDataObject(ScheduleTaskModel scheduleTaskModel) {
ScheduleTaskDO scheduleTaskDO = new ScheduleTaskDO();
BeanUtils.copyProperties(scheduleTaskModel, scheduleTaskDO);
scheduleTaskDO.setAction(String.valueOf(scheduleTaskModel.getAction()));
return scheduleTaskDO;
}
private static ScheduleTaskModel convertToModel(ScheduleTaskDO scheduleTaskDO) {
ScheduleTaskModel scheduleTaskModel = new ScheduleTaskModel();
BeanUtils.copyProperties(scheduleTaskDO, scheduleTaskModel);
scheduleTaskModel.setAction(ScheduleTaskActionEnum.valueOf(scheduleTaskDO.getAction()));
return scheduleTaskModel;
}
}

View File

@@ -19,7 +19,7 @@ public class FileModel {
// 文件存储名称 (文件的实际文件名,含扩展名)
String fileName;
// 文件格式
// 文件格式 (文件扩展名)
String fileFormat;
// 总页数

View File

@@ -0,0 +1,26 @@
package plus.bookshelf.Service.Model;
import lombok.Data;
import plus.bookshelf.Common.Enum.ScheduleTaskActionEnum;
import java.util.Date;
@Data
public class ScheduleTaskModel {
Integer id;
Date createTime;
Date scheduleTime;
ScheduleTaskActionEnum action;
String data;
String taskGuid;
Integer associatedUserId;
Byte failTime;
}