系列文章目录(springboot整合activiti5)

事件网关是基于事件的网关,比如有如下的需求,在申请人发起了申请之后,一分钟之内没有收到任务触发事件,则该任务自动进入到部门领导审批,如果有事件触发,则进入到财务部门审批。看起来挺像排他网关的,但是这里是基于事件的,可以采用事件网关。事件网关的XML代码描述如下

<eventBasedGateway id="eventgateway1" name="Event Gateway"></eventBasedGateway>

对应的流程图如下

springboot 可以指定网卡吗_java


在事件网关之后,只能使用intermediateCatchEvent类型,不能使用其他类型。在intermediateCatchEvent内部可以定义timerEventDefinition(定时事件定义),比如一分钟触发

<intermediateCatchEvent id="timerintermediatecatchevent1" name="TimerCatchEvent">
  <timerEventDefinition>
    <timeDuration>PT1M</timeDuration>
  </timerEventDefinition>
</intermediateCatchEvent>

也可以定义signalEventDefinition(信号事件触发)

<intermediateCatchEvent id="signalintermediatecatchevent1" name="SignalCatchEvent">
  <signalEventDefinition signalRef="alertSignal"></signalEventDefinition>
</intermediateCatchEvent>

完整的流程定义文件如下

<?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:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.zioer.com/reimbursement-10">
  <signal id="alertSignal" name="alert"></signal>
  <process id="reimbursement-10" name="费用报销-10" isExecutable="true">
    <startEvent id="startevent1" name="Start" activiti:initiator="startUserId" activiti:formKey="start.form"></startEvent>
    <userTask id="usertask1" name="部门领导审批" activiti:candidateGroups="leadergroup" activiti:formKey="conform1.form"></userTask>
    <userTask id="usertask3" name="申请人确认" activiti:assignee="${startUserId}" activiti:formKey="conform3.form"></userTask>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow7" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
    <eventBasedGateway id="eventgateway1" name="Event Gateway"></eventBasedGateway>
    <sequenceFlow id="flow8" sourceRef="startevent1" targetRef="eventgateway1"></sequenceFlow>
    <intermediateCatchEvent id="timerintermediatecatchevent1" name="TimerCatchEvent">
      <timerEventDefinition>
        <timeDuration>PT1M</timeDuration>
      </timerEventDefinition>
    </intermediateCatchEvent>
    <sequenceFlow id="flow9" sourceRef="eventgateway1" targetRef="timerintermediatecatchevent1"></sequenceFlow>
    <sequenceFlow id="flow10" sourceRef="timerintermediatecatchevent1" targetRef="usertask1"></sequenceFlow>
    <intermediateCatchEvent id="signalintermediatecatchevent1" name="SignalCatchEvent">
      <signalEventDefinition signalRef="alertSignal"></signalEventDefinition>
    </intermediateCatchEvent>
    <userTask id="usertask4" name="财务部门审批" activiti:candidateGroups="feegroup" activiti:formKey="conform2.form"></userTask>
    <sequenceFlow id="flow11" sourceRef="eventgateway1" targetRef="signalintermediatecatchevent1"></sequenceFlow>
    <sequenceFlow id="flow12" sourceRef="signalintermediatecatchevent1" targetRef="usertask4"></sequenceFlow>
    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>
    <sequenceFlow id="flow13" sourceRef="usertask1" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow14" sourceRef="usertask4" targetRef="exclusivegateway1"></sequenceFlow>
    <sequenceFlow id="flow15" sourceRef="exclusivegateway1" targetRef="usertask3"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_reimbursement-10">
    <bpmndi:BPMNPlane bpmnElement="reimbursement-10" id="BPMNPlane_reimbursement-10">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="60.0" y="147.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="280.0" y="90.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="520.0" y="137.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="680.0" y="147.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="eventgateway1" id="BPMNShape_eventgateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="141.0" y="144.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="timerintermediatecatchevent1" id="BPMNShape_timerintermediatecatchevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="210.0" y="100.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="signalintermediatecatchevent1" id="BPMNShape_signalintermediatecatchevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="210.0" y="210.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4">
        <omgdc:Bounds height="55.0" width="105.0" x="280.0" y="200.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">
        <omgdc:Bounds height="40.0" width="40.0" x="430.0" y="151.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
        <omgdi:waypoint x="625.0" y="164.0"></omgdi:waypoint>
        <omgdi:waypoint x="680.0" y="164.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
        <omgdi:waypoint x="95.0" y="164.0"></omgdi:waypoint>
        <omgdi:waypoint x="141.0" y="164.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
        <omgdi:waypoint x="161.0" y="144.0"></omgdi:waypoint>
        <omgdi:waypoint x="161.0" y="117.0"></omgdi:waypoint>
        <omgdi:waypoint x="210.0" y="117.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
        <omgdi:waypoint x="245.0" y="117.0"></omgdi:waypoint>
        <omgdi:waypoint x="280.0" y="117.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
        <omgdi:waypoint x="161.0" y="184.0"></omgdi:waypoint>
        <omgdi:waypoint x="161.0" y="227.0"></omgdi:waypoint>
        <omgdi:waypoint x="210.0" y="227.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow12" id="BPMNEdge_flow12">
        <omgdi:waypoint x="245.0" y="227.0"></omgdi:waypoint>
        <omgdi:waypoint x="280.0" y="227.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">
        <omgdi:waypoint x="385.0" y="117.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="117.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="151.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14">
        <omgdi:waypoint x="385.0" y="227.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="227.0"></omgdi:waypoint>
        <omgdi:waypoint x="450.0" y="191.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow15" id="BPMNEdge_flow15">
        <omgdi:waypoint x="470.0" y="171.0"></omgdi:waypoint>
        <omgdi:waypoint x="520.0" y="164.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

