add 新增 warmflow 源码级定制化开发

This commit is contained in:
疯狂的狮子Li 2026-09-11 17:06:33 +08:00
parent bd82af3727
commit 472d2d1a3a
20 changed files with 98 additions and 222 deletions

View File

@ -15,20 +15,18 @@
*/
package org.dromara.warm.flow;
import cn.hutool.core.util.ClassUtil;
import cn.hutool.core.util.StrUtil;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.warm.flow.config.WarmFlowProperties;
import org.dromara.warm.flow.handler.DataFillHandler;
import org.dromara.warm.flow.handler.PermissionHandler;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.warm.flow.listener.GlobalListener;
import org.dromara.warm.flow.service.*;
import cn.hutool.core.util.ClassUtil;
import java.lang.reflect.Constructor;
import java.util.function.Supplier;
/**
* 流程引擎通过静态方法驱动流程流转
*/
@ -129,24 +127,24 @@ public class FlowEngine {
* @return bean
*/
private static <T> T initBean(Class<T> tClazz, String beanPath, Supplier<T> supplier) {
T hander = null;
T handler = null;
try {
if (!StrUtil.isEmpty(beanPath)) {
if (StrUtil.isNotBlank(beanPath)) {
Class<?> clazz = ClassUtil.loadClass(beanPath);
if (clazz != null && tClazz.isAssignableFrom(clazz)) {
Constructor<?> constructor = clazz.getConstructor();
hander = tClazz.cast(constructor.newInstance());
handler = tClazz.cast(constructor.newInstance());
}
}
} catch (Exception ignored) {
}
if (hander == null) {
hander = SpringUtils.getBeanOrNull(tClazz);
if (handler == null) {
handler = SpringUtils.getBeanOrNull(tClazz);
}
if (hander == null && supplier != null) {
hander = supplier.get();
if (handler == null && supplier != null) {
handler = supplier.get();
}
return hander;
return handler;
}
}

View File

@ -18,9 +18,9 @@ package org.dromara.warm.flow.config;
import jakarta.annotation.PostConstruct;
import org.dromara.warm.flow.FlowEngine;
import org.dromara.warm.flow.enums.FrameworkType;
import org.dromara.workflow.common.ConditionalOnEnable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;
@ -32,7 +32,7 @@ import org.springframework.stereotype.Component;
*/
@Component
@EnableConfigurationProperties(WarmFlowProperties.class)
@ConditionalOnProperty(value = "warm-flow.enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnEnable
public class WarmFlowInitializer {
private static final Logger log = LoggerFactory.getLogger(WarmFlowInitializer.class);

View File

@ -16,7 +16,7 @@
package org.dromara.warm.flow.dto;
import java.io.Serial;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
@ -250,7 +250,7 @@ public class FlowParams implements Serializable {
}
public String getVariableStr() {
return JsonUtil.objToStr(variable);
return JsonUtils.toJsonString(variable);
}
public String getHandler() {

View File

@ -14,7 +14,8 @@
* limitations under the License.
*/
package org.dromara.warm.flow.entity;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import tools.jackson.core.type.TypeReference;
import org.dromara.warm.flow.entity.RootEntity;
@ -24,7 +25,10 @@ import lombok.experimental.Accessors;
import org.dromara.warm.flow.entity.FlowHisTask;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* 历史任务记录
*/
@ -165,7 +169,8 @@ public class FlowHisTask implements RootEntity {
/**
* 流程变量转 map
*/
public java.util.Map<String, Object> getVariableMap() {
return JsonUtil.strToMap(getVariable());
public Map<String, Object> getVariableMap() {
return Optional.ofNullable(JsonUtils.parseObject(getVariable(), new TypeReference<Map<String, Object>>() {
})).orElseGet(HashMap::new);
}
}

View File

@ -14,7 +14,8 @@
* limitations under the License.
*/
package org.dromara.warm.flow.entity;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import tools.jackson.core.type.TypeReference;
import org.dromara.warm.flow.entity.RootEntity;
@ -24,6 +25,9 @@ import lombok.experimental.Accessors;
import org.dromara.warm.flow.entity.FlowInstance;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
/**
* 流程实例
*/
@ -134,7 +138,8 @@ public class FlowInstance implements RootEntity {
/**
* 流程变量转 map
*/
public java.util.Map<String, Object> getVariableMap() {
return JsonUtil.strToMap(getVariable());
public Map<String, Object> getVariableMap() {
return Optional.ofNullable(JsonUtils.parseObject(getVariable(), new TypeReference<Map<String, Object>>() {
})).orElseGet(HashMap::new);
}
}

View File

@ -9,8 +9,6 @@ import org.springframework.expression.spel.support.DataBindingMethodResolver;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@ -22,21 +20,20 @@ import java.util.Set;
*/
public class SafeMethodResolver implements MethodResolver {
private static final Set<String> DANGEROUS_METHODS = new HashSet<>(Arrays.asList(
"getRuntime",
"exec",
"forName",
"loadClass",
"getClassLoader",
"setAccessible",
"newInstance",
"invoke",
"getField",
"getDeclaredField",
"getMethod",
"getDeclaredMethod"
));
private static final Set<String> DANGEROUS_METHODS = Set.of(
"getRuntime",
"exec",
"forName",
"loadClass",
"getClassLoader",
"setAccessible",
"newInstance",
"invoke",
"getField",
"getDeclaredField",
"getMethod",
"getDeclaredMethod"
);
@Nullable
@Override

View File

@ -1,121 +0,0 @@
/*
* Copyright 2024-2025, Warm-Flow (290631660@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.warm.flow.json;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import org.dromara.warm.flow.exception.FlowException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.json.JsonMapper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Jackson 3map和json字符串转换工具类
*
* @author warm
*/
public final class JsonUtil {
private static final Logger log = LoggerFactory.getLogger(JsonUtil.class);
private static final JsonMapper JSON_MAPPER = JsonMapper.builder()
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.build();
private JsonUtil() {
}
/**
* 将字符串转为map
*
* @param jsonStr json字符串
* @return map
*/
public static Map<String, Object> strToMap(String jsonStr) {
if (StrUtil.isNotEmpty(jsonStr)) {
try {
return JSON_MAPPER.readValue(jsonStr,
JSON_MAPPER.getTypeFactory().constructMapType(Map.class, String.class, Object.class));
} catch (Exception e) {
log.error("json转换异常", e);
throw new FlowException("json转换异常");
}
}
return new HashMap<>();
}
/**
* 将字符串转为bean
*
* @param jsonStr json字符串
* @param clazz Class<T>
* @return T
*/
public static <T> T strToBean(String jsonStr, Class<T> clazz) {
if (StrUtil.isNotEmpty(jsonStr)) {
try {
return JSON_MAPPER.readValue(jsonStr, clazz);
} catch (Exception e) {
log.error("json转换异常", e);
throw new FlowException("json转换异常");
}
}
return null;
}
/**
* 将字符串转为集合
*
* @param jsonStr json字符串
* @return List<T>
*/
public static <T> List<T> strToList(String jsonStr) {
if (StrUtil.isNotEmpty(jsonStr)) {
try {
return JSON_MAPPER.readValue(jsonStr, new TypeReference<List<T>>() {
});
} catch (Exception e) {
log.error("json转换异常", e);
throw new FlowException("json转换异常");
}
}
return null;
}
/**
* 将对象转为字符串
*
* @param variable object
* @return json字符串
*/
public static String objToStr(Object variable) {
if (ObjectUtil.isNotNull(variable)) {
try {
return JSON_MAPPER.writeValueAsString(variable);
} catch (Exception e) {
log.error("Map转换异常", e);
throw new FlowException("Map转换异常");
}
}
return null;
}
}

View File

@ -80,7 +80,7 @@ public interface FlowUserMapper extends WarmMapper<FlowUser> {
queryWrapper.in(FlowUser::getProcessedBy, processedBys);
}
}
queryWrapper.in(ArrayUtil.isNotEmpty(types), FlowUser::getType, types);
queryWrapper.in(ArrayUtil.isNotEmpty(types), FlowUser::getType, Arrays.asList(types));
return selectList(queryWrapper);
}
}

View File

@ -15,7 +15,7 @@
*/
package org.dromara.warm.flow.service;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import cn.hutool.core.util.ArrayUtil;
@ -70,12 +70,12 @@ public class ChartService {
NodeType.isEnd(node.getNodeType()) ? ChartStatus.DONE.getKey() : ChartStatus.TO_DO.getKey()
));
return JsonUtil.objToStr(defJson);
return JsonUtils.toJsonString(defJson);
}
public String skipMetadata(PathWayData pathWayData) {
FlowInstance instance = FlowEngine.insService().getById(pathWayData.getInsId());
DefJson defJson = JsonUtil.strToBean(instance.getDefJson(), DefJson.class);
DefJson defJson = JsonUtils.parseObject(instance.getDefJson(), DefJson.class);
List<NodeJson> nodeList = defJson.getNodeList();
List<SkipJson> skipList = defJson.getNodeList().stream().map(NodeJson::getSkipList)
@ -125,7 +125,7 @@ public class ChartService {
});
return JsonUtil.objToStr(defJson);
return JsonUtils.toJsonString(defJson);
}
public List<String> getChartRgb(String modelValue) {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.dromara.warm.flow.service;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.warm.flow.entity.*;
@ -79,7 +79,7 @@ public class DefService extends WarmServiceImpl<FlowDefinition> {
}
public FlowDefinition importJson(String defJson) {
return importDef(JsonUtil.strToBean(defJson, DefJson.class));
return importDef(JsonUtils.parseObject(defJson, DefJson.class));
}
public FlowDefinition importDef(DefJson defJson) {
@ -147,7 +147,7 @@ public class DefService extends WarmServiceImpl<FlowDefinition> {
}
public String exportJson(Long id) {
return JsonUtil.objToStr(queryDesign(id).setIsPublish(null));
return JsonUtils.toJsonString(queryDesign(id).setIsPublish(null));
}
public FlowDefinition getAllDataDefinition(Long id) {
@ -357,4 +357,4 @@ public class DefService extends WarmServiceImpl<FlowDefinition> {
public FlowDefinitionMapper getMapper() {
return SpringUtils.getBean(FlowDefinitionMapper.class);
}
}
}

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package org.dromara.warm.flow.service;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.warm.flow.entity.*;
@ -187,7 +187,7 @@ public class InsService extends WarmServiceImpl<FlowInstance> {
.setNodeName(firstBetweenNode.getNodeName())
.setFlowStatus(StrUtil.emptyToDefault(flowParams.getFlowStatus(), FlowStatus.TOBESUBMIT.getKey()))
.setActivityStatus(ActivityStatus.ACTIVITY.getKey())
.setVariable(JsonUtil.objToStr(flowParams.getVariable()))
.setVariable(JsonUtils.toJsonString(flowParams.getVariable()))
.setCreateTime(now)
.setUpdateTime(now)
.setCreateBy(flowParams.getHandler())
@ -236,7 +236,7 @@ public class InsService extends WarmServiceImpl<FlowInstance> {
for (String key : keys) {
variableMap.remove(key);
}
instance.setVariable(JsonUtil.objToStr(variableMap));
instance.setVariable(JsonUtils.toJsonString(variableMap));
FlowEngine.insService().updateById(instance);
}
}
@ -245,4 +245,4 @@ public class InsService extends WarmServiceImpl<FlowInstance> {
public FlowInstanceMapper getMapper() {
return SpringUtils.getBean(FlowInstanceMapper.class);
}
}
}

View File

@ -14,7 +14,8 @@
* limitations under the License.
*/
package org.dromara.warm.flow.service;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import tools.jackson.core.type.TypeReference;
import org.dromara.warm.flow.entity.*;
@ -292,7 +293,8 @@ public class NodeService extends WarmServiceImpl<FlowNode> {
Map<String, String> map = new HashMap<>();
String ext = node.getExt();
if (StrUtil.isNotEmpty(ext)) {
List<Map<String, Object>> extList = JsonUtil.strToList(ext);
List<Map<String, Object>> extList = JsonUtils.parseObject(ext, new TypeReference<List<Map<String, Object>>>() {
});
if (CollUtil.isNotEmpty(extList)) {
for (Map<String, Object> extMap : extList) {
String code = ObjectUtil.defaultIfNull(extMap.get("code"), "").toString();
@ -359,4 +361,4 @@ public class NodeService extends WarmServiceImpl<FlowNode> {
public FlowNodeMapper getMapper() {
return SpringUtils.getBean(FlowNodeMapper.class);
}
}
}

View File

@ -14,7 +14,8 @@
* limitations under the License.
*/
package org.dromara.warm.flow.service;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import tools.jackson.core.type.TypeReference;
import org.dromara.warm.flow.entity.*;
@ -559,9 +560,10 @@ public class TaskService extends WarmServiceImpl<FlowTask> {
public void mergeVariable(FlowInstance instance, Map<String, Object> variable) {
if (MapUtil.isNotEmpty(variable)) {
String variableStr = instance.getVariable();
Map<String, Object> deserialize = JsonUtil.strToMap(variableStr);
Map<String, Object> deserialize = Optional.ofNullable(JsonUtils.parseObject(variableStr, new TypeReference<Map<String, Object>>() {
})).orElseGet(HashMap::new);
deserialize.putAll(variable);
instance.setVariable(JsonUtil.objToStr(deserialize));
instance.setVariable(JsonUtils.toJsonString(deserialize));
}
}
@ -814,7 +816,7 @@ public class TaskService extends WarmServiceImpl<FlowTask> {
return;
}
DefJson defJson = JsonUtil.strToBean(instance.getDefJson(), DefJson.class);
DefJson defJson = JsonUtils.parseObject(instance.getDefJson(), DefJson.class);
Map<String, NodeJson> nodeJsonMap = StreamUtils.toMap(defJson.getNodeList(), NodeJson::getNodeCode, node -> node);
// 途径节点中的并行/包容网关只剩一个前置待办任务时才能生成新的代办任务
List<FlowNode> parallelOrInclusiveList = StreamUtils.filter(pathWayData.getPathWayNodes(),

View File

@ -15,13 +15,9 @@
*/
package org.dromara.warm.flow.strategy;
import cn.hutool.core.util.ObjectUtil;
import org.dromara.common.core.utils.StreamUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* 办理人表达式策略接口
@ -48,15 +44,15 @@ public interface HandlerStrategy extends ExpressionStrategy<List<String>> {
}
default List<String> afterEval(Object o) {
if (ObjectUtil.isNull(o)) {
if (o == null) {
return null;
}
if (o instanceof List) {
return StreamUtils.toList((List<?>) o, Object::toString);
if (o instanceof List<?> list) {
return StreamUtils.toList(list, Object::toString);
}
if (o instanceof Object[]) {
return Arrays.stream((Object[]) o).map(Object::toString).toList();
if (o instanceof Object[] array) {
return Arrays.stream(array).map(Object::toString).toList();
}
return Collections.singletonList(o.toString());
return List.of(o.toString());
}
}

View File

@ -17,6 +17,7 @@ package org.dromara.warm.flow.ui.config;
import org.dromara.warm.flow.ui.controller.WarmFlowController;
import org.dromara.warm.flow.ui.controller.WarmFlowUiController;
import org.dromara.workflow.common.ConditionalOnEnable;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@ -29,9 +30,9 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author ruoyi
*/
@Configuration
@ConditionalOnEnable
@ConditionalOnProperty(value = "warm-flow.ui", havingValue = "true", matchIfMissing = true)
@Import({WarmFlowUiController.class
, WarmFlowController.class})
@Import({WarmFlowUiController.class, WarmFlowController.class})
public class WarmFlowUiConfig implements WebMvcConfigurer {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {

View File

@ -15,11 +15,10 @@
*/
package org.dromara.warm.flow.ui.service;
import org.dromara.warm.flow.json.JsonUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.warm.flow.FlowEngine;
import org.dromara.warm.flow.config.WarmFlowProperties;
import org.dromara.warm.flow.dto.*;
@ -124,7 +123,7 @@ public class WarmFlowService {
try {
FlowInstance instance = FlowEngine.insService().getById(id);
String defJsonStr = instance.getDefJson();
DefJson defJson = JsonUtil.strToBean(defJsonStr, DefJson.class);
DefJson defJson = JsonUtils.parseObject(defJsonStr, DefJson.class);
defJson.setInstance(instance);
// 获取流程图三原色

View File

@ -72,30 +72,23 @@ public class AssertUtil {
public static void isNotEmpty(Object obj, String errorMsg) {
if (obj != null) {
if (obj instanceof String) {
AssertUtil.isTrue(StrUtil.isNotEmpty((String) obj), errorMsg);
} else if (obj instanceof Collection) {
AssertUtil.isTrue(CollUtil.isNotEmpty((Collection<?>) obj), errorMsg);
} else if (obj instanceof Map) {
AssertUtil.isTrue(MapUtil.isNotEmpty((Map<?, ?>) obj), errorMsg);
} else {
throw new FlowException("Unsupported type: " + obj.getClass().getName());
switch (obj) {
case String str -> AssertUtil.isTrue(StrUtil.isNotEmpty(str), errorMsg);
case Collection<?> collection -> AssertUtil.isTrue(CollUtil.isNotEmpty(collection), errorMsg);
case Map<?, ?> map -> AssertUtil.isTrue(MapUtil.isNotEmpty(map), errorMsg);
default -> throw new FlowException("Unsupported type: " + obj.getClass().getName());
}
}
}
public static void isEmpty(Object obj, String errorMsg) {
if (obj == null) {
throw new FlowException(errorMsg);
} else if (obj instanceof String) {
AssertUtil.isTrue(StrUtil.isEmpty((String) obj), errorMsg);
} else if (obj instanceof Collection) {
AssertUtil.isTrue(CollUtil.isEmpty((Collection<?>) obj), errorMsg);
} else if (obj instanceof Map) {
AssertUtil.isTrue(MapUtil.isEmpty((Map<?, ?>) obj), errorMsg);
} else {
throw new FlowException("Unsupported type: " + obj.getClass().getName());
switch (obj) {
case null -> throw new FlowException(errorMsg);
case String str -> AssertUtil.isTrue(StrUtil.isEmpty(str), errorMsg);
case Collection<?> collection -> AssertUtil.isTrue(CollUtil.isEmpty(collection), errorMsg);
case Map<?, ?> map -> AssertUtil.isTrue(MapUtil.isEmpty(map), errorMsg);
default -> throw new FlowException("Unsupported type: " + obj.getClass().getName());
}
}

View File

@ -96,7 +96,7 @@ public class ExpressionUtil {
.map(s -> evalVariable(s, variable)).filter(Objects::nonNull)
.flatMap(List::stream)
.distinct()
.toList();
.collect(Collectors.toCollection(ArrayList::new));
// 转换办理人比如设计器中预设了能办理的人如果其中包含角色或者部门id等可以通过此接口进行转换成用户id
PermissionHandler permissionHandler = FlowEngine.permissionHandler();
@ -125,7 +125,7 @@ public class ExpressionUtil {
if (CollUtil.isNotEmpty(value)) {
return value;
}
return Collections.singletonList(expression);
return List.of(expression);
}
/**
@ -188,7 +188,7 @@ public class ExpressionUtil {
return permissions;
}
if (nextHandlerAppend) {
permissions.addAll(new ArrayList<>(Arrays.asList(nextHandler)));
permissions.addAll(Arrays.asList(nextHandler));
} else {
permissions = new ArrayList<>(Arrays.asList(nextHandler));
}

View File

@ -16,7 +16,6 @@
package org.dromara.warm.flow.utils;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import java.util.HashMap;
import java.util.Map;
@ -36,7 +35,7 @@ public class MapUtil {
* @return true为空 false非空
*/
public static boolean isEmpty(Map<?, ?> map) {
return ObjectUtil.isNull(map) || map.isEmpty();
return cn.hutool.core.map.MapUtil.isEmpty(map);
}
/**
@ -46,7 +45,7 @@ public class MapUtil {
* @return true非空 false
*/
public static boolean isNotEmpty(Map<?, ?> map) {
return !isEmpty(map);
return cn.hutool.core.map.MapUtil.isNotEmpty(map);
}
/**

View File

@ -1,6 +1,6 @@
package org.dromara.workflow.service.impl;
import org.dromara.warm.flow.json.JsonUtil;
import org.dromara.common.json.utils.JsonUtils;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
@ -400,7 +400,7 @@ public class FlwInstanceServiceImpl implements IFlwInstanceService {
return false;
}
variableMap.put(bo.key(), bo.value());
flowInstance.setVariable(JsonUtil.objToStr(variableMap));
flowInstance.setVariable(JsonUtils.toJsonString(variableMap));
return flowInstanceMapper.updateById(flowInstance) > 0;
}