The use of workflow activiti plugin

1. Because I am using eclipse, I will introduce the method of installing activiti in eclipse, help->Install new software, as shown below:

click add

The following image will appear:

Enter the installation icon, click ok, then finish, and wait for the installation to complete.

2. Use

Create a project: Create a new MyProcess.bpmn file with the following code:

<?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.activiti.org/test">
  <process id="myProcess" name="My process" isExecutable="true">
    <startEvent id="startevent1" name="Start">
      <extensionElements>
        <activiti:executionListener event="start" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>
      </extensionElements>
    </startEvent>
    <userTask id="usertask1" name="申请开始任务">
      <extensionElements>
        <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernBegin"></activiti:taskListener>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow1" name="申请" sourceRef="startevent1" targetRef="usertask1">
      <extensionElements>
        <activiti:executionListener event="take" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>
      </extensionElements>
    </sequenceFlow>
    <userTask id="usertask2" name="任务开始结束">
      <extensionElements>
        <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernBegin"></activiti:taskListener>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2">
      <extensionElements>
        <activiti:executionListener event="take" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>
      </extensionElements>
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isTrue == "true"}]]></conditionExpression>
    </sequenceFlow>
    <endEvent id="endevent1" name="End">
      <extensionElements>
        <activiti:executionListener event="end" class="org.pan.activity.bpmnlistern.MyExecutionListern"></activiti:executionListener>
      </extensionElements>
    </endEvent>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask4"></sequenceFlow>
    <userTask id="usertask3" name="个人任务">
      <extensionElements>
        <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernOwern"></activiti:taskListener>
        <activiti:taskListener event="complete" class="org.pan.activity.bpmnlistern.MyTaskListernOwern"></activiti:taskListener>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow4" sourceRef="usertask1" targetRef="usertask3">
      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${isTrue == "false"}]]></conditionExpression>
    </sequenceFlow>
    <sequenceFlow id="flow5" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
    <userTask id="usertask4" name="分组任务">
      <extensionElements>
        <activiti:taskListener event="create" class="org.pan.activity.bpmnlistern.MyTaskListernGroup"></activiti:taskListener>
      </extensionElements>
    </userTask>
    <sequenceFlow id="flow6" sourceRef="usertask4" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="50.0" y="216.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="180.0" y="206.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="362.0" y="100.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="770.0" y="216.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="466.0" y="310.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4">
        <omgdc:Bounds height="55.0" width="105.0" x="580.0" y="100.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="85.0" y="233.0"></omgdi:waypoint>
        <omgdi:waypoint x="180.0" y="233.0"></omgdi:waypoint>
        <bpmndi:BPMNLabel>
          <omgdc:Bounds height="14.0" width="24.0" x="85.0" y="233.0"></omgdc:Bounds>
        </bpmndi:BPMNLabel>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="232.0" y="206.0"></omgdi:waypoint>
        <omgdi:waypoint x="414.0" y="155.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="467.0" y="127.0"></omgdi:waypoint>
        <omgdi:waypoint x="580.0" y="127.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="232.0" y="261.0"></omgdi:waypoint>
        <omgdi:waypoint x="518.0" y="310.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
        <omgdi:waypoint x="518.0" y="310.0"></omgdi:waypoint>
        <omgdi:waypoint x="787.0" y="251.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
        <omgdi:waypoint x="632.0" y="155.0"></omgdi:waypoint>
        <omgdi:waypoint x="787.0" y="216.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>

The activiti view is as follows:

The pom file needs to add the following packages:

        <dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-engine</artifactId>
			<version>5.21.0</version>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-spring</artifactId>
			<version>5.21.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-diagram-rest</artifactId>
			<version>5.21.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
			</exclusions>
		</dependency>
		<dependency>
			<groupId>org.activiti</groupId>
			<artifactId>activiti-modeler</artifactId>
			<version>5.21.0</version>
			<exclusions>
				<exclusion>
					<groupId>org.springframework</groupId>
					<artifactId>spring</artifactId>
				</exclusion>
			</exclusions>
		</dependency>

Activiti has two kinds of listeners, namely: ExecutionListern is mainly used for monitoring the start, end and connection of the process, there are three values: "start", "end", "take", where start and end are used for the whole process The start and end of , take is used for connection. TaskListern is mainly used for node monitoring. There are four events: "create", "assignment", "complete", "delete". When the flow goes to this node, the create event is triggered, and when it is delegated, the assignment event is triggered. When the event completes, the complete and delete events are fired at the same time because the activity deletes the node information in the corresponding data table.

The four listener codes used in the project are as follows:

/**
 *@description		executionListern主要用于流程的开始、结束和连线的监听
 *					共有三个值:"start"、"end"、"take"。
 *					其中start和end用于整个流程的开始和结束,take用于连线
 *@auth panmingshuai
 *@time 2018年4月5日下午8:59:16
 * 
 */

