定时器事件用于在特定的日期,时间或者周期触发一个事件。它们可以用做开始事件、中间事件、边界事件。边界事件可以是中断的,也可以是非中断的。默认是中断事件,即当触发定时器时,原执行实例会被删除。
- 开始事件定时器
定时器开始事件用于在指定的时间点或者周期创建流程实例。 - 中间捕获事件定时器
定时器中间事件可以充当秒表,当执行到中间捕获事件活动时,将启动定时器,经过指定时间后定时器触发时,将沿着离开事件的序列继续执行。 - 边界事件定时器
边界事件定时器可以充当秒表和闹钟,当执行到达附有边界事件的活动时,将启动定时器。当定时器触发时,会根据是否为中断事件来中断当前活动,沿着离开定时器边界事件的序列继续执行。
创建流程
现在用java代码的方式来创建各个事件的定时器。
String modelName = "timeEvent";
String name = "事件定时器";
Process process = new Process();
UserTask userTask = createUserTask("user", "用户或签节点", 1);
process.addFlowElement(userTask);
process.addFlowElement(createTimeStartEvent("timeStart","开始事件定时器"));
process.addFlowElement(createEndEvent("end","结束"));
process.addFlowElement(createTimeBoundaryEvent("timeBoundary","定时器边界事件","user",userTask));
process.addFlowElement(createTimeIntermediateCatchEvent("timeIntermediateCatch","定时器中间捕获事件"));
process.addFlowElement(createSequenceFlow("timeStart","user"));
process.addFlowElement(createSequenceFlow("user","timeIntermediateCatch"));
process.addFlowElement(createSequenceFlow("timeBoundary","timeIntermediateCatch"));
process.addFlowElement(createSequenceFlow("timeIntermediateCatch","end"));
BpmnModel bpmnModel = new BpmnModel();
bpmnModel.addProcess(process);
process.setId(modelName);
process.setName(name);
//流程部署
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
Deployment deploy = deploymentBuilder
.addBpmnModel(modelName+".bpmn", bpmnModel)
.name(name)
.deploy();
String deployId = deploy.getId();
System.out.println("流程部署id: "+deployId);
//流程定义
List<ProcessDefinition> processDefinitions = repositoryService.createProcessDefinitionQuery().deploymentId(deployId).list();
for(ProcessDefinition pd : processDefinitions){
System.out.println("------流程定义--------");
System.out.println("Name:"+pd.getName());
System.out.println("Key:"+pd.getKey());
System.out.println("ResourceName:"+pd.getResourceName());
System.out.println("DeploymentId:"+pd.getDeploymentId());
System.out.println("Version:"+pd.getVersion());
}
创建各个节点与事件
private SequenceFlow createSequenceFlow(String from, String to) {
SequenceFlow flow = new SequenceFlow();
flow.setSourceRef(from);
flow.setTargetRef(to);
return flow;
}
/**
* 创建多实例任务节点
*/
private UserTask createUserTask(String id, String name, int examineMode) {
UserTask userTask = new UserTask();
userTask.setName(name);
userTask.setId(id);
//普通任务节点
if (examineMode < 2) {
return userTask;
}
//2044 mx1
//2048 mx3
//多实例任务节点
//examineMode 1 或签 2 多实例 超过一半 3 多实例 依次审批 4 多实例 全部审批
MultiInstanceLoopCharacteristics characteristics = new MultiInstanceLoopCharacteristics();
//设置执行人
userTask.setAssignee("${" + ActivitiTools.MUIT_VAR_NAME + "}");
// 设置集合变量,统一设置成users
characteristics.setInputDataItem("${" + ActivitiTools.MUIT_LIST_NAME + "}");
// 设置变量
characteristics.setElementVariable(ActivitiTools.MUIT_VAR_NAME);
if (examineMode == ActConstant.SIGN_TYPE_AND_HALF) {
// 设置为同时接收(false 表示不按顺序执行)
characteristics.setSequential(false);
// 设置条件(暂时处理成,全部会签完转下步)
characteristics.setCompletionCondition("${nrOfCompletedInstances/nrOfInstances >= 0.5 }");
} else if (examineMode == ActConstant.SIGN_TYPE_AND_SEQ) {
// 设置为同时接收(false 表示不按顺序执行)
characteristics.setSequential(true);
// 设置条件(暂时处理成,全部会签完转下步)
characteristics.setCompletionCondition("${nrOfCompletedInstances==nrOfInstances}");
} else if (examineMode == ActConstant.SIGN_TYPE_AND) {
// 设置为同时接收(false 表示不按顺序执行)
characteristics.setSequential(false);
// 设置条件(暂时处理成,全部会签完转下步)
characteristics.setCompletionCondition("${nrOfCompletedInstances==nrOfInstances}");
} else {
throw new BusinessException("暂不支持该种审批方式");
}
userTask.setLoopCharacteristics(characteristics);
return userTask;
}
/**
* 创建开始节点
*/
private StartEvent createStartEvent(String id, String name) {
StartEvent startEvent = new StartEvent();
startEvent.setId(id);
startEvent.setName(name);
return startEvent;
}
/**
* 创建结束节点
*/
private EndEvent createEndEvent(String id, String name) {
EndEvent endEvent = new EndEvent();
endEvent.setId(id);
endEvent.setName(name);
return endEvent;
}
/**
* 创建定时器定义
*/
private TimerEventDefinition createTimeEvent() {
TimerEventDefinition timerEventDefinition = new TimerEventDefinition();
timerEventDefinition.setTimeDuration("PT1M");
return timerEventDefinition;
}
/**
* 创建时间事件
* P1D:代表1天后执行此时间定时器。
* P1H:代表1小时后执行此时间定时器。
* P1M:代表1分钟后执行此时间定时器。
* PT1M:代表1分钟后执行此时间定时器。
*/
private BoundaryEvent createTimeBoundaryEvent(String id, String name,String refId,Activity ref) {
List<EventDefinition> eventDefinitions = new ArrayList<>();
eventDefinitions.add(createTimeEvent());
BoundaryEvent boundaryEvent = new BoundaryEvent();
boundaryEvent.setEventDefinitions(eventDefinitions);
boundaryEvent.setId(id);
boundaryEvent.setName(name);
boundaryEvent.setAttachedToRefId(refId);
boundaryEvent.setAttachedToRef(ref);
//是否为中断事件
boundaryEvent.setCancelActivity(true);
return boundaryEvent;
}
/**
* 创建开始事件定时器
* @param id
* @param name
* @return
*/
private StartEvent createTimeStartEvent(String id, String name) {
TimerEventDefinition timerEventDefinition = new TimerEventDefinition();
timerEventDefinition.setTimeDuration("PT1M");
List<EventDefinition> eventDefinitions = new ArrayList<>();
eventDefinitions.add(timerEventDefinition);
StartEvent startEvent = new StartEvent();
startEvent.setEventDefinitions(eventDefinitions);
startEvent.setId(id);
startEvent.setName(name);
return startEvent;
}
/**
* 创建中间捕获事件定时器
* @param id
* @param name
* @return
*/
private IntermediateCatchEvent createTimeIntermediateCatchEvent(String id, String name) {
TimerEventDefinition timerEventDefinition = new TimerEventDefinition();
timerEventDefinition.setTimeDuration("PT1M");
List<EventDefinition> eventDefinitions = new ArrayList<>();
eventDefinitions.add(timerEventDefinition);
IntermediateCatchEvent intermediateCatchEvent = new IntermediateCatchEvent();
intermediateCatchEvent.setEventDefinitions(eventDefinitions);
intermediateCatchEvent.setId(id);
intermediateCatchEvent.setName(name);
return intermediateCatchEvent;
}
流程可视化
以下将新建的流程转换为可编辑模型与图片
//查找流程模型
InputStream resourceAsStream = repositoryService.getResourceAsStream(deployId, modelName + ".bpmn");
XMLInputFactory safeXmlInputFactory = XmlUtil.createSafeXmlInputFactory();
XMLStreamReader xmlStreamReader = safeXmlInputFactory.createXMLStreamReader(resourceAsStream, StandardCharsets.UTF_8.toString());
bpmnModel = new BpmnXMLConverter().convertToBpmnModel(xmlStreamReader);
new BpmnAutoLayout(bpmnModel).execute();
// 查找流程定义
ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployId).singleResult();
Model modelData = repositoryService.newModel();
ObjectNode modelObjectNode = objectMapper.createObjectNode();
modelData.setMetaInfo(modelObjectNode.toString());
modelData.setKey(pd.getKey());
modelData.setName(modelName);
modelData.setMetaInfo("");
modelData.setVersion(1);
repositoryService.saveModel(modelData);
ObjectNode jsonNodes = new BpmnJsonConverter().convertToJson(bpmnModel);
repositoryService.addModelEditorSource(modelData.getId(), jsonNodes.toString().getBytes(StandardCharsets.UTF_8));
//生成流程图片
DefaultProcessDiagramGenerator generator = new DefaultProcessDiagramGenerator();
InputStream imageStream = generator.generateDiagram(bpmnModel, "png", new ArrayList<>(),
new ArrayList<>(), ActivitiTools.FONT_NAME, ActivitiTools.FONT_NAME, ActivitiTools.FONT_NAME, null, 1.0);
byte[] buffer = new byte[imageStream.available()];
imageStream.read(buffer);
repositoryService.addModelEditorSourceExtra(modelData.getId(), buffer);
OutputStream outputStream = new FileOutputStream(new File("D:\\My Documents\\stu\\activiti\\"+bpmnModel+".png"));
outputStream.write(buffer);
outputStream.close();
以下是刚才流程生成的流程图
开始事件定时器
同时act_ru_job有了一个开始事件的定时器任务
等到定时器触发之后。会生成一个用户task任务与一个边界事件定时器任务。
边界事件定时器
边界事件定时器任务
用户节点task任务
等边界事件定时器任务触发之后,由于是中断边界事件,用户节点task任务会被删除。
同时生成一条中间捕获事件任务
中间捕获事件定时器
这时该流程实例存在两个执行实例,一个是主流程执行实例,一个是中间事件的执行实例。
当该定时器触发时,该流程结束。
注意:默认异步执行时关闭的,需要手动打开,springboot项目下可以加配置来启用作业执行器
spring:
activiti:
#启用作业执行器
async-executor-activate: true
#启用异步执行器
job-executor-activate: true