修改向定时任务写的接口,枚举类实现策略模式,接口层服务层实现业务分离。
This commit is contained in:
+48
-17
@@ -1,5 +1,13 @@
|
||||
package org.jeecg.modules.tasktask.constant;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class FlowConstants {
|
||||
private FlowConstants() {
|
||||
}
|
||||
@@ -13,27 +21,50 @@ public final class FlowConstants {
|
||||
/** 延迟发起 */
|
||||
public static final Integer IMMEDIATE_AND_RECURRING = 3;
|
||||
}
|
||||
public static final class IntervalType {
|
||||
@Getter
|
||||
public enum IntervalType {
|
||||
EVERY_DAY(1, 1, ChronoUnit.DAYS, "每天"),
|
||||
EVERY_WEEK(2, 1, ChronoUnit.WEEKS, "每周"),
|
||||
EVERY_TWO_WEEKS(3, 2, ChronoUnit.WEEKS, "每两周"),
|
||||
EVERY_MONTH(4, 1, ChronoUnit.MONTHS, "每月"),
|
||||
EVERY_QUARTER(5, 3, ChronoUnit.MONTHS, "每季");
|
||||
|
||||
private final Integer code;
|
||||
private final int amount; // 步长数量
|
||||
private final ChronoUnit unit; // 时间单位
|
||||
private final String description;
|
||||
|
||||
IntervalType(Integer code, int amount, ChronoUnit unit, String description) {
|
||||
this.code = code;
|
||||
this.amount = amount;
|
||||
this.unit = unit;
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
// 静态缓存:优化查找性能,避免重复遍历 values()
|
||||
private static final Map<Integer, IntervalType> LOOKUP = Arrays.stream(values())
|
||||
.collect(Collectors.toMap(IntervalType::getCode, it -> it));
|
||||
|
||||
/**
|
||||
* 每天
|
||||
* 根据 code 获取枚举对象
|
||||
*/
|
||||
public static final Integer EVERY_DAY = 1;
|
||||
public static IntervalType of(Integer code) {
|
||||
IntervalType type = LOOKUP.get(code);
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("未知的周期类型代码: " + code);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 每周
|
||||
* 计算下一次执行时间
|
||||
* @param base 基准时间
|
||||
* @param step 第几次循环
|
||||
*/
|
||||
public static final Integer EVERY_WEEK = 2;
|
||||
/**
|
||||
* 每两周
|
||||
*/
|
||||
public static final Integer EVERY_TWO_WEEKS = 3;
|
||||
/**
|
||||
* 每月
|
||||
*/
|
||||
public static final Integer EVERY_MONTH = 4;
|
||||
/**
|
||||
* 每季
|
||||
*/
|
||||
public static final Integer EVERY_QUARTER = 5;
|
||||
public LocalDateTime nextTime(LocalDateTime base, int step) {
|
||||
// 使用 base + (步长 * 循环次数) 避免累加误差
|
||||
return base.plus((long) step * amount, unit);
|
||||
}
|
||||
}
|
||||
public static final class taskCount{
|
||||
public static final Integer MAX = 24;
|
||||
|
||||
+9
-55
@@ -10,6 +10,7 @@ import java.net.URLDecoder;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.system.query.QueryGenerator;
|
||||
@@ -114,65 +115,18 @@ public class TaskTaskController extends JeecgController<TaskTask, ITaskTaskServi
|
||||
@Operation(summary = "事项任务计划表(发起周期性流程)-添加")
|
||||
@RequiresPermissions("tasktask:task_task:add")
|
||||
@PostMapping(value = "/flow-schedules")
|
||||
public Result<String> addRecurringTask(@RequestBody TaskTask taskTask,
|
||||
@RequestParam(name = "intervalType", required = false) Integer intervalType,
|
||||
@RequestParam(name = "startCount", required = false) Integer startCount) throws Exception {
|
||||
if (taskTask.getTriggerType() == null) {
|
||||
return Result.error("触发类型不能为空");
|
||||
}
|
||||
Integer triggerType = taskTask.getTriggerType();
|
||||
public Result<?> addRecurringTask(@RequestBody TaskTask taskTask, Integer intervalType, Integer startCount) {
|
||||
// 获取用户信息
|
||||
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal();
|
||||
if (sysUser.getUsername() == null || sysUser.getUsername().isEmpty()) {
|
||||
return Result.error("无法获取当前流程发起人信息");
|
||||
}
|
||||
if (startCount > FlowConstants.taskCount.MAX) return Result.error("单词生成周期任务不能超过100个");
|
||||
String username = sysUser.getUsername();
|
||||
|
||||
if (FlowConstants.Strategy.IMMEDIATE_ONLY.equals(triggerType)) {
|
||||
if (taskTaskService.singleFlowStart(taskTask, sysUser.getUsername())) {
|
||||
return Result.ok("单次流程发起成功");
|
||||
}
|
||||
return Result.error("立即发起流程失败");
|
||||
} else if (FlowConstants.Strategy.RECURRING_ONLY.equals(triggerType)) {
|
||||
//向中间表写入n个待发起流程,由定时器扫描发起
|
||||
List<TaskTask> temTaskList = new ArrayList<>();
|
||||
Date baseDate = Optional.ofNullable(taskTask.getStartTime())
|
||||
.orElseThrow(() -> new IllegalArgumentException("周期性流程开始时间不能为空!"));
|
||||
|
||||
LocalDateTime currentLdt = baseDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
|
||||
for (int i = 0; i < startCount; i++) {
|
||||
// 计算下一次执行时间
|
||||
if (FlowConstants.IntervalType.EVERY_DAY.equals(intervalType)) {
|
||||
currentLdt = currentLdt.plusDays(1);
|
||||
} else if (FlowConstants.IntervalType.EVERY_WEEK.equals(intervalType)) {
|
||||
currentLdt = currentLdt.plusWeeks(1);
|
||||
} else if (FlowConstants.IntervalType.EVERY_TWO_WEEKS.equals(intervalType)) {
|
||||
currentLdt = currentLdt.plusWeeks(2);
|
||||
} else if (FlowConstants.IntervalType.EVERY_MONTH.equals(intervalType)) {
|
||||
currentLdt = currentLdt.plusMonths(1);
|
||||
} else if (FlowConstants.IntervalType.EVERY_QUARTER.equals(intervalType)) {
|
||||
currentLdt = currentLdt.plusMonths(3);
|
||||
} else {
|
||||
throw new IllegalArgumentException("未知的周期类型: " + intervalType);
|
||||
// 这里只做最基础的鉴权拦截
|
||||
if (StringUtils.isEmpty(username)) {
|
||||
return Result.error("登录已失效,请重新登录");
|
||||
}
|
||||
|
||||
// 2. 创建新的任务对象并添加到列表
|
||||
TaskTask newTask = new TaskTask();
|
||||
// 复制基础属性 (建议使用 BeanUtils.copyProperties)
|
||||
BeanUtils.copyProperties(taskTask, newTask);
|
||||
|
||||
// 设置计算后的触发时间
|
||||
Date nextExecutionDate = Date.from(currentLdt.atZone(ZoneId.systemDefault()).toInstant());
|
||||
newTask.setStartTime(nextExecutionDate);
|
||||
|
||||
temTaskList.add(newTask);
|
||||
}
|
||||
taskTaskService.saveBatch(temTaskList);
|
||||
} else {
|
||||
// 这个 else 很重要,处理那些“意料之外”的数值
|
||||
return Result.error("非法的触发类型数值: " + triggerType);
|
||||
}
|
||||
return Result.OK("添加成功!");
|
||||
// 业务逻辑全部交给 Service
|
||||
return taskTaskService.handleFlowStart(taskTask, username, intervalType, startCount);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+3
@@ -1,5 +1,6 @@
|
||||
package org.jeecg.modules.tasktask.service;
|
||||
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.tasktask.entity.TaskTask;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
@@ -11,4 +12,6 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
||||
*/
|
||||
public interface ITaskTaskService extends IService<TaskTask> {
|
||||
boolean singleFlowStart(TaskTask taskTask,String userName) throws Exception;
|
||||
boolean multiFlowStart(TaskTask taskTask,String userName,Integer intervalType, Integer startCount) throws Exception;
|
||||
Result<?> handleFlowStart(TaskTask taskTask, String username, Integer intervalType, Integer startCount);
|
||||
}
|
||||
|
||||
+72
-3
@@ -6,17 +6,20 @@ import org.apache.shiro.util.Assert;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.modules.extbpm.process.exception.BpmException;
|
||||
import org.jeecg.modules.extbpm.process.service.impl.BpmBaseExtApiImpl;
|
||||
import org.jeecg.modules.tasktask.constant.FlowConstants;
|
||||
import org.jeecg.modules.tasktask.entity.TaskTask;
|
||||
import org.jeecg.modules.tasktask.mapper.TaskTaskMapper;
|
||||
import org.jeecg.modules.tasktask.service.ITaskTaskService;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.ZoneId;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @Description: 事项任务计划表(发起流程)
|
||||
@@ -28,7 +31,6 @@ import java.util.Optional;
|
||||
public class TaskTaskServiceImpl extends ServiceImpl<TaskTaskMapper, TaskTask> implements ITaskTaskService {
|
||||
@Autowired
|
||||
private BpmBaseExtApiImpl bpmBaseExtApiImpl;
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean singleFlowStart(TaskTask taskTask, String userName) throws Exception {
|
||||
if (StringUtils.isBlank(taskTask.getFlowCode())) {
|
||||
@@ -46,4 +48,71 @@ public class TaskTaskServiceImpl extends ServiceImpl<TaskTaskMapper, TaskTask> i
|
||||
Result<String> res = bpmBaseExtApiImpl.startMutilProcess(taskTask.getFlowCode(), taskTask.getBusinessId(), taskTask.getFormUrl(), taskTask.getFormUrl(), userName, jsonString);
|
||||
return res.isSuccess();
|
||||
}
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public boolean multiFlowStart(TaskTask taskTask,String userName,Integer intervalType, Integer startCount) throws Exception{
|
||||
List<TaskTask> temTaskList = new ArrayList<>();
|
||||
Date baseDate = Optional.ofNullable(taskTask.getStartTime())
|
||||
.orElseThrow(() -> new IllegalArgumentException("周期性流程开始时间不能为空!"));
|
||||
|
||||
LocalDateTime currentLdt = baseDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
FlowConstants.IntervalType intervalTypeInstance = FlowConstants.IntervalType.of(intervalType);
|
||||
for (int i = 0; i < startCount; i++) {
|
||||
|
||||
LocalDateTime execDateTime = intervalTypeInstance.nextTime(currentLdt,i+1);
|
||||
|
||||
// 2. 创建新的任务对象并添加到列表
|
||||
TaskTask newTask = new TaskTask();
|
||||
// 复制基础属性 (建议使用 BeanUtils.copyProperties)
|
||||
BeanUtils.copyProperties(taskTask, newTask);
|
||||
newTask.setId(null);
|
||||
// 设置计算后的触发时间
|
||||
Date nextExecutionDate = Date.from(execDateTime.atZone(ZoneId.systemDefault()).toInstant());
|
||||
newTask.setStartTime(nextExecutionDate);
|
||||
|
||||
temTaskList.add(newTask);
|
||||
}
|
||||
return this.saveBatch(temTaskList);
|
||||
}
|
||||
public Result<?> handleFlowStart(TaskTask taskTask, String username, Integer intervalType, Integer startCount) throws Exception {
|
||||
// 1. 显式校验:代替 Assert
|
||||
Result<?> checkResult = validateBusinessParams(taskTask, startCount);
|
||||
if (!checkResult.isSuccess()) {
|
||||
return checkResult; // 校验不通过直接返回错误
|
||||
}
|
||||
|
||||
Integer triggerType = taskTask.getTriggerType();
|
||||
|
||||
// 2. 策略分发(路由)
|
||||
if (FlowConstants.Strategy.IMMEDIATE_ONLY.equals(triggerType)) {
|
||||
boolean success = singleFlowStart(taskTask, username);
|
||||
return success ? Result.ok("立即发起流程成功") : Result.error("立即发起流程失败");
|
||||
}
|
||||
|
||||
if (FlowConstants.Strategy.RECURRING_ONLY.equals(triggerType)) {
|
||||
boolean success = multiFlowStart(taskTask, username, intervalType, startCount);
|
||||
return success ? Result.ok("周期性流程添加成功") : Result.error("周期性流程添加失败");
|
||||
}
|
||||
|
||||
// 3. 保底处理
|
||||
return Result.error("未知的触发类型: " + triggerType);
|
||||
}
|
||||
private Result<?> validateBusinessParams(TaskTask taskTask, Integer startCount) {
|
||||
if (taskTask.getTriggerType() == null) {
|
||||
return Result.error("触发类型不能为空");
|
||||
}
|
||||
|
||||
// 如果是周期任务,校验次数和开始时间
|
||||
if (FlowConstants.Strategy.RECURRING_ONLY.equals(taskTask.getTriggerType())) {
|
||||
if (startCount == null || startCount <= 0) {
|
||||
return Result.error("周期任务生成数量必须大于0");
|
||||
}
|
||||
if (startCount > FlowConstants.taskCount.MAX) {
|
||||
return Result.error("单次生成周期任务不能超过24个");
|
||||
}
|
||||
if (taskTask.getStartTime() == null) {
|
||||
return Result.error("周期性流程开始时间不能为空");
|
||||
}
|
||||
}
|
||||
return Result.ok();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user