public class MyExecutionListern implements ExecutionListener{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateExecution execution) throws Exception {
		//得到现在事件阶段的值,用"start".endsWith(eventName)来判断
		String eventName = execution.getEventName();
		if("start".endsWith(eventName)){
			System.out.println("-------------------流程开始-------------------");
		} else if("end".equals(eventName)){
			System.out.println("-------------------流程结束-------------------");
		}
		
		
		
	}
}
/**
 *@description 
 *@auth panmingshuai
 *@time 2018年4月5日下午11:18:24
 * 
 */

public class MyTaskListernBegin implements TaskListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateTask delegateTask) {
		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断
		String eventName = delegateTask.getEventName();
		if("create".equals(eventName)){
			System.out.println("-------------------分组任务开始---------------");
			
			//指定组任务审核人员
			delegateTask.addCandidateUser("ming1");
			delegateTask.addCandidateUser("ming2");
		} else if("complete".equals(eventName)){
			System.out.println("-------------------分组任务结束---------------");
		}
		
	}

}
/**
 *@description taskListern主要用于节点的监听
 *				共有四个事件:分别是:"create"、"assignment"、"complete"、"delete"。
 *				当流转到这个节点是触发create事件,当被委托是触发assignment事件,当事件完成时,
 *				因为activity会删除相应数据表中的节点信息所以会触发complete和delete事件
 *@auth panmingshuai
 *@time 2018年4月5日下午8:59:16
 * 
 */

public class MyTaskListernGroup implements TaskListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateTask delegateTask) {
		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断
		String eventName = delegateTask.getEventName();
		if("create".equals(eventName)){
			System.out.println("-------------------分组任务开始---------------");
			
			//指定组任务审核人员
			delegateTask.addCandidateUser("ming1");
			delegateTask.addCandidateUser("ming2");
		} else if("complete".equals(eventName)){
			System.out.println("-------------------分组任务结束---------------");
		}
		
		
	}

}
/**
 *@description 
 *@auth panmingshuai
 *@time 2018年4月5日下午9:44:16
 * 
 */

public class MyTaskListernOwern implements TaskListener {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public void notify(DelegateTask delegateTask) {
		//得到现在事件阶段的值,用"create".endsWith(eventName)来判断
		String eventName = delegateTask.getEventName();
		
		if("create".equals(eventName)){
			System.out.println("-------------------个人任务开始---------------");
			
			//添加个人任务
			delegateTask.setOwner("ming1");
		} else if("complete".equals(eventName)){
			System.out.println("-------------------个人任务结束---------------");
		}
		
		
		
	}

}

Next is the configuration of activiti, because activiti needs to operate data tables, so if you want to use activiti, you must configure the database connection pool and transaction management:

    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
        <property name="driverClass" value="${jdbc.driver}"/>
        <property name="jdbcUrl" value="${jdbc.url}"/>
        <property name="user" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxPoolSize" value="${jdbc.maxPoolSize}"/>
        <property name="minPoolSize" value="${jdbc.minPoolSize}"/>
        <property name="initialPoolSize" value="${jdbc.initialPoolSize}"/>
        <property name="acquireIncrement" value="${jdbc.acquireIncrement}"/>
        <property name="maxIdleTime" value="${jdbc.maxIdleTime}"/>
    </bean>

    <!-- 启用注解式事务管理 -->
	<tx:annotation-driven transaction-manager="transactionManager" />

    <!-- 加载activiti引擎 -->
	<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
		<property name="processEngineConfiguration" ref="processEngineConfiguration" />
	</bean>
	<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
		<property name="dataSource" ref="dataSource" />
		<property name="transactionManager" ref="transactionManager" />
		<property name="databaseSchemaUpdate" value="true" />
		<property name="jobExecutorActivate" value="false" />
	</bean>
	<!-- activiti的各种服务接口 -->
	<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService" />
	<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService" />
	<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService" />
	<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService" />

The role of the activiti service interface is as follows:

RepositoryService management process definition

RuntimeService performs management, including operations such as starting, advancing, and deleting process instances

TaskService task management

HistoryService history management (management of executed data)

When using it, you need to inject the corresponding interface:

Of course, you can use the various get methods of processEngine without using these interfaces, but it is not very convenient:

3. Specific business use:

3.1. First of all, if you want to use the workflow, you must first deploy the process:

// 部署流程,只要是符合BPMN2规范的XML文件,理论上都可以被ACTIVITI部署
		Deployment deployment = repositoryService.createDeployment().addClasspathResource("org/pan/activity/bpmn/MyProcess.bpmn").deploy();
		System.out.println("deployment: id: " + deployment.getId() + "----- name: " + deployment.getName());
		return "发布成功";

Note: When the project starts, activiti will automatically generate the data tables it needs in the database you connect to, all of which start with act_.

Generally, if you don't change the flow chart or the database, you only need to deploy it once.

Now suppose a person submits an application, how to give him an example of the process? as follows:

//开启流程时设置的变量是全局变量
		Map<String, Object> variables = new HashMap<>();
		variables.put("shuai", "haha");
		// 开启流程,myprocess是流程的ID,每个流程图都有自己专属的id,businessid代表每个具体的业务流程
		ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("myProcess", businessId, variables);
		Task activityTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey(processInstance.getActivityId()).singleResult();
		System.out.println("processInstance: id: " + processInstance.getId() + "----- activityTaskId: " + activityTask.getId());
		return "开启成功";

This opens an exclusive process instance for a certain business. It is worth noting that the id of processInstance.getId() is the id generated by activiti itself, and businessId is our own business id, but this does not need to be set, it depends on the project If necessary, we can have our own business application form, but we can also put the content of the application in variables and check it out when needed, so that we don't need to create our own application form.

When the process starts, the task needs to be processed, but who handles the task?

There is actually code in the above listener. It should be noted that when the creat event of the task is triggered, the handler is set, and the set handler can only handle this task. Of course, there are other ways to set the handler, but I think This way is best. In addition, delegateTask.addCandidateUser("ming1"); this is to set the group task handler. 

delegateTask.setOwner("ming1"); This is for setting personal tasks. The so-called group task means that everyone in the group can see the task, and the individual task means that only this person can see the task.

After the task handler is set, how can that person see his task?

// 个人任务查询
		List<Task> taskList = taskService.createTaskQuery().taskAssignee(userName).list();
		for(Task task : taskList){
			System.out.println("assignee: " + task.getAssignee() + "---- taskName:" + task.getName() + "---- taskId: " + task.getId());
		}
		return taskList.size() + "";
// 组任务查询
		List<Task> taskList = taskService.createTaskQuery().taskCandidateUser(userName).list();
		for(Task task : taskList){
			System.out.println("assignee: " + task.getAssignee() + "---- taskName:" + task.getName() + "---- taskId: " + task.getId());
		}
		return taskList.size() + "";

One thing to note is that when a group task is queried, anyone who is a member of the group will see all the group tasks, but how does the group task determine who handles the task? At this time, the task needs to be designated. For example, a team member said that the task belongs to him, then we have to assign the task to him, otherwise we don't know who did it. Specify as follows:

taskService.claim(taskId, userName);

Okay, the task has been checked, how should I deal with it:

String val = (String) taskService.getVariable(taskId, "isTrue");
		String shuai = (String) taskService.getVariable(taskId, "shuai");
		System.out.println(shuai);
		System.out.println(val);
		//这里设置的变量是局部变量,只对下一个节点有用
		Map<String, Object> variables = new HashMap<>();
		variables.put("isTrue", isTrue);
		taskService.complete(taskId, variables);
		return "任务:" + taskId + " 完成";

The getVariable method here is to obtain the parameters passed from the previous node. The taskService calls the complete method to complete the node. At this time, the complete and delete events of the node and the create event of the next node will be triggered. The variables in the complete method are the parameters passed to the next node. It should be noted that the variables parameters in the startProcessInstanceByKey method are global when starting a process instance, and you can adjust their values ​​at any node. One of its uses is: for example, if you want to limit the number of times an application is called back, you can use it.

Well, the task is completed, how do we see where this process has gone?

ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessId).singleResult();
		Task activityTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).taskDefinitionKey(processInstance.getActivityId()).singleResult();
		System.out.print("----- activityTaskName: " + activityTask.getName());
		System.out.println("----- isEnded:" + processInstance.isEnded());
		return "查询成功";

The activityTask is the task node where the current process is located.

So how do you check which nodes a task has gone through?

HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessId).singleResult();
		List<HistoricTaskInstance> taskInstances = historyService.createHistoricTaskInstanceQuery().processInstanceId(processInstance.getId()).orderByTaskCreateTime().asc().list();
		for(HistoricTaskInstance taskInstance : taskInstances){
			System.out.print("taskId:" + taskInstance.getId());
			System.out.print("---taskName:" + taskInstance.getName());
			System.out.print("---assignee:" + taskInstance.getAssignee());
			System.out.print("---startTime:" + taskInstance.getStartTime());
			System.out.print("---endTime:" + taskInstance.getEndTime());
			System.out.println("---duration:" + taskInstance.getDurationInMillis());
		}
		return "查询成功";

How to find out which tasks a person handles?

List<HistoricTaskInstance> taskInstances = historyService.createHistoricTaskInstanceQuery().taskAssignee(userName).list();
		for(HistoricTaskInstance taskInstance : taskInstances){
			System.out.print("taskId:" + taskInstance.getId());
			System.out.print("---taskName:" + taskInstance.getName());
			System.out.print("---assignee:" + taskInstance.getAssignee());
			System.out.print("---startTime:" + taskInstance.getStartTime());
			System.out.print("---endTime:" + taskInstance.getEndTime());
			System.out.println("---duration:" + taskInstance.getDurationInMillis());
		}

Basically, the functions of these processes are used in a project, basically satisfied, finished

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325440388&siteId=291194637