对应的控制层代码TimeController如下

package com.xquant.platform.test.activiti.controller;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.activiti.engine.FormService;
import org.activiti.engine.HistoryService;
import org.activiti.engine.IdentityService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricDetail;
import org.activiti.engine.impl.persistence.entity.HistoricProcessInstanceEntity;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.Execution;
import org.activiti.engine.runtime.ExecutionQuery;
import org.activiti.engine.task.Task;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * 事件网关
 */
@Controller
@RequestMapping(value = "/time")
public class TimeController {
	
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private FormService formService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IdentityService identityService;
    @Autowired
    private HistoryService historyService;
    @Autowired
    private RuntimeService runtimeService;
    
    @RequestMapping(value = "/add")
    public String add(Model model,HttpSession session) {
    	if (session.getAttribute("userId") == null){
    		return "redirect:/login/";
    	}
    	        
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
        		.processDefinitionKey("reimbursement-10")
        		.latestVersion().singleResult();

        Object startForm = formService.getRenderedStartForm(processDefinition.getId());
        
		model.addAttribute("formData", startForm);
    	return "reimbursement-5_start";
    }
    
    /**
     * 提交启动流程
     */
    @RequestMapping(value = "/start/save")
    public String saveStartForm(Model model,HttpServletRequest request,HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	Map formProperties = PageData(request);
        ProcessDefinition processDefinition = repositoryService
        		.createProcessDefinitionQuery()
        		.processDefinitionKey("reimbursement-10")
        		.latestVersion().singleResult();
        String processDefinitionId = processDefinition.getId();
        try {
            identityService.setAuthenticatedUserId(userId);
            formService.submitStartFormData(processDefinitionId, formProperties);
            
        } finally {
            identityService.setAuthenticatedUserId(null);
        }

        return "redirect:/time/list";
    }

    @RequestMapping(value = "/list")
    public String list(Model model,HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	List<Task> tasks = new ArrayList<Task>();
    	
    	//获得当前用户的任务
    	tasks = taskService.createTaskQuery().processDefinitionKey("reimbursement-10")
    			.taskCandidateOrAssigned(userId)
    			.active()
    			.orderByTaskId().desc().list();
    	
    	model.addAttribute("list", tasks);
    	
    	return "reimbursement-5_list";
    }
    
    /**
     * 接收信号
     * @param model
     * @param session
     * @return
     */
    @RequestMapping(value = "/receive")
    public String receive(Model model,HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	
      ExecutionQuery executionQuery = runtimeService.createExecutionQuery();
      List<Execution> executions = executionQuery.signalEventSubscriptionName("alert").list();

      for (int j=0;j<executions.size();j++){
      	Execution execution = executions.get(j);
      	if (execution != null){
      		// 接收信号处理
      		runtimeService.signalEventReceived("alert", execution.getId());
      	}
      }
      
    	List<Task> tasks = new ArrayList<Task>();
    	
    	//获得当前用户的任务
    	tasks = taskService.createTaskQuery().processDefinitionKey("reimbursement-10")
    			.taskCandidateOrAssigned(userId)
    			.active()
    			.orderByTaskId().desc().list();
    	
    	model.addAttribute("list", tasks);
    	
    	return "reimbursement-5_list";
    }
    
    /**
     * 任务签收
     */
    @RequestMapping(value = "/claim/{taskId}")
    public String claim(@PathVariable("taskId") String taskId, HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
        taskService.claim(taskId, userId);
        return "redirect:/time/list";
    }
    
