反序列化问题。
This commit is contained in:
parent
b5861a1bfe
commit
f69897a9d0
@ -1,5 +1,6 @@
|
||||
package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
@ -8,6 +9,7 @@ import lombok.Data;
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||
public class EdgeConfig {
|
||||
/**
|
||||
* 条件
|
||||
@ -19,8 +21,24 @@ public class EdgeConfig {
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
/**
|
||||
* 条件表达式
|
||||
*/
|
||||
private String conditionExpression;
|
||||
|
||||
/**
|
||||
* 类型(sequence/message/association)
|
||||
*/
|
||||
private String type;
|
||||
|
||||
public void setConditionExpression(String conditionExpression) {
|
||||
this.conditionExpression = conditionExpression;
|
||||
// 同时设置 condition 字段,保持兼容性
|
||||
this.condition = conditionExpression;
|
||||
}
|
||||
|
||||
public String getConditionExpression() {
|
||||
// 如果 conditionExpression 为空但 condition 不为空,返回 condition
|
||||
return conditionExpression != null ? conditionExpression : condition;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package com.qqchen.deploy.backend.workflow.dto.graph;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude;
|
||||
import lombok.Data;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -10,6 +11,7 @@ import java.util.Map;
|
||||
* @date 2024-12-11
|
||||
*/
|
||||
@Data
|
||||
@JsonInclude(JsonInclude.Include.NON_NULL) // 只序列化非空字段
|
||||
public class NodeConfig {
|
||||
/**
|
||||
* 配置类型
|
||||
@ -70,4 +72,14 @@ public class NodeConfig {
|
||||
* 是否排他
|
||||
*/
|
||||
private Boolean exclusive;
|
||||
|
||||
/**
|
||||
* 脚本格式
|
||||
*/
|
||||
private String scriptFormat;
|
||||
|
||||
/**
|
||||
* 脚本内容
|
||||
*/
|
||||
private String script;
|
||||
}
|
||||
|
||||
@ -2,9 +2,11 @@ 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.WorkflowGraph;
|
||||
import com.qqchen.deploy.backend.workflow.enums.WorkflowStatusEnums;
|
||||
import com.vladmihalcea.hibernate.type.json.JsonType;
|
||||
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.EnumType;
|
||||
import jakarta.persistence.Enumerated;
|
||||
@ -50,9 +52,9 @@ public class WorkflowDefinition extends Entity<Long> {
|
||||
/**
|
||||
* 流程图数据,包含节点和连线的位置、样式等信息
|
||||
*/
|
||||
@Type(JsonType.class)
|
||||
@Column(name = "graph_data", columnDefinition = "json")
|
||||
private JsonNode graphData;
|
||||
@Type(WorkflowGraphType.class)
|
||||
@Column(name = "graph", columnDefinition = "json")
|
||||
private WorkflowGraph graph;
|
||||
|
||||
/**
|
||||
* 表单配置
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
package com.qqchen.deploy.backend.workflow.enums;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
|
||||
/**
|
||||
* 节点类型枚举
|
||||
* @author cascade
|
||||
@ -16,6 +18,7 @@ public enum NodeType {
|
||||
SUBPROCESS("subProcess"),
|
||||
CALL_ACTIVITY("callActivity");
|
||||
|
||||
@JsonValue
|
||||
private final String value;
|
||||
|
||||
NodeType(String value) {
|
||||
@ -25,4 +28,13 @@ public enum NodeType {
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public static NodeType fromValue(String value) {
|
||||
for (NodeType type : values()) {
|
||||
if (type.value.equals(value)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("Unknown NodeType value: " + value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,122 @@
|
||||
package com.qqchen.deploy.backend.workflow.hibernate;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.qqchen.deploy.backend.workflow.dto.graph.WorkflowGraph;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.usertype.UserType;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* 自定义 Hibernate 类型,用于处理 WorkflowGraph 的序列化和反序列化
|
||||
*/
|
||||
public class WorkflowGraphType implements UserType<WorkflowGraph> {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public WorkflowGraphType() {
|
||||
this.objectMapper = new ObjectMapper();
|
||||
// 配置 ObjectMapper
|
||||
this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSqlType() {
|
||||
return Types.VARCHAR;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<WorkflowGraph> returnedClass() {
|
||||
return WorkflowGraph.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(WorkflowGraph x, WorkflowGraph y) {
|
||||
if (x == y) {
|
||||
return true;
|
||||
}
|
||||
if (x == null || y == null) {
|
||||
return false;
|
||||
}
|
||||
return x.equals(y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode(WorkflowGraph x) {
|
||||
return x == null ? 0 : x.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner)
|
||||
throws SQLException {
|
||||
String value = rs.getString(position);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(value, WorkflowGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to convert String to WorkflowGraph: " + value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(PreparedStatement st, WorkflowGraph value, int index, SharedSessionContractImplementor session)
|
||||
throws SQLException {
|
||||
if (value == null) {
|
||||
st.setNull(index, Types.VARCHAR);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
st.setString(index, objectMapper.writeValueAsString(value));
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to convert WorkflowGraph to String: " + value, e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph deepCopy(WorkflowGraph value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.readValue(objectMapper.writeValueAsString(value), WorkflowGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to deep copy WorkflowGraph", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(WorkflowGraph value) {
|
||||
try {
|
||||
return value == null ? null : objectMapper.writeValueAsString(value);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to disassemble WorkflowGraph", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph assemble(Serializable cached, Object owner) {
|
||||
try {
|
||||
return cached == null ? null : objectMapper.readValue(cached.toString(), WorkflowGraph.class);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw new HibernateException("Failed to assemble WorkflowGraph", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkflowGraph replace(WorkflowGraph detached, WorkflowGraph managed, Object owner) {
|
||||
return deepCopy(detached);
|
||||
}
|
||||
}
|
||||
@ -397,7 +397,7 @@ CREATE TABLE workflow_definition
|
||||
|
||||
-- 流程配置
|
||||
bpmn_xml TEXT COMMENT 'BPMN XML内容',
|
||||
graph_data JSON COMMENT '流程图数据,包含节点和连线的位置、样式等信息',
|
||||
graph JSON COMMENT '流程图数据,包含节点和连线的位置、样式等信息',
|
||||
form_config JSON COMMENT '表单配置',
|
||||
tags JSON COMMENT '流程标签',
|
||||
|
||||
|
||||
@ -159,7 +159,7 @@ INSERT INTO sys_external_system (
|
||||
-- 工作流定义测试数据
|
||||
INSERT INTO workflow_definition (
|
||||
name, `key`, flow_version, description, category,
|
||||
bpmn_xml, graph_data, form_config, tags,
|
||||
bpmn_xml, graph, form_config, tags,
|
||||
status, is_executable, target_namespace,
|
||||
created_at, updated_at, created_by, updated_by, is_deleted
|
||||
) VALUES
|
||||
@ -167,7 +167,7 @@ INSERT INTO workflow_definition (
|
||||
(
|
||||
'简单服务任务流程', 'simple_service_flow', 1, '一个包含服务任务的简单流程', 'test',
|
||||
'<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/test"><process id="simple_service_flow" name="简单服务任务流程" isExecutable="true"><startEvent id="start1" name="开始"></startEvent><serviceTask id="service1" name="服务任务"><extensionElements><flowable:field name="script"><flowable:string><![CDATA[echo "Hello World"]]></flowable:string></flowable:field></extensionElements></serviceTask><endEvent id="end1" name="结束"></endEvent><sequenceFlow id="flow1" sourceRef="start1" targetRef="service1"></sequenceFlow><sequenceFlow id="flow2" sourceRef="service1" targetRef="end1"></sequenceFlow></process></definitions>',
|
||||
'{"nodes":[{"id":"start1","type":"start","position":{"x":100,"y":100}},{"id":"service1","type":"serviceTask","position":{"x":300,"y":100}},{"id":"end1","type":"end","position":{"x":500,"y":100}}],"edges":[{"id":"flow1","source":"start1","target":"service1"},{"id":"flow2","source":"service1","target":"end1"}]}',
|
||||
'{"nodes":[{"id":"start1","type":"start","name":"开始","position":{"x":100,"y":100},"config":{"type":"start"},"properties":{},"size":{"width":40,"height":40}},{"id":"service1","type":"serviceTask","name":"服务任务","position":{"x":300,"y":100},"config":{"type":"serviceTask","implementation":"shell","fields":{"script":{"string":"echo \\"Hello World\\""}}},"properties":{},"size":{"width":100,"height":60}},{"id":"end1","type":"end","name":"结束","position":{"x":500,"y":100},"config":{"type":"end"},"properties":{},"size":{"width":40,"height":40}}],"edges":[{"id":"flow1","source":"start1","target":"service1","name":"","config":{"type":"sequenceFlow"},"properties":{}},{"id":"flow2","source":"service1","target":"end1","name":"","config":{"type":"sequenceFlow"},"properties":{}}],"properties":{}}',
|
||||
'{"formItems":[]}',
|
||||
'["simple","test","service"]',
|
||||
'PUBLISHED', TRUE, 'http://www.flowable.org/test',
|
||||
@ -177,10 +177,8 @@ INSERT INTO workflow_definition (
|
||||
-- 用户任务流程:开始 -> 用户任务 -> 结束
|
||||
(
|
||||
'用户审批流程', 'user_approval_flow', 1, '一个简单的用户审批流程', 'approval',
|
||||
'<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/test"><process id="user_approval_flow" name="用户审批流程"
|
||||
isExecutable="true"><startEvent id="start1" name="开始"></startEvent><userTask id="user1" name="审批任务" flowable:assignee="$${initiator}" flowable:candidateUsers="user1,user2" flowable:candidateGroups="group1,group2" flowable:dueDate="$${dueDate}" flowable:formKey="form1"
|
||||
flowable:priority="1"></userTask><endEvent id="end1" name="结束"></endEvent><sequenceFlow id="flow1" name="提交审批" sourceRef="start1" targetRef="user1"></sequenceFlow><sequenceFlow id="flow2" name="审批完成" sourceRef="user1" targetRef="end1"></sequenceFlow></process></definitions>',
|
||||
'{"nodes":[{"id":"start1","type":"start","position":{"x":100,"y":100}},{"id":"user1","type":"userTask","position":{"x":300,"y":100}},{"id":"end1","type":"end","position":{"x":500,"y":100}}],"edges":[{"id":"flow1","source":"start1","target":"user1","label":"提交审批"},{"id":"flow2","source":"user1","target":"end1","label":"审批完成"}]}',
|
||||
'<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/test"><process id="user_approval_flow" name="用户审批流程" isExecutable="true"><startEvent id="start1" name="开始"></startEvent><userTask id="user1" name="审批任务" flowable:assignee="$${initiator}" flowable:candidateUsers="user1,user2" flowable:candidateGroups="group1,group2" flowable:dueDate="$${dueDate}" flowable:formKey="form1" flowable:priority="1"></userTask><endEvent id="end1" name="结束"></endEvent><sequenceFlow id="flow1" name="提交审批" sourceRef="start1" targetRef="user1"></sequenceFlow><sequenceFlow id="flow2" name="审批完成" sourceRef="user1" targetRef="end1"></sequenceFlow></process></definitions>',
|
||||
'{"nodes":[{"id":"start1","type":"start","name":"开始","position":{"x":100,"y":100},"config":{"type":"start"},"properties":{},"size":{"width":40,"height":40}},{"id":"user1","type":"userTask","name":"审批任务","position":{"x":300,"y":100},"config":{"type":"userTask","assignee":"user1"},"properties":{},"size":{"width":100,"height":60}},{"id":"end1","type":"end","name":"结束","position":{"x":500,"y":100},"config":{"type":"end"},"properties":{},"size":{"width":40,"height":40}}],"edges":[{"id":"flow1","source":"start1","target":"user1","name":"提交审批","config":{"type":"sequenceFlow"},"properties":{}},{"id":"flow2","source":"user1","target":"end1","name":"审批完成","config":{"type":"sequenceFlow"},"properties":{}}],"properties":{}}',
|
||||
'{"formItems":[{"type":"input","label":"意见","name":"comment","required":true}]}',
|
||||
'["approval","user-task"]',
|
||||
'PUBLISHED', TRUE, 'http://www.flowable.org/test',
|
||||
@ -190,9 +188,8 @@ flowable:priority="1"></userTask><endEvent id="end1" name="结束"></endEvent><s
|
||||
-- 复杂流程:开始 -> 服务任务 -> 用户任务 -> 脚本任务 -> 结束
|
||||
(
|
||||
'复杂业务流程', 'complex_business_flow', 1, '包含多种任务节点的复杂业务流程', 'business',
|
||||
'<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/test"><process id="complex_business_flow"
|
||||
name="复杂业务流程" isExecutable="true"><startEvent id="start1" name="开始"></startEvent><serviceTask id="service1" name="服务任务"><extensionElements><flowable:field name="implementation"><flowable:string><![CDATA[com.example.ServiceTask]]></flowable:string></flowable:field></extensionElements></serviceTask><userTask id="user1" name="用户任务" flowable:assignee="user1"></userTask><scriptTask id="script1" name="脚本任务" scriptFormat="groovy"><script><![CDATA[println "Hello"]]></script></scriptTask><endEvent id="end1" name="结束"></endEvent><sequenceFlow id="flow1" sourceRef="start1" targetRef="service1"></sequenceFlow><sequenceFlow id="flow2" sourceRef="service1" targetRef="user1"><conditionExpression xsi:type="tFormalExpression">$${condition}</conditionExpression></sequenceFlow><sequenceFlow id="flow3" sourceRef="user1" targetRef="script1"></sequenceFlow><sequenceFlow id="flow4" sourceRef="script1" targetRef="end1"></sequenceFlow></process></definitions>',
|
||||
'{"nodes":[{"id":"start1","type":"start","position":{"x":100,"y":100}},{"id":"service1","type":"serviceTask","position":{"x":300,"y":100}},{"id":"user1","type":"userTask","position":{"x":500,"y":100}},{"id":"script1","type":"scriptTask","position":{"x":700,"y":100}},{"id":"end1","type":"end","position":{"x":900,"y":100}}],"edges":[{"id":"flow1","source":"start1","target":"service1"},{"id":"flow2","source":"service1","target":"user1","label":"条件分支"},{"id":"flow3","source":"user1","target":"script1"},{"id":"flow4","source":"script1","target":"end1"}]}',
|
||||
'<?xml version="1.0" encoding="UTF-8"?><definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:flowable="http://flowable.org/bpmn" targetNamespace="http://www.flowable.org/test"><process id="complex_business_flow" name="复杂业务流程" isExecutable="true"><startEvent id="start1" name="开始"></startEvent><serviceTask id="service1" name="服务任务"><extensionElements><flowable:field name="implementation"><flowable:string><![CDATA[com.example.ServiceTask]]></flowable:string></flowable:field></extensionElements></serviceTask><userTask id="user1" name="用户任务" flowable:assignee="user1"></userTask><scriptTask id="script1" name="脚本任务" scriptFormat="groovy"><script><![CDATA[println "Hello"]]></script></scriptTask><endEvent id="end1" name="结束"></endEvent><sequenceFlow id="flow1" sourceRef="start1" targetRef="service1"></sequenceFlow><sequenceFlow id="flow2" sourceRef="service1" targetRef="user1"><conditionExpression xsi:type="tFormalExpression">$${condition}</conditionExpression></sequenceFlow><sequenceFlow id="flow3" sourceRef="user1" targetRef="script1"></sequenceFlow><sequenceFlow id="flow4" sourceRef="script1" targetRef="end1"></sequenceFlow></process></definitions>',
|
||||
'{"nodes":[{"id":"start1","type":"start","name":"开始","position":{"x":100,"y":100},"config":{"type":"start"},"properties":{},"size":{"width":40,"height":40}},{"id":"service1","type":"serviceTask","name":"服务任务","position":{"x":300,"y":100},"config":{"type":"serviceTask","implementation":"com.example.ServiceTask"},"properties":{},"size":{"width":100,"height":60}},{"id":"user1","type":"userTask","name":"用户任务","position":{"x":500,"y":100},"config":{"type":"userTask","assignee":"user1"},"properties":{},"size":{"width":100,"height":60}},{"id":"script1","type":"scriptTask","name":"脚本任务","position":{"x":700,"y":100},"config":{"type":"scriptTask","scriptFormat":"groovy","script":"println \\"Hello\\""},"properties":{},"size":{"width":100,"height":60}},{"id":"end1","type":"end","name":"结束","position":{"x":900,"y":100},"config":{"type":"end"},"properties":{},"size":{"width":40,"height":40}}],"edges":[{"id":"flow1","source":"start1","target":"service1","name":"","config":{"type":"sequenceFlow"},"properties":{}},{"id":"flow2","source":"service1","target":"user1","name":"条件分支","config":{"type":"sequenceFlow","conditionExpression":"$${condition}"},"properties":{}},{"id":"flow3","source":"user1","target":"script1","name":"","config":{"type":"sequenceFlow"},"properties":{}},{"id":"flow4","source":"script1","target":"end1","name":"","config":{"type":"sequenceFlow"},"properties":{}}],"properties":{}}',
|
||||
'{"formItems":[{"type":"input","label":"业务参数","name":"businessParam","required":true},{"type":"select","label":"审批结果","name":"approvalResult","options":[{"label":"同意","value":"approve"},{"label":"拒绝","value":"reject"}]}]}',
|
||||
'["complex","business","multi-task"]',
|
||||
'PUBLISHED', TRUE, 'http://www.flowable.org/test',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user