反序列化问题。

This commit is contained in:
dengqichen 2024-12-16 11:14:23 +08:00
parent 84df7e50b8
commit ecf12a22a0
18 changed files with 301 additions and 258 deletions

View File

@ -12,7 +12,8 @@ import java.util.stream.Collectors;
@org.mapstruct.MapperConfig(
componentModel = "spring",
unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE
unmappedTargetPolicy = org.mapstruct.ReportingPolicy.IGNORE,
uses = {EnumListConverter.class}
)
public interface BaseConverter<T extends Entity<?>, D extends BaseDTO> {

View File

@ -0,0 +1,31 @@
package com.qqchen.deploy.backend.framework.converter;
import org.mapstruct.Qualifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.List;
/**
* 枚举列表转换器
*/
public class EnumListConverter {
@Qualifier
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface EnumMapping {
}
@EnumMapping
public <T extends Enum<T>> List<T> mapEnumList(List<T> value) {
return value;
}
@EnumMapping
public <T extends Enum<T>> T mapEnum(T value) {
return value;
}
}

View File

@ -3,11 +3,13 @@ package com.qqchen.deploy.backend.workflow.api;
import com.qqchen.deploy.backend.framework.api.Response;
import com.qqchen.deploy.backend.framework.controller.BaseController;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.workflow.dto.WorkflowCategoryDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceCreateDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.enums.WorkflowCategoryEnum;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.query.WorkflowDefinitionQuery;
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
@ -56,7 +58,7 @@ public class WorkflowDefinitionApiController extends BaseController<WorkflowDefi
}
@PostMapping("/{workflowDefinitionId}/published")
public Response<Void> publishedWorkflowDesign(@PathVariable Long workflowDefinitionId){
public Response<Void> publishedWorkflowDesign(@PathVariable Long workflowDefinitionId) {
workflowDefinitionService.publishedWorkflowDesign(workflowDefinitionId);
return Response.success();
}
@ -252,6 +254,14 @@ public class WorkflowDefinitionApiController extends BaseController<WorkflowDefi
return Response.success();
}
@Operation(summary = "启用工作流")
@GetMapping("/categories")
public Response<List<WorkflowCategoryDTO>> getWorkflowCategories() {
return Response.success(workflowDefinitionService.getWorkflowCategories());
}
@Override
protected void exportData(HttpServletResponse response, List<WorkflowDefinitionDTO> data) {

View File

@ -1,39 +0,0 @@
package com.qqchen.deploy.backend.workflow.config;
import lombok.Builder;
import lombok.Data;
import java.util.List;
/**
* BPMN节点配置
*/
@Data
@Builder
public class BpmnNodeConfig {
/**
* 节点类型
*/
private String type;
/**
* 节点名称
*/
private String name;
/**
* 是否异步执行
*/
private boolean async;
/**
* 必需的字段
*/
private List<String> requiredFields;
/**
* 委托表达式
*/
private String delegateExpression;
}

View File

@ -1,61 +0,0 @@
package com.qqchen.deploy.backend.workflow.config;
import com.qqchen.deploy.backend.workflow.annotation.BpmnNode;
import jakarta.annotation.PostConstruct;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* BPMN节点管理器
*/
@Slf4j
@Component
public class BpmnNodeManager {
@Autowired
private ApplicationContext applicationContext;
private final Map<String, BpmnNodeConfig> nodeConfigs = new ConcurrentHashMap<>();
@PostConstruct
public void init() {
// 扫描所有带有@BpmnNode注解的类
Map<String, Object> beans = applicationContext.getBeansWithAnnotation(BpmnNode.class);
beans.forEach((name, bean) -> {
BpmnNode annotation = bean.getClass().getAnnotation(BpmnNode.class);
if (annotation != null) {
BpmnNodeConfig config = BpmnNodeConfig.builder()
.type(annotation.type())
.name(annotation.name())
.async(annotation.async())
.requiredFields(Arrays.asList(annotation.requiredFields()))
.delegateExpression(annotation.delegateExpression())
.build();
nodeConfigs.put(annotation.type(), config);
log.info("Registered BPMN node type: {}", annotation.type());
}
});
}
/**
* 获取节点配置
*/
public BpmnNodeConfig getNodeConfig(String type) {
return nodeConfigs.get(type);
}
/**
* 检查节点类型是否存在
*/
public boolean hasNodeType(String type) {
return nodeConfigs.containsKey(type);
}
}

View File

@ -1,83 +0,0 @@
package com.qqchen.deploy.backend.workflow.constants;
/**
* BPMN相关常量
*/
public class BpmnConstants {
/**
* 节点类型
*/
public static class NodeShape {
public static final String START = "start";
public static final String END = "end";
public static final String EDGE = "edge";
public static final String SHELL_TASK = "shellTask";
}
/**
* 节点属性
*/
public static class NodeAttribute {
public static final String SHAPE = "shape";
public static final String ID = "id";
public static final String LABEL = "label";
public static final String SOURCE = "source";
public static final String TARGET = "target";
public static final String DATA = "data";
public static final String CONDITION = "condition";
public static final String SERVICE_TASK = "serviceTask";
public static final String FIELDS = "fields";
}
/**
* 默认节点ID
*/
public static class DefaultNodeId {
public static final String START_EVENT = "startEvent";
public static final String END_EVENT = "endEvent";
public static final String START_FLOW = "flow_start";
public static final String END_FLOW = "flow_end";
}
/**
* 默认节点名称
*/
public static class DefaultNodeName {
public static final String START_EVENT = "开始";
public static final String END_EVENT = "结束";
}
/**
* 委托表达式类型
*/
public static class DelegateExpression {
public static final String TYPE = "delegateExpression";
public static final String SHELL_TASK = "${shellTaskDelegate}";
}
/**
* Shell任务配置
*/
public static class ShellTaskConfig {
public static final String SCRIPT = "script";
public static final String WORK_DIR = "workDir";
public static final String TIMEOUT = "timeout";
public static final String RETRY_COUNT = "retryCount";
public static final String ENV = "env";
public static final String PRIORITY = "priority";
public static final String GROUP = "group";
}
/**
* 流程属性
*/
public static class ProcessAttribute {
public static final String CELLS = "cells";
public static final String EXECUTABLE = "true";
}
private BpmnConstants() {
// 防止实例化
}
}

View File

@ -0,0 +1,19 @@
package com.qqchen.deploy.backend.workflow.dto;
import lombok.Data;
import java.util.List;
@Data
public class WorkflowCategoryDTO {
private String code;
private String lable;
private String description;
private List<WorkflowTriggerTypeDTO> supportedTriggers;
}

View File

@ -3,12 +3,18 @@ package com.qqchen.deploy.backend.workflow.dto;
import com.fasterxml.jackson.databind.JsonNode;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.enums.WorkflowCategoryEnum;
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowTriggerTypeEnum;
import jakarta.persistence.Column;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 工作流定义DTO
*
* @author cascade
* @date 2024-12-11
*/
@ -26,6 +32,16 @@ public class WorkflowDefinitionDTO extends BaseDTO {
*/
private String key;
/**
* 分类
*/
private WorkflowCategoryEnum category;
/**
* 触发类型列表
*/
private List<WorkflowTriggerTypeEnum> triggers;
/**
* 流程版本
*/

View File

@ -0,0 +1,12 @@
package com.qqchen.deploy.backend.workflow.dto;
import lombok.Data;
@Data
public class WorkflowTriggerTypeDTO {
private String code;
private String lable;
}

View File

@ -3,11 +3,14 @@ package com.qqchen.deploy.backend.workflow.entity;
import com.fasterxml.jackson.databind.JsonNode;
import com.qqchen.deploy.backend.framework.annotation.LogicDelete;
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.enums.WorkflowCategoryEnum;
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowTriggerTypeEnum;
import com.qqchen.deploy.backend.workflow.hibernate.WorkflowGraphType;
import com.qqchen.deploy.backend.framework.domain.Entity;
import com.vladmihalcea.hibernate.type.json.JsonType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Table;
@ -15,6 +18,8 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
import org.hibernate.annotations.Type;
import java.util.List;
/**
* 工作流定义实体
*/
@ -37,6 +42,18 @@ public class WorkflowDefinition extends Entity<Long> {
@Column(name = "`key`", nullable = false)
private String key;
/**
* 流程分类
*/
@Column(name = "category", nullable = false)
@Enumerated(EnumType.STRING)
private WorkflowCategoryEnum category;
@Column(name = "triggers", nullable = false)
@Convert(converter = WorkflowTriggerTypeListConverter.class)
private List<WorkflowTriggerTypeEnum> triggers;
@Column(name = "process_definition_id", nullable = false)
private String processDefinitionId;
@ -91,11 +108,6 @@ public class WorkflowDefinition extends Entity<Long> {
@Column(name = "target_namespace")
private String targetNamespace = "http://www.flowable.org/test";
/**
* 流程分类
*/
@Column(name = "category")
private String category;
/**
* 流程标签用于分组和过滤

View File

@ -0,0 +1,47 @@
package com.qqchen.deploy.backend.workflow.entity;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qqchen.deploy.backend.workflow.enums.WorkflowTriggerTypeEnum;
import jakarta.persistence.AttributeConverter;
import jakarta.persistence.Converter;
import org.springframework.util.StringUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@Converter
public class WorkflowTriggerTypeListConverter implements AttributeConverter<List<WorkflowTriggerTypeEnum>, String> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
public String convertToDatabaseColumn(List<WorkflowTriggerTypeEnum> attribute) {
try {
return objectMapper.writeValueAsString(
attribute.stream()
.map(Enum::name)
.collect(Collectors.toList())
);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Error converting trigger type list to JSON", e);
}
}
@Override
public List<WorkflowTriggerTypeEnum> convertToEntityAttribute(String dbData) {
try {
if (StringUtils.isEmpty(dbData)) {
return new ArrayList<>();
}
List<String> triggerNames = objectMapper.readValue(dbData, new TypeReference<List<String>>() {
});
return triggerNames.stream()
.map(WorkflowTriggerTypeEnum::valueOf)
.collect(Collectors.toList());
} catch (JsonProcessingException e) {
throw new IllegalArgumentException("Error converting JSON to trigger type list", e);
}
}
}

View File

@ -0,0 +1,72 @@
package com.qqchen.deploy.backend.workflow.enums;
import lombok.Getter;
import java.util.Arrays;
import java.util.List;
/**
* 工作流节点分类枚举
*/
@Getter
public enum WorkflowCategoryEnum {
// 1. 脚本执行类
SCRIPT_EXECUTION(
"脚本执行",
"用于执行各类脚本的流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL, WorkflowTriggerTypeEnum.SCHEDULED)
),
// 2. 部署类
DEPLOYMENT(
"应用部署",
"用于应用部署的流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL, WorkflowTriggerTypeEnum.SCHEDULED, WorkflowTriggerTypeEnum.APPROVAL)
),
// 3. 数据同步类
DATA_SYNC(
"数据同步",
"用于第三方系统数据同步的流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL, WorkflowTriggerTypeEnum.SCHEDULED)
),
// 4. 配置同步类
CONFIG_SYNC(
"配置同步",
"用于配置中心数据同步的流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL, WorkflowTriggerTypeEnum.APPROVAL)
),
// 5. 审批流程类
APPROVAL(
"审批流程",
"纯审批流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL)
),
// 6. 其他类型用于扩展
OTHER(
"其他",
"其他类型流程",
Arrays.asList(WorkflowTriggerTypeEnum.MANUAL)
);
private final String label; // 显示名称
private final String description; // 描述
private final List<WorkflowTriggerTypeEnum> supportedTriggers; // 支持的触发方式
WorkflowCategoryEnum(String label, String description, List<WorkflowTriggerTypeEnum> supportedTriggers) {
this.label = label;
this.description = description;
this.supportedTriggers = supportedTriggers;
}
// 判断是否支持某种触发方式
public boolean supportsTriggerType(WorkflowTriggerTypeEnum triggerType) {
return supportedTriggers.contains(triggerType);
}
}

View File

@ -0,0 +1,18 @@
package com.qqchen.deploy.backend.workflow.enums;
import lombok.Getter;
@Getter
public enum WorkflowTriggerTypeEnum {
MANUAL("手动触发"),
SCHEDULED("定时触发"),
APPROVAL("审批触发"),
EVENT("事件触发"); // 预留将来可能的事件驱动场景
private final String label;
WorkflowTriggerTypeEnum(String label) {
this.label = label;
}
}

View File

@ -1,38 +0,0 @@
package com.qqchen.deploy.backend.workflow.model;
import com.qqchen.deploy.backend.workflow.enums.BpmnNodeTypeEnums;
import lombok.Data;
import java.util.HashMap;
import java.util.Map;
/**
* BPMN节点配置
*/
@Data
public class BpmnNodeConfig {
/**
* 节点ID
*/
private String id;
/**
* 节点名称
*/
private String name;
/**
* 节点类型
*/
private BpmnNodeTypeEnums type;
/**
* 节点属性
*/
private Map<String, Object> properties = new HashMap<>();
/**
* 扩展字段
*/
private Map<String, String> extensions = new HashMap<>();
}

View File

@ -1,16 +1,19 @@
package com.qqchen.deploy.backend.workflow.service;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.workflow.dto.WorkflowCategoryDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDesignDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceCreateDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.enums.WorkflowCategoryEnum;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.runtime.ProcessInstance;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Map;
/**
@ -55,4 +58,6 @@ public interface IWorkflowDefinitionService extends IBaseService<WorkflowDefinit
void enable(Long id);
void publishedWorkflowDesign(Long workflowDefinitionId);
List<WorkflowCategoryDTO> getWorkflowCategories();
}

View File

@ -1,26 +1,22 @@
package com.qqchen.deploy.backend.workflow.service.impl;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.workflow.converter.WorkflowInstanceConverter;
import com.qqchen.deploy.backend.workflow.dto.WorkflowCategoryDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowDefinitionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowExecutionDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceCreateDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowInstanceDTO;
import com.qqchen.deploy.backend.workflow.dto.WorkflowTriggerTypeDTO;
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowDefinitionGraph;
import com.qqchen.deploy.backend.workflow.entity.WorkflowDefinition;
import com.qqchen.deploy.backend.workflow.entity.WorkflowInstance;
import com.qqchen.deploy.backend.workflow.enums.WorkflowInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowCategoryEnum;
import com.qqchen.deploy.backend.workflow.enums.WorkflowNodeInstanceStatusEnums;
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowDefinitionRepository;
import com.qqchen.deploy.backend.workflow.repository.IWorkflowInstanceRepository;
import com.qqchen.deploy.backend.workflow.service.IWorkflowDefinitionService;
import com.qqchen.deploy.backend.workflow.service.IWorkflowInstanceService;
import com.qqchen.deploy.backend.workflow.util.BpmnConverter;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.SequenceFlow;
import org.flowable.bpmn.model.StartEvent;
import org.flowable.engine.HistoryService;
import org.flowable.engine.ManagementService;
import org.flowable.engine.RepositoryService;
@ -38,8 +34,8 @@ import org.flowable.bpmn.model.FlowElement;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -340,4 +336,28 @@ public class WorkflowDefinitionServiceImpl extends BaseServiceImpl<WorkflowDefin
log.info("Successfully published workflow definition: {}", workflowDefinitionId);
}
@Override
public List<WorkflowCategoryDTO> getWorkflowCategories() {
return Arrays.stream(WorkflowCategoryEnum.values())
.map(category -> {
WorkflowCategoryDTO dto = new WorkflowCategoryDTO();
dto.setCode(category.name());
dto.setLable(category.getLabel());
dto.setDescription(category.getDescription());
// 获取该类别支持的触发方式
dto.setSupportedTriggers(
category.getSupportedTriggers().stream()
.map(triggerType -> {
WorkflowTriggerTypeDTO triggerDto = new WorkflowTriggerTypeDTO();
triggerDto.setCode(triggerType.name());
triggerDto.setLable(triggerType.getLabel());
return triggerDto;
})
.collect(Collectors.toList())
);
return dto;
})
.collect(Collectors.toList());
}
}

View File

@ -407,10 +407,11 @@ CREATE TABLE workflow_definition
-- 基础信息
name VARCHAR(255) NOT NULL COMMENT '流程名称',
`key` VARCHAR(255) NOT NULL COMMENT '流程标识',
category VARCHAR(100) COMMENT '流程分类',
triggers VARCHAR(200) COMMENT '流程分类',
process_definition_id VARCHAR(100) NULL COMMENT '工作流定义ID',
flow_version INT NOT NULL COMMENT '流程版本',
description TEXT COMMENT '流程描述',
category VARCHAR(100) COMMENT '流程分类',
-- 流程配置
bpmn_xml TEXT COMMENT 'BPMN XML内容',
@ -424,8 +425,8 @@ CREATE TABLE workflow_definition
target_namespace VARCHAR(255) DEFAULT 'http://www.flowable.org/test' COMMENT '目标命名空间',
-- 审计字段
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6) COMMENT '创建时间',
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP (6) ON UPDATE CURRENT_TIMESTAMP (6) COMMENT '更新时间',
created_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) COMMENT '创建时间',
updated_at DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6) COMMENT '更新时间',
created_by BIGINT COMMENT '创建人',
updated_by BIGINT COMMENT '更新人',
is_deleted BOOLEAN NOT NULL DEFAULT FALSE COMMENT '是否删除',

View File

@ -158,7 +158,7 @@ INSERT INTO sys_external_system (
-- 工作流定义测试数据
INSERT INTO workflow_definition (
-- 基础信息
name, `key`, process_definition_id, flow_version, description, category,
name, `key`, process_definition_id, flow_version, description, category, triggers,
-- 流程配置
graph, form_config, tags,
-- 流程属性
@ -168,7 +168,7 @@ INSERT INTO workflow_definition (
) VALUES
-- 简单脚本流程:开始 -> 脚本任务 -> 结束
(
'简单脚本流程', 'simple_script_flow', null, 1, '一个包含脚本任务的简单流程', 'test',
'简单脚本流程', 'simple_script_flow', null, 1, '一个包含脚本任务的简单流程', 'SCRIPT_EXECUTION', null,
'{
"nodes" : [ {
"id" : "startEvent1",
@ -337,7 +337,7 @@ INSERT INTO workflow_definition (
-- 复杂业务流程:开始 -> 脚本任务A -> 脚本任务B -> 结束
(
'复杂业务流程', 'complex_business_flow', null, 1, '包含多个脚本任务节点的业务流程', 'business',
'复杂业务流程', 'complex_business_flow', null, 1, '包含多个脚本任务节点的业务流程', 'SCRIPT_EXECUTION', null,
'{
"nodes" : [ {
"id" : "startEvent1",