refactor(flow): 重构循环处理逻辑并完善自动填充功能
- 在BaseEntity中添加MyBatis Plus字段自动填充注解 - 实现FlowLoopValueResolver工具类统一处理循环数据源 - 简化FlowGetCurrentObjNodeHandler中的循环对象获取逻辑 - 优化MyMetaObjectHandler中的时间字段填充方法 - 在多个服务实现中添加实体对象参数确保更新操作正确性 - 为SysFileInfo启用创建时间和创建者的自动填充功能 - 添加FlowLoopValueResolver的单元测试确保功能正确性
This commit is contained in:
parent
bdb6640ad8
commit
e62f445013
@ -4,6 +4,8 @@ import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
@ -24,16 +26,20 @@ public class BaseEntity implements Serializable
|
||||
private String searchValue;
|
||||
|
||||
/** 创建者 */
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
/** 创建时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
/** 更新者 */
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
private String updateBy;
|
||||
|
||||
/** 更新时间 */
|
||||
@TableField(fill = FieldFill.UPDATE)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date updateTime;
|
||||
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
package com.cmvr.common.core.domain.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
@ -32,11 +34,11 @@ public class SysFileInfo implements Serializable {
|
||||
private Integer fileType;
|
||||
|
||||
@ApiModelProperty("上传人")
|
||||
// @TableField(fill = FieldFill.INSERT) // todo 暂时不要 没有token
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
@ApiModelProperty("上传时间")
|
||||
// @TableField(fill = FieldFill.INSERT)
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private Date createTime;
|
||||
|
||||
@ApiModelProperty("文件MD5值")
|
||||
|
||||
@ -33,9 +33,9 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
}
|
||||
// 起始版本 3.3.0(推荐使用)
|
||||
this.setFieldValByName(CREATE_BY, username, metaObject);
|
||||
this.setFieldValByName(CREATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
|
||||
this.setFieldValByName(CREATE_TIME, currentTime(metaObject, CREATE_TIME), metaObject);
|
||||
this.setFieldValByName(UPDATE_BY, username, metaObject);
|
||||
this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
|
||||
this.setFieldValByName(UPDATE_TIME, currentTime(metaObject, UPDATE_TIME), metaObject);
|
||||
this.setFieldValByName(DELETED, "0", metaObject);
|
||||
// this.setFieldValByName(STATUS, "1", metaObject);
|
||||
if (getFieldValByName(STATUS, metaObject) == null) {
|
||||
@ -56,9 +56,14 @@ public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
username = "anonymous"; // 匿名接口默认值
|
||||
}
|
||||
this.setFieldValByName(UPDATE_BY, username, metaObject);
|
||||
this.setFieldValByName(UPDATE_TIME, formatDate(metaObject.getSetterType(CREATE_TIME)), metaObject);
|
||||
this.setFieldValByName(UPDATE_TIME, currentTime(metaObject, UPDATE_TIME), metaObject);
|
||||
}
|
||||
|
||||
private Object currentTime(MetaObject metaObject, String fieldName) {
|
||||
return metaObject.hasSetter(fieldName)
|
||||
? formatDate(metaObject.getSetterType(fieldName))
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理特殊日期
|
||||
|
||||
@ -47,5 +47,12 @@
|
||||
<artifactId>nashorn-core</artifactId>
|
||||
<version>${nashorn.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.13.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
||||
@ -1,16 +1,12 @@
|
||||
package com.cmvr.test.flow.runtime.dispatcher;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.cmvr.test.flow.runtime.engine.support.FlowLoopValueResolver;
|
||||
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Component("GET_CURRENT_OBJECT")
|
||||
public class FlowGetCurrentObjNodeHandler implements FlowNodeTypeHandler {
|
||||
@ -19,18 +15,11 @@ public class FlowGetCurrentObjNodeHandler implements FlowNodeTypeHandler {
|
||||
@Override
|
||||
public TaskNodeExecuteResult handle(TaskNodeExecuteMessage message) {
|
||||
try {
|
||||
// JSONObject inputParams = message.getInputParams();
|
||||
// JSONArray jsonArray = inputParams.getJSONArray("array");
|
||||
//
|
||||
// List<Integer> iterations = message.getIterations();
|
||||
// int last = CollUtil.getLast(iterations) - 1;
|
||||
int index = message.getLoopNum() - 1;
|
||||
int iteration = message.getLoopNum();
|
||||
int index = iteration - 1;
|
||||
JSONObject output = new JSONObject();
|
||||
output.put("index", index);
|
||||
JSONArray objects = (JSONArray)message.getLoopArray();
|
||||
if (CollUtil.isNotEmpty(objects) && index >= 0) {
|
||||
output.put("object", objects.get(index));
|
||||
}
|
||||
output.put("object", FlowLoopValueResolver.current(message.getLoopArray(), iteration));
|
||||
|
||||
return TaskNodeExecuteResult.success(output);
|
||||
|
||||
|
||||
@ -0,0 +1,91 @@
|
||||
package com.cmvr.test.flow.runtime.engine.support;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.cmvr.common.exception.GlobalException;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
/** Resolves the two supported loop sources: arrays and iteration counts. */
|
||||
public final class FlowLoopValueResolver {
|
||||
|
||||
private FlowLoopValueResolver() {
|
||||
}
|
||||
|
||||
public static int count(Object value) {
|
||||
Object normalized = normalize(value);
|
||||
if (normalized == null) {
|
||||
return 0;
|
||||
}
|
||||
if (normalized instanceof Collection<?>) {
|
||||
return ((Collection<?>) normalized).size();
|
||||
}
|
||||
if (normalized != null && normalized.getClass().isArray()) {
|
||||
return Array.getLength(normalized);
|
||||
}
|
||||
if (normalized instanceof Number) {
|
||||
return ((Number) normalized).intValue();
|
||||
}
|
||||
throw unsupported(value);
|
||||
}
|
||||
|
||||
public static Object current(Object value, int iteration) {
|
||||
if (iteration < 1) {
|
||||
throw new GlobalException("当前循环次数必须从 1 开始: " + iteration);
|
||||
}
|
||||
|
||||
Object normalized = normalize(value);
|
||||
int index = iteration - 1;
|
||||
if (normalized instanceof Collection<?>) {
|
||||
Collection<?> collection = (Collection<?>) normalized;
|
||||
if (index >= collection.size()) {
|
||||
throw outOfBounds(iteration, collection.size());
|
||||
}
|
||||
return new ArrayList<>(collection).get(index);
|
||||
}
|
||||
if (normalized != null && normalized.getClass().isArray()) {
|
||||
int length = Array.getLength(normalized);
|
||||
if (index >= length) {
|
||||
throw outOfBounds(iteration, length);
|
||||
}
|
||||
return Array.get(normalized, index);
|
||||
}
|
||||
if (normalized instanceof Number) {
|
||||
int loopCount = ((Number) normalized).intValue();
|
||||
if (iteration > loopCount) {
|
||||
throw outOfBounds(iteration, loopCount);
|
||||
}
|
||||
return iteration;
|
||||
}
|
||||
throw unsupported(value);
|
||||
}
|
||||
|
||||
private static Object normalize(Object value) {
|
||||
if (!(value instanceof String)) {
|
||||
return value;
|
||||
}
|
||||
|
||||
String text = ((String) value).trim();
|
||||
if (text.startsWith("[")) {
|
||||
try {
|
||||
return JSON.parseArray(text);
|
||||
} catch (Exception e) {
|
||||
throw new GlobalException("循环数组参数格式错误: " + value);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(text);
|
||||
} catch (NumberFormatException e) {
|
||||
throw unsupported(value);
|
||||
}
|
||||
}
|
||||
|
||||
private static GlobalException unsupported(Object value) {
|
||||
return new GlobalException("循环参数仅支持数组或数字: " + value);
|
||||
}
|
||||
|
||||
private static GlobalException outOfBounds(int iteration, int count) {
|
||||
return new GlobalException("当前循环次数超出范围: " + iteration + "/" + count);
|
||||
}
|
||||
}
|
||||
@ -2,7 +2,6 @@ package com.cmvr.test.flow.runtime.engine.support;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.cmvr.common.exception.GlobalException;
|
||||
@ -17,8 +16,6 @@ import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Component
|
||||
@ -51,32 +48,7 @@ public class FlowNodeParamPreparer {
|
||||
if (node.getNodeType() == NodeTypeEnum.LOOP) {
|
||||
Object loopNumVal = input.get("loopNum");
|
||||
input.put("loopArray", loopNumVal);
|
||||
int loopCount = 0;
|
||||
|
||||
// 根据迭代路径找到当前层的集合对象
|
||||
// Object target = resolveLoopTarget(loopNumVal, rootMessage.getIterations(), 0);
|
||||
Object target = loopNumVal;
|
||||
if (target instanceof JSONArray) {
|
||||
loopCount = ((JSONArray) target).size();
|
||||
} else if (target instanceof Collection) {
|
||||
loopCount = ((Collection<?>) target).size();
|
||||
} else if (target != null && target.getClass().isArray()) {
|
||||
loopCount = Array.getLength(target);
|
||||
} else if (target instanceof Number) {
|
||||
loopCount = ((Number) target).intValue();
|
||||
} else if (target != null) {
|
||||
try {
|
||||
String string = target.toString();
|
||||
if (string.startsWith("[")) {
|
||||
JSONArray array = JSON.parseArray(string);
|
||||
loopCount = array.size();
|
||||
}else {
|
||||
loopCount = Integer.parseInt(string);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw new GlobalException("loopNum 参数格式错误: " + loopNumVal);
|
||||
}
|
||||
}
|
||||
int loopCount = FlowLoopValueResolver.count(loopNumVal);
|
||||
|
||||
// 写回 inputParams,供 LoopHandler 使用
|
||||
input.put("loopNum", loopCount);
|
||||
@ -177,40 +149,4 @@ public class FlowNodeParamPreparer {
|
||||
return curr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据迭代路径(iterations)逐层解析嵌套集合
|
||||
* - iterations = [] → 返回最外层对象
|
||||
* - iterations = [2] → 返回 list[1]
|
||||
* - iterations = [2,3] → 返回 list[1][2]
|
||||
*/
|
||||
private Object resolveLoopTarget(Object obj, List<Integer> iterations, int depth) {
|
||||
if (obj == null) return null;
|
||||
|
||||
// 已经走到当前循环层,返回目标
|
||||
if (depth >= iterations.size()) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
int idx = iterations.get(depth) - 1;
|
||||
|
||||
if (obj instanceof List) {
|
||||
List<?> list = (List<?>) obj;
|
||||
if (idx >= 0 && idx < list.size()) {
|
||||
return resolveLoopTarget(list.get(idx), iterations, depth + 1);
|
||||
}
|
||||
} else if (obj instanceof JSONArray) {
|
||||
JSONArray arr = (JSONArray) obj;
|
||||
if (idx >= 0 && idx < arr.size()) {
|
||||
return resolveLoopTarget(arr.get(idx), iterations, depth + 1);
|
||||
}
|
||||
} else if (obj != null && obj.getClass().isArray()) {
|
||||
int length = Array.getLength(obj);
|
||||
if (idx >= 0 && idx < length) {
|
||||
return resolveLoopTarget(Array.get(obj, idx), iterations, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果不是集合类型,直接返回
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,7 @@ public class TeTaskInstServiceImpl extends ServiceImpl<TeTaskInstMapper, TeTaskI
|
||||
@Override
|
||||
public boolean updateStatus(String instId, TaskStatusEnum taskStatusEnum) {
|
||||
return this.update(
|
||||
new TeTaskInst(),
|
||||
new LambdaUpdateWrapper<TeTaskInst>()
|
||||
.eq(TeTaskInst::getId, instId)
|
||||
.set(TeTaskInst::getStatus, taskStatusEnum.getCode())
|
||||
|
||||
@ -0,0 +1,64 @@
|
||||
package com.cmvr.test.flow.runtime.engine.support;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.cmvr.common.exception.GlobalException;
|
||||
import com.cmvr.test.flow.runtime.dispatcher.FlowGetCurrentObjNodeHandler;
|
||||
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteMessage;
|
||||
import com.cmvr.test.flow.runtime.message.TaskNodeExecuteResult;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class FlowLoopValueResolverTest {
|
||||
|
||||
@Test
|
||||
public void resolvesCurrentArrayElement() {
|
||||
assertEquals(3, FlowLoopValueResolver.count(JSON.parseArray("[\"a\",\"b\",\"c\"]")));
|
||||
assertEquals("b", FlowLoopValueResolver.current(Arrays.asList("a", "b", "c"), 2));
|
||||
assertEquals(20, FlowLoopValueResolver.current(new Integer[]{10, 20, 30}, 2));
|
||||
assertEquals("b", FlowLoopValueResolver.current("[\"a\",\"b\",\"c\"]", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolvesCurrentNumericIteration() {
|
||||
assertEquals(3, FlowLoopValueResolver.count(3));
|
||||
assertEquals(2, FlowLoopValueResolver.current(3, 2));
|
||||
assertEquals(3, FlowLoopValueResolver.count("3"));
|
||||
assertEquals(2, FlowLoopValueResolver.current("3", 2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentObjectNodeKeepsOutputContractForArrayLoop() {
|
||||
TaskNodeExecuteResult result = executeCurrentObjectNode(Arrays.asList("a", "b", "c"), 2);
|
||||
|
||||
assertEquals(1, result.getOutputParams().getIntValue("index"));
|
||||
assertEquals("b", result.getOutputParams().get("object"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void currentObjectNodeReturnsIterationForNumericLoop() {
|
||||
TaskNodeExecuteResult result = executeCurrentObjectNode(3, 2);
|
||||
|
||||
assertEquals(1, result.getOutputParams().getIntValue("index"));
|
||||
assertEquals(2, result.getOutputParams().getIntValue("object"));
|
||||
}
|
||||
|
||||
@Test(expected = GlobalException.class)
|
||||
public void rejectsUnsupportedLoopValue() {
|
||||
FlowLoopValueResolver.count("not-a-loop");
|
||||
}
|
||||
|
||||
@Test(expected = GlobalException.class)
|
||||
public void rejectsIterationOutsideLoopRange() {
|
||||
FlowLoopValueResolver.current(Arrays.asList("a"), 2);
|
||||
}
|
||||
|
||||
private TaskNodeExecuteResult executeCurrentObjectNode(Object loopValue, int iteration) {
|
||||
TaskNodeExecuteMessage message = new TaskNodeExecuteMessage();
|
||||
message.setLoopArray(loopValue);
|
||||
message.setLoopNum(iteration);
|
||||
return new FlowGetCurrentObjNodeHandler().handle(message);
|
||||
}
|
||||
}
|
||||
@ -163,7 +163,7 @@ public class TiProjectServiceImpl extends ServiceImpl<TiProjectMapper, TiProject
|
||||
LambdaUpdateWrapper<TiProject> wrapper = Wrappers.lambdaUpdate();
|
||||
wrapper.eq(TiProject::getProjectId, projectId)
|
||||
.set(TiProject::getStatus, status);
|
||||
return this.update(null, wrapper);
|
||||
return this.update(new TiProject(), wrapper);
|
||||
}
|
||||
|
||||
// 功能ID -> 音频地址
|
||||
|
||||
@ -27,6 +27,6 @@ public class ExViProjectServiceImpl implements ExViProjectService {
|
||||
wrapper.eq(ViProject::getProjectId, id)
|
||||
.eq(ViProject::getStatus, 1) // 运行中
|
||||
.set(ViProject::getStatus, 2); // 完成
|
||||
return viProjectService.update(null, wrapper);
|
||||
return viProjectService.update(new ViProject(), wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
@ -138,6 +138,7 @@ public class ViProjectServiceImpl extends ServiceImpl<ViProjectMapper, ViProject
|
||||
normalVO.setTerminalId(taskExecuteProjectVO.getTerminalId());
|
||||
String instId = flowTaskRuntimeService.executeProjectTask(normalVO);
|
||||
this.update(
|
||||
new ViProject(),
|
||||
new LambdaUpdateWrapper<ViProject>()
|
||||
.eq(ViProject::getProjectId, taskExecuteProjectVO.getProjectId())
|
||||
.set(ViProject::getStatus, "1") //执行中
|
||||
|
||||
Loading…
Reference in New Issue
Block a user