    /**
     * 初始化启动流程,读取启动流程的表单字段来渲染start form
     */
    @RequestMapping(value = "/startform/{taskId}")
    public String StartTaskForm(@PathVariable("taskId") String taskId,Model model,HttpSession session) throws Exception {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	Object taskForm = formService.getRenderedTaskForm(taskId);        
        String startUserId = (String) taskService.getVariable(taskId, "startUserId"); 
        
        model.addAttribute("formData", taskForm);
        model.addAttribute("taskId", taskId);
        model.addAttribute("startUserId", startUserId);
        
        return "reimbursement-5_edit";
    }
    /**
     * 提交启动流程
     */
    @RequestMapping(value = "/startform/save/{taskId}")
    public String saveTaskForm(@PathVariable("taskId") String taskId,HttpSession session,HttpServletRequest request) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}

    	Map formProperties = PageData(request);
        
        try {
            identityService.setAuthenticatedUserId(userId);
            formService.submitTaskFormData(taskId, formProperties);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }

        return "redirect:/time/list";
    }

    @RequestMapping(value = "/hlist")
    public String historylist(Model model,HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	    	
    	List<Map> hlist = new ArrayList<Map>();
    	List historylist = historyService.createHistoricProcessInstanceQuery()
    			.processDefinitionKey("reimbursement-10")
                .startedBy(userId).list();

    	for (int i=0;i<historylist.size();i++){
    		Map<String, Object> map = new HashMap<String, Object>();
    		HistoricProcessInstanceEntity hpe = (HistoricProcessInstanceEntity) historylist.get(i);
    		
    		map.put("id", hpe.getId());
    		map.put("startUserId", hpe.getStartUserId());
    		map.put("processInstanceId", hpe.getProcessInstanceId());
    		map.put("endTime", hpe.getEndTime());
    		map.put("startTime", hpe.getStartTime());
    		if (hpe.getEndTime() == null){
    			List<Task> taskList =  taskService.createTaskQuery().processInstanceId(hpe.getProcessInstanceId()).active().list();
    			String taskName = "";
    			for (int j=0;j<taskList.size();j++){
    				if (taskList.get(j) != null){
    					taskName = taskName == "" ? taskList.get(j).getName() : taskName + "," + taskList.get(j).getName(); 
    				}
    			}
    			if (taskName != ""){
    				map.put("name", taskName);
    			}
    		}else{
    			map.put("name", "已完成");
    		}
    		hlist.add(map);
    	}
    	
    	//获得当前用户的任务
    	model.addAttribute("list", hlist);
    	
    	return "reimbursement_hlist";
    }
    
    @RequestMapping(value = "/hview/{pId}")
    public String historyView(@PathVariable("pId") String pId,Model model,HttpSession session) {
    	String userId = session.getAttribute("userId") == null ? null : session.getAttribute("userId").toString();
    	if (userId == null){
    		return "redirect:/login/";
    	}
    	
    	List<HistoricDetail> details = historyService
    		    .createHistoricDetailQuery()
    		    .processInstanceId(pId)
    		    .orderByTime().asc()
    		    .list();
    	
    	model.addAttribute("list", details);
    	return "reimbursement_hview";
    }
    
    public Map PageData(HttpServletRequest request){
		Map properties = request.getParameterMap();
		Map returnMap = new HashMap(); 
		Iterator entries = properties.entrySet().iterator(); 
		Map.Entry entry; 
		String name = "";  
		String value = "";  
		while (entries.hasNext()) {
			entry = (Map.Entry) entries.next(); 
			name = (String) entry.getKey(); 
			Object valueObj = entry.getValue(); 
			if(null == valueObj){ 
				value = ""; 
			}else if(valueObj instanceof String[]){ 
				String[] values = (String[])valueObj;
				for(int i=0;i<values.length;i++){ 
					 value = values[i] + ",";
				}
				value = value.substring(0, value.length()-1); 
			}else{
				value = valueObj.toString(); 
			}
			returnMap.put(name, value); 
		}
		return returnMap;
	}
	
}

其中主要添加了一个接收事件触发的action,用户通过浏览器发起触发动作

for (int j=0;j<executions.size();j++){
	Execution execution = executions.get(j);
	if (execution != null){
		// 接收信号处理
		runtimeService.signalEventReceived("alert", execution.getId());
	}
}

另外还需要注意一个地方,就是打开异步任务开关,否则一分钟之后是不会触发定时任务的。

logging.level.org.activiti.engine=trace
spring.activiti.async-executor-enabled=true
spring.activiti.async-executor-activate=true

通过http://localhost:8080/time/add创建事件

springboot 可以指定网卡吗_springboot 可以指定网卡吗_02


保存之后在列表页面,此时是看不到任何任务的

springboot 可以指定网卡吗_java_03


等待一分钟之后,刷新页面,就可以看到任务了

springboot 可以指定网卡吗_springboot 可以指定网卡吗_04


此时的当前节点为部门领导审批。

再次http://localhost:8080/time/add创建一个任务,创建完成之后立即调用http://localhost:8080/time/receive请求。可以看到此时的任务很快就出现了,当前节点为财务部门审批

springboot 可以指定网卡吗_java_05


从以上的示例中我们可以看出事件网关的触发都是基于事件的,如果事件尚未发生,那么对应的流程不会继续的。