feat(ops): 状态机新增 forceTransition 强制跳转方法
适用于系统自动结单等场景,允许跳过转换规则直接跳转到终态, 但仍校验终态不可再转换,且完整记录事件流。 重构:抽取 doTransition 公共方法,transition 和 forceTransition 通过 validate 参数区分,消除重复代码。新增 TERMINAL_STATES 显式终态集合替代隐式空 Set 判断。 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -93,22 +93,21 @@ public class OrderStateMachine {
|
|||||||
WorkOrderStatusEnum.CANCELLED, Collections.emptySet()
|
WorkOrderStatusEnum.CANCELLED, Collections.emptySet()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/** 终态集合,不允许再转换 */
|
||||||
|
private static final Set<WorkOrderStatusEnum> TERMINAL_STATES = Set.of(
|
||||||
|
WorkOrderStatusEnum.COMPLETED, WorkOrderStatusEnum.CANCELLED
|
||||||
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 执行状态转换(核心方法)
|
* 执行状态转换(校验转换规则)
|
||||||
* <p>
|
|
||||||
* 此方法负责:
|
|
||||||
* 1. 验证状态转换合法性
|
|
||||||
* 2. 更新工单状态和相关字段
|
|
||||||
* 3. 记录事件流
|
|
||||||
* 4. 发布状态变更事件
|
|
||||||
*
|
*
|
||||||
* @param order 工单对象
|
* @param order 工单对象
|
||||||
* @param newStatus 目标状态
|
* @param newStatus 目标状态
|
||||||
* @param operatorType 操作人类型
|
* @param operatorType 操作人类型
|
||||||
* @param operatorId 操作人ID
|
* @param operatorId 操作人ID
|
||||||
* @param remark 说明
|
* @param remark 说明
|
||||||
* @throws IllegalArgumentException 参数不合法
|
* @throws IllegalArgumentException 参数不合法
|
||||||
* @throws IllegalStateException 状态转换不合法
|
* @throws IllegalStateException 状态转换不合法
|
||||||
*/
|
*/
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public void transition(OpsOrderDO order,
|
public void transition(OpsOrderDO order,
|
||||||
@@ -116,7 +115,66 @@ public class OrderStateMachine {
|
|||||||
OperatorTypeEnum operatorType,
|
OperatorTypeEnum operatorType,
|
||||||
Long operatorId,
|
Long operatorId,
|
||||||
String remark) {
|
String remark) {
|
||||||
|
doTransition(order, newStatus, operatorType, operatorId, remark, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 强制状态跳转(不受转换规则限制)
|
||||||
|
* <p>
|
||||||
|
* 适用于系统自动结单等场景:告警自动解除时工单可能处于任何非终态,
|
||||||
|
* 需要直接跳转到 COMPLETED / CANCELLED,不经过中间状态。
|
||||||
|
* <p>
|
||||||
|
* 与 {@link #transition} 的区别:跳过转换规则校验,
|
||||||
|
* 其余逻辑(字段更新、事件记录)完全一致。
|
||||||
|
*
|
||||||
|
* @param order 工单对象
|
||||||
|
* @param newStatus 目标状态(通常为终态 COMPLETED / CANCELLED)
|
||||||
|
* @param operatorType 操作人类型
|
||||||
|
* @param operatorId 操作人ID
|
||||||
|
* @param remark 说明
|
||||||
|
* @throws IllegalArgumentException 参数不合法
|
||||||
|
* @throws IllegalStateException 当前已是终态
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void forceTransition(OpsOrderDO order,
|
||||||
|
WorkOrderStatusEnum newStatus,
|
||||||
|
OperatorTypeEnum operatorType,
|
||||||
|
Long operatorId,
|
||||||
|
String remark) {
|
||||||
|
doTransition(order, newStatus, operatorType, operatorId, remark, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查状态转换是否合法(不执行转换)
|
||||||
|
*/
|
||||||
|
public boolean canTransition(WorkOrderStatusEnum fromStatus, WorkOrderStatusEnum toStatus) {
|
||||||
|
if (fromStatus == null || toStatus == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Set<WorkOrderStatusEnum> allowedTargets = TRANSITIONS.get(fromStatus);
|
||||||
|
return allowedTargets != null && allowedTargets.contains(toStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前状态允许转换到的目标状态集合
|
||||||
|
*/
|
||||||
|
public Set<WorkOrderStatusEnum> getAllowedTransitions(WorkOrderStatusEnum currentStatus) {
|
||||||
|
return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet());
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== 私有方法 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态转换核心逻辑(transition / forceTransition 的统一实现)
|
||||||
|
*
|
||||||
|
* @param validate true=校验转换规则(transition),false=仅校验终态(forceTransition)
|
||||||
|
*/
|
||||||
|
private void doTransition(OpsOrderDO order,
|
||||||
|
WorkOrderStatusEnum newStatus,
|
||||||
|
OperatorTypeEnum operatorType,
|
||||||
|
Long operatorId,
|
||||||
|
String remark,
|
||||||
|
boolean validate) {
|
||||||
// 1. 参数校验
|
// 1. 参数校验
|
||||||
if (order == null) {
|
if (order == null) {
|
||||||
throw new IllegalArgumentException("工单对象不能为空");
|
throw new IllegalArgumentException("工单对象不能为空");
|
||||||
@@ -128,15 +186,19 @@ public class OrderStateMachine {
|
|||||||
// 2. 获取当前状态
|
// 2. 获取当前状态
|
||||||
WorkOrderStatusEnum currentStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
WorkOrderStatusEnum currentStatus = WorkOrderStatusEnum.valueOf(order.getStatus());
|
||||||
|
|
||||||
// 3. 如果目标状态与当前状态相同,直接返回(避免不必要的操作)
|
// 3. 相同状态,跳过
|
||||||
if (currentStatus == newStatus) {
|
if (currentStatus == newStatus) {
|
||||||
log.debug("工单状态未变化,跳过状态转换: orderId={}, status={}",
|
log.debug("工单状态未变化,跳过: orderId={}, status={}", order.getId(), currentStatus);
|
||||||
order.getId(), currentStatus);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 4. 校验状态转换合法性
|
// 4. 校验
|
||||||
validateTransition(currentStatus, newStatus);
|
if (validate) {
|
||||||
|
validateTransition(currentStatus, newStatus);
|
||||||
|
} else if (TERMINAL_STATES.contains(currentStatus)) {
|
||||||
|
throw new IllegalStateException(String.format(
|
||||||
|
"工单已处于终态 %s,无法转换到 %s", currentStatus.name(), newStatus.name()));
|
||||||
|
}
|
||||||
|
|
||||||
// 5. 更新工单状态和相关字段
|
// 5. 更新工单状态和相关字段
|
||||||
WorkOrderStatusEnum oldStatus = currentStatus;
|
WorkOrderStatusEnum oldStatus = currentStatus;
|
||||||
@@ -155,37 +217,10 @@ public class OrderStateMachine {
|
|||||||
remark
|
remark
|
||||||
);
|
);
|
||||||
|
|
||||||
log.info("工单状态转换成功: orderId={}, {} -> {}, operatorType={}, operatorId={}",
|
log.info("工单状态转换: orderId={}, {} -> {}, forced={}, operatorType={}, operatorId={}",
|
||||||
order.getId(), oldStatus, newStatus, operatorType, operatorId);
|
order.getId(), oldStatus, newStatus, !validate, operatorType, operatorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 检查状态转换是否合法(不执行转换)
|
|
||||||
*
|
|
||||||
* @param fromStatus 当前状态
|
|
||||||
* @param toStatus 目标状态
|
|
||||||
* @return 是否可以转换
|
|
||||||
*/
|
|
||||||
public boolean canTransition(WorkOrderStatusEnum fromStatus, WorkOrderStatusEnum toStatus) {
|
|
||||||
if (fromStatus == null || toStatus == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Set<WorkOrderStatusEnum> allowedTargets = TRANSITIONS.get(fromStatus);
|
|
||||||
return allowedTargets != null && allowedTargets.contains(toStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取当前状态允许转换到的目标状态集合
|
|
||||||
*
|
|
||||||
* @param currentStatus 当前状态
|
|
||||||
* @return 允许的目标状态集合
|
|
||||||
*/
|
|
||||||
public Set<WorkOrderStatusEnum> getAllowedTransitions(WorkOrderStatusEnum currentStatus) {
|
|
||||||
return TRANSITIONS.getOrDefault(currentStatus, Collections.emptySet());
|
|
||||||
}
|
|
||||||
|
|
||||||
// ==================== 私有方法 ====================
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 校验状态转换是否合法
|
* 校验状态转换是否合法
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user