flowable已发起流程变更节点、修改节点路径、移动节点
flowable已发起流程变更节点、修改节点路径、移动节点
1.引入包:为了后面自适应排版
implementation "org.flowable:flowable-bpmn-layout:6.4.1"
2.模版类:UserTaskDTO
@Data
public class UserTaskDTO {
@NotNull(message = "type不能为空")
private Integer type;
private String taskId;
@NotBlank(message = "processInstanceId不能为空")
private String processInstanceId;
private String id;
private String name;
private String assignee;
private String formKey;
private MultiInstanceLoopCharacteristicsDTO multiInstanceLoopCharacteristicsDTO;
private List<TaskListenerDTO> taskListenerList;
private List<ExecutionListenerDTO> executionListenerList;
private List<SequenceFlowDTO> sequenceFlowList;
}
3.模版类:MultiInstanceLoopCharacteristicsDTO
@Data
public class MultiInstanceLoopCharacteristicsDTO {
private String completionCondition;
private Boolean sequential;
private String inputDataItem;
private String elementVariable;
}
4.模版类:TaskListenerDTO
@Data
public class TaskListenerDTO {
private String event;
private String implementationType ="class";
private String implementation;
}
5.模版类:ExecutionListenerDTO
@Data
public class ExecutionListenerDTO {
private String event;
private String implementationType ="class";
private String implementation;
}
6.模版类:SequenceFlowDTO
@Data
public class SequenceFlowDTO {
private String name;
private String documentation;
private String conditionExpression;
private String sourceRef;
private String targetRef;
private String skipExpression;
}
7.实现方法
@Slf4j
public class CustomInjectUserTaskInProcessInstanceCmd extends AbstractDynamicInjectionCmd implements Command<Void> {
protected UserTaskDTO userTaskDTO;
protected DynamicUserTaskBuilder dynamicUserTaskBuilder;
private final FlowElement currentFlowElemet;
public CustomInjectUserTaskInProcessInstanceCmd(UserTaskDTO userTaskDTO, DynamicUserTaskBuilder dynamicUserTaskBuilder, FlowElement currentFlowElemet) {
this.userTaskDTO = userTaskDTO;
this.dynamicUserTaskBuilder = dynamicUserTaskBuilder;
this.currentFlowElemet = currentFlowElemet;
}
@Override
public Void execute(CommandContext commandContext) {
createDerivedProcessDefinitionForProcessInstance(commandContext, userTaskDTO.getProcessInstanceId());
return null;
}
@Override
protected void updateBpmnProcess(CommandContext commandContext, Process process,
BpmnModel bpmnModel, ProcessDefinitionEntity originalProcessDefinitionEntity, DeploymentEntity newDeploymentEntity){
if(userTaskDTO.getType().equals(0)){
List<StartEvent> startEvents = process.findFlowElementsOfType(StartEvent.class);
StartEvent initialStartEvent = null;
for (StartEvent startEvent : startEvents) {
if (startEvent.getEventDefinitions().isEmpty()) {
initialStartEvent = startEvent;
break;
} else if (initialStartEvent == null) {
initialStartEvent = startEvent;
}
}
UserTask userTask = new UserTask();
userTask.setId(userTaskDTO.getId());
userTask.setName(userTaskDTO.getName());
userTask.setAssignee(userTaskDTO.getAssignee());
if(CollectionUtil.isNotEmpty(userTaskDTO.getTaskListenerList())){
List<FlowableListener>flowableListenerList=new ArrayList<>();
userTaskDTO.getTaskListenerList().forEach(task->{
FlowableListener flowableListener=new FlowableListener();
flowableListener.setEvent(task.getEvent());
flowableListener.setImplementationType(task.getImplementationType());
flowableListener.setImplementation(task.getImplementation());
flowableListenerList.add(flowableListener);
});
userTask.setTaskListeners(flowableListenerList);
}
if(CollectionUtil.isNotEmpty(userTaskDTO.getExecutionListenerList())){
List<FlowableListener>flowableListenerList=new ArrayList<>();
userTaskDTO.getExecutionListenerList().forEach(execution->{
FlowableListener flowableListener=new FlowableListener();
flowableListener.setEvent(execution.getEvent());
flowableListener.setImplementationType(execution.getImplementationType());
flowableListener.setImplementation(execution.getImplementation());
flowableListenerList.add(flowableListener);
});
userTask.setExecutionListeners(flowableListenerList);
}
if(StrUtil.isNotBlank(userTaskDTO.getFormKey())){
userTask.setFormKey(userTaskDTO.getFormKey());
}
MultiInstanceLoopCharacteristicsDTO multiInstanceLoopCharacteristicsDtos = userTaskDTO.getMultiInstanceLoopCharacteristicsDTO();
if(multiInstanceLoopCharacteristicsDtos!=null){
MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics=new MultiInstanceLoopCharacteristics();
multiInstanceLoopCharacteristics.setCompletionCondition(multiInstanceLoopCharacteristicsDtos.getCompletionCondition());
multiInstanceLoopCharacteristics.setSequential(multiInstanceLoopCharacteristicsDtos.getSequential());
multiInstanceLoopCharacteristics.setInputDataItem(multiInstanceLoopCharacteristicsDtos.getInputDataItem());
multiInstanceLoopCharacteristics.setElementVariable(multiInstanceLoopCharacteristicsDtos.getElementVariable());
userTask.setLoopCharacteristics(multiInstanceLoopCharacteristics);
}
UserTask currentFlowElemet = (UserTask) this.currentFlowElemet;
SequenceFlow sequenceFlow;
List<SequenceFlow> outgoingFlows = new ArrayList<>();
if(CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())){
for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
process.removeFlowElement(sequenceFlow1.getId());
}
for (SequenceFlowDTO sequenceFlowNew :userTaskDTO.getSequenceFlowList()){
sequenceFlow = new SequenceFlow(StrUtil.isBlank(sequenceFlowNew.getSourceRef())?userTask.getId():sequenceFlowNew.getSourceRef(),sequenceFlowNew.getTargetRef());
sequenceFlow.setSkipExpression(sequenceFlowNew.getSkipExpression());
sequenceFlow.setConditionExpression(sequenceFlowNew.getConditionExpression());
sequenceFlow.setName(sequenceFlowNew.getName());
sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
outgoingFlows.add(sequenceFlow);
process.addFlowElement(sequenceFlow);
}
}else{
for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
sequenceFlow = new SequenceFlow(userTask.getId(),sequenceFlow1.getTargetRef());
sequenceFlow.setSkipExpression(sequenceFlow1.getSkipExpression());
sequenceFlow.setConditionExpression(sequenceFlow1.getConditionExpression());
sequenceFlow.setExtensionElements(sequenceFlow1.getExtensionElements());
sequenceFlow.setExecutionListeners(sequenceFlow1.getExecutionListeners());
sequenceFlow.setName(sequenceFlow1.getName());
sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
outgoingFlows.add(sequenceFlow);
process.removeFlowElement(sequenceFlow1.getId());
process.addFlowElement(sequenceFlow);
}
}
List<SequenceFlow> incomingFlows = new ArrayList<>();
SequenceFlow incomingFlow = new SequenceFlow(currentFlowElemet.getId(),userTask.getId());
incomingFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
incomingFlows.add(incomingFlow);
process.addFlowElement(incomingFlow);
userTask.setOutgoingFlows(outgoingFlows);
userTask.setIncomingFlows(incomingFlows);
process.addFlowElement(userTask);
GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(currentFlowElemet.getId());
if (elementGraphicInfo != null) {
double yDiff = 0;
double xDiff = 80;
if (elementGraphicInfo.getY() < 173) {
yDiff = 173 - elementGraphicInfo.getY();
elementGraphicInfo.setY(173);
}
Map<String, GraphicInfo> locationMap = bpmnModel.getLocationMap();
for (String locationId : locationMap.keySet()) {
if (initialStartEvent != null && initialStartEvent.getId().equals(locationId)) {
continue;
}
GraphicInfo locationGraphicInfo = locationMap.get(locationId);
locationGraphicInfo.setX(locationGraphicInfo.getX() + xDiff);
locationGraphicInfo.setY(locationGraphicInfo.getY() + yDiff);
}
Map<String, List<GraphicInfo>> flowLocationMap = bpmnModel.getFlowLocationMap();
for (String flowId : flowLocationMap.keySet()) {
List<GraphicInfo> flowGraphicInfoList = flowLocationMap.get(flowId);
for (GraphicInfo flowGraphicInfo : flowGraphicInfoList) {
flowGraphicInfo.setX(flowGraphicInfo.getX() + xDiff);
flowGraphicInfo.setY(flowGraphicInfo.getY() + yDiff);
}
}
new BpmnAutoLayout(bpmnModel).execute();
}
}
}else if(userTaskDTO.getType().equals(1)){
UserTask currentFlowElemet = (UserTask) this.currentFlowElemet;
SequenceFlow sequenceFlow;
List<SequenceFlow> outgoingFlows = new ArrayList<>();
if(CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())){
process.removeFlowElement(currentFlowElemet.getId());
for (SequenceFlow sequenceFlow1 : currentFlowElemet.getOutgoingFlows()) {
process.removeFlowElement(sequenceFlow1.getId());
}
for (SequenceFlowDTO sequenceFlowNew :userTaskDTO.getSequenceFlowList()){
sequenceFlow = new SequenceFlow(currentFlowElemet.getId(),sequenceFlowNew.getTargetRef());
sequenceFlow.setSkipExpression(sequenceFlowNew.getSkipExpression());
sequenceFlow.setConditionExpression(sequenceFlowNew.getConditionExpression());
sequenceFlow.setName(sequenceFlowNew.getName());
sequenceFlow.setId("seq_"+ UUID.randomUUID().toString().replaceAll("-","" ));
outgoingFlows.add(sequenceFlow);
process.addFlowElement(sequenceFlow);
}
}
currentFlowElemet.setOutgoingFlows(outgoingFlows);
process.addFlowElement(currentFlowElemet);
GraphicInfo elementGraphicInfo = bpmnModel.getGraphicInfo(currentFlowElemet.getId());
if (elementGraphicInfo != null) {
new BpmnAutoLayout(bpmnModel).execute();
}
}
BaseDynamicSubProcessInjectUtil.processFlowElements(commandContext, process, bpmnModel, originalProcessDefinitionEntity, newDeploymentEntity);
}
@Override
protected void updateExecutions(CommandContext commandContext, ProcessDefinitionEntity processDefinitionEntity,
ExecutionEntity processInstance, List<ExecutionEntity> childExecutions) {
BpmnModel bpmnModel = ProcessDefinitionUtil.getBpmnModel(processDefinitionEntity.getId());
try {
BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
byte[] bpmnBytes = bpmnXMLConverter.convertToXML(bpmnModel);
String bpmnXml = new String(bpmnBytes, StandardCharsets.UTF_8);
System.out.println(bpmnXml);
}catch (Exception e){
log.error(e.getMessage());
}
}
8.调用方法
@Component
@RequiredArgsConstructor
@Slf4j
public class UpdateBpmnUtil {
private final ProcessEngine processEngine;
public void updateBpmn(UserTaskDTO userTaskDTO) {
if(userTaskDTO.getType().equals(1)){
if (StrUtil.isBlank(userTaskDTO.getId())){
throw new CustomException("9999", "移动节点NodeID不存在!");
}
}
if (CollectionUtil.isNotEmpty(userTaskDTO.getExecutionListenerList())) {
userTaskDTO.getExecutionListenerList().forEach(execution -> {
if (!execution.getEvent().equals("start") && !execution.getEvent().equals("end") && !execution.getEvent().equals("task")) {
throw new CustomException("9999", "执行监听器不存在此类型!");
}
if (classIsExist(execution.getImplementation())) {
throw new CustomException("9999", "此类:" + execution.getImplementation() + "不存在");
}
});
}
if (CollectionUtil.isNotEmpty(userTaskDTO.getTaskListenerList())) {
userTaskDTO.getTaskListenerList().forEach(task -> {
if (!task.getEvent().equals("create") && !task.getEvent().equals("assignment") && !task.getEvent().equals("complete") && !task.getEvent().equals("delete")) {
throw new CustomException("9999", "任务监听器不存在");
}
if (classIsExist(task.getImplementation())) {
throw new CustomException("9999", "此类:" + task.getImplementation() + "不存在");
}
});
}
if (CollectionUtil.isNotEmpty(userTaskDTO.getSequenceFlowList())) {
Set<String> sequenceKey=new HashSet<>();
userTaskDTO.getSequenceFlowList().forEach(sequence -> {
if(!sequenceKey.contains(sequence.getConditionExpression())){
sequenceKey.add(sequence.getConditionExpression());
}else{
throw new CustomException("9999", "此:" +sequence.getConditionExpression() + "表达式重复!");
}
});
}
DynamicUserTaskBuilder dynamicUserTaskBuilder = new DynamicUserTaskBuilder();
if (StrUtil.isBlank(userTaskDTO.getId())) {
userTaskDTO.setId("sid-" + UUID.randomUUID());
} else {
userTaskDTO.setId("sid-" + userTaskDTO.getId());
}
List<Task> list = processEngine.getTaskService().createTaskQuery().active().taskId(userTaskDTO.getTaskId()).list();
if (CollectionUtil.isEmpty(list)) {
list = processEngine.getTaskService().createTaskQuery().active().processInstanceId(userTaskDTO.getProcessInstanceId()).list();
}
if (CollectionUtil.isNotEmpty(list)) {
Task task = list.get(0);
BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(task.getProcessDefinitionId());
dynamicUserTaskBuilder.setId(userTaskDTO.getId());
dynamicUserTaskBuilder.setAssignee(userTaskDTO.getAssignee());
dynamicUserTaskBuilder.setName(userTaskDTO.getName());
Process process = bpmnModel.getProcesses().get(0);
try {
processEngine.getManagementService().executeCommand(new CustomInjectUserTaskInProcessInstanceCmd(userTaskDTO, dynamicUserTaskBuilder, process.getFlowElement(task.getTaskDefinitionKey())));
} catch (Exception e) {
throw new CustomException("999999", e.getMessage());
}
}
}
public boolean classIsExist(String className) {
try {
String path = ResourceUtils.getURL("classpath:").getPath();
File file = new File(path + className.replace(".", "/") + ".class");
return !file.exists();
} catch (Exception e) {
return true;
}
}
public void moveNode(MoveNodeDTO moveNodeDTO) {
processEngine.getRuntimeService().createChangeActivityStateBuilder()
.processInstanceId(moveNodeDTO.getProcessInstanceId())
.moveActivityIdTo(moveNodeDTO.getNodeId(), moveNodeDTO.getToNodeId())
.changeState();
}
public String lookXmlForFlowable(BpmnGetMyTaskDTO bpmnGetMyTaskDTO) {
String bpmnXml = "";
List<HistoricTaskInstance> list = processEngine.getHistoryService().createHistoricTaskInstanceQuery().processInstanceId(bpmnGetMyTaskDTO.getProcessInstanceId()).list();
if (CollectionUtil.isNotEmpty(list)) {
BpmnModel bpmnModel = processEngine.getRepositoryService().getBpmnModel(list.get(0).getProcessDefinitionId());
BpmnXMLConverter bpmnXMLConverter = new BpmnXMLConverter();
byte[] bpmnBytes = bpmnXMLConverter.convertToXML(bpmnModel);
bpmnXml = new String(bpmnBytes, StandardCharsets.UTF_8);
System.out.println(bpmnXml);
}
return bpmnXml;
}
9.入参JSON
- 新增节点 (所有的操作仅在流程流转到当前节点。配置下一节点有效)
{
"type":0,
"processInstanceId": "??????",
"taskId": "??????",
"id": "??????",
"formKey": "",
"name": "新增节点40",
"assignee": "${user}",
"multiInstanceLoopCharacteristicsDTO": {
"completionCondition": "??????",
"sequential": false,
"inputDataItem": "${UserList}",
"elementVariable": "user"
},
"taskListenerList": [
{
"event": "create",
"implementationType": "class",
"implementation": "*.listener.TestTaskListener"
},
{
"event": "complete",
"implementationType": "class",
"implementation": "*.listener.TestTaskListener"
}
],
"executionListenerList": [
{
"event": "start",
"implementationType": "class",
"implementation": "*.listener.TestListener"
},
{
"event": "end",
"implementationType": "class",
"implementation": "*.listener.TestListener"
}
]
,
"sequenceFlowList": [
{
"name": "3333",
"documentation": "55555555",
"conditionExpression": "${ok == 0}",
"sourceRef": "",
"targetRef": "??????",
"skipExpression": ""
}
, {
"name": "44444",
"documentation": "66666",
"conditionExpression": "${ok == 1}",
"sourceRef": "",
"targetRef": "??????",
"skipExpression": ""
},
{
"name": "77777",
"documentation": "88888",
"conditionExpression": "${ok == 2}",
"sourceRef": "",
"targetRef": "??????",
"skipExpression": ""
}
]
}
- 查看流程引擎xml文件
{
"processInstanceId": "??????"
}
- 修改流程节点路径 (所有的操作仅在流程流转到当前节点。配置下一节点有效)
{
"type": 1,
"processInstanceId": "??????",
"taskId": "??????",
"id":"??????",
"sequenceFlowList": [
{
"name": "3333",
"documentation": "55555555",
"conditionExpression": "${ok == 1}",
"targetRef": "??????",
"skipExpression": ""
}
, {
"name": "44444",
"documentation": "66666",
"conditionExpression": "${ok == 0}",
"sourceRef": "",
"targetRef": "??????",
"skipExpression": ""
}
]
}