Activiti——流程任务详解(一)

Activiti6---获取节点信息 文章目录1. 说明2. 获取上一节点的方式3. 获取下一节点的方式 1. 说明 在应用中可能需要获取当前节点的上一个节点的信息,或者下一个节点的信息。 2. 获取上一节点的方式 如下能够获取到上一个节点的key,可以用来进行回退等功能实现。 /** * 根据流程实例id获取上一个节点的信息 */ @Test public void queryUpOneNode(){ Task task = taskService.createTaskQuery() 阅读详情

Activiti流程任务

任务是流程的核心元素之一,任务表示在流程中需要完成的工作。BPMN2.0中定义了多种任务,每种任务都有不同的属性,完成不同的工作。

1、BPMN2.0任务

BPMN2.0中定义了多种不同的任务,每种任务都有其特定的行为。BPMN2.0中定义的任务有Service Task、Send Task、Receive Task、User Task、Manual Task、Business Rule Task和Script Task。Activiti支持BPMN2.0中定义的大部分任务,并且对这些任务进行了相应的扩
展,例如Service Task在Activiti中可以体现为Java Service Task、Web Service Task等。

1.1、任务的继承

BPMN2.0为任务在流程文件中的定义提供了规范,遵守BPMN2.0规范的流程引擎都需要按照其提供的XML约束来定义流程,也可以根据流程引擎自身的需要添加额外的XML元素或者属性。BPMN2.0在定义流程文件的XML约束时,根据不同流程元素的特点,定义了整套流程元素的继承机制,关于任务的继承关系如图所示。
在这里插入图片描述

流程文件中全部的XML元素均直接或者间接继承于BaseElement,其中FlowElement下有两种子元素:FlowNode和SequenceFlow,即流程节点和顺序流,而FlowNode下有三类子元素:Activity(行为)、Event(事件)和Gateway(网关)。Activity表示流程中行为流程节点,流程中表示行为的元素有三类:SubProcess(嵌入子流程)、CallActivity(调用子流程)和Task(任务)。

1.2、XML约束

对于流程文件中的每个XML元素,BPMN2.0均提供了XML约束,任务元素的ML约束如代码所示。

<xsd:element name="baseElement" type="tBaseElement"/>
<xsd:complexType name="tBaseElement" abstract="true">
	<xsd:sequence>
		<xsd:element ref="documentation" minOccurs="0" maxOccurs="unbounded"/>
		<xsd:element ref="extensionElements" minOccurs="0" maxOccurs="1" /> 
	</xsd:sequence>
	<xsd:attribute name="id" type="xsd:ID" use="optional"/>
	<xsd:anyAttribute namespace="##other" processContents="lax"/>
</xsd:complexType>

<xsd:element name="flowElement" type="tFlowElement"/>
<xsd:complexType name="tFlowElement" abstract="true">
	<xsd:complexContent>
		<xsd:extension base="tBaseElement">
			<xsd:sequence>
				<xsd:element ref="auditing" minOccurs="0" maxOccurs="1"/>
				<xsd:element ref="monitoring" minOccurs="0" maxOccurs="1"/>
				<xsd:element name="categoryValueRef" type="xsd:QName" minOccurs="0" maxOccurs="unbounded"/>
			</xsd:sequence>
			<xsd:attribute name="name" type="xsd:string"/>
		</xsd:extension>
	</xsd:complexContent>
</xsd:complexType>

...

1.3、任务的类型

BPMN2.0有以下类型的任务。

  • Service Task:服务任务可以用于调用Web Service或者自动执行程序,Activiti中的Java Service Task、Web Service Task、Shell Task为BPMN2.0中定义的Service Task,对应的XML元素为serviceTask。
  • Send Task:发送任务表示处理向外部的流程参与人发送消息的工作,根据这个定义,Activiti中的Email Task属于这种任务,但是Activiti的官方文档却使用serviceTask元
    素来配置,而笔者在查看Activiti的源代码时发现,Activiti的这两种任务,既可以使用serviceTask元素进行配置,也可以使用sendTask元素进行配置,该任务对应的XML元素为sendTask。
  • Receive Task:接收任务是一种等待外部流程参与者发送消息的任务,换言之,当流程到达该任务时,需要外界告诉该任务接收到消息,它才会继续执行。对于该类任务,目前Activiti只对Java进行了实现,因此Activiti中只有Java Receive Task,Receive Task对应的XML元素为receiveTask。
  • User Task:用户任务是典型的流程元素之一,它表示需要有人参与的任务,对应Activiti中的User Task任务,XML元素为userTask。
  • Manual Task:手动任务并不需要任务的流程引擎或者应用的驱动,它会自动执行,在工作流中,它表示一种工作己经完成,工作流引擎不需要关心它是如何完成的。该任务对应的XML元素为manualTasl。
  • Business Rule Task:业务规则任务,主要用于向规则引擎发送请求参数,让其按照既定的业务规则进行运算并返回结果,当前Activiti只对JBoss的Drools规则引擎提供支
    持,对应的XML元素为businessRuleTask。
  • Script Task:脚本任务用于执行定义好的脚本程序,流程到达该任务后,这些脚本程序被执行,执行完成后任务结束,对应XML元素为scriptTask。

2、用户任务

一般的业务流程大多都会有人的参与,因此用户任务是最常用的任务,当流程到达用户任务时,用户任务会被分配到特定用户或者用户组。
在这里插入图片描述

在流程文件中,可以使用userTask元素定义一个用户任务:

<process id="process1" name="process1">
	<userTask id="usertask1">
		<documentation>task doc</documentation>
	</userTask>
	<startEvent id="startevent1" name="Start"></startEvent>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

在代码中定义了一个id为“usertask1”的用户任务,在userTask元素下定义了documentation子元素,该子元素是BaseElement定义的子元素,因此流程文件中的全部元素(除根元素外)均可以使用该子元素来配置描述信息。为userTask配置了描述信息,当流程启动并到达这个用户任务时,会将这里所配置的任务描述信息写入任务数据表
(ACT_RU_TASK)的DESCRIPTION字段中。如果需要在代码中获取这些信息,可以使用task的getDescription方法。

2.1、分配任务候选人

任务的候选人是指有权限对该任务进行操作的潜在用户群体,这个用户群体有权限处理(处理、完成)该任务。设置这种权限可以使用TaskService的addCandidateUser方法或者
addCandidateGroup方法(见8.2节),也可以通过XML配置的方式为任务分配候选人。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Task1">
		<potentialOwner>
			<resourceAssignmentExpression>
				<formalExpression>user(angus), group(management), boss
				</formalExpression>
			</resourceAssignmentExpression>
		</potentialOwner>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

用户可以作为多种角色被分配到流程活动中,BPMN2.0提供了humanPerformer和potentialOwner元素来实现角色的分配,代码使用了potentialOwner元素,该元素继承于resourceRole,resourceRole可以作为子元素被配置在Activity元素下,而Task就是Activity的子元素,那么就可以使用potentialOwner。

在formalExpression中,定义了用户“anugs”和用户组“management’”、“boss”为该任务的候选人,该配置的效果等同于在流程运行时使用TaskService的
addCandidateGroup方法和addCandidateUser方法,如果需要指定某个用户为该任务的候选人,则需要使用user(userId)这样的表达式,用户组的话,可以使用group(groupld)来指定。如果不使用user或者group而直接使用字符串,则会被直接视作用户组的ID,效果等同于
group(groupId)。

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/Candidate.bpmn").deploy();
// 启动流程
runtimeService.startProcessInstanceByKey("process1");
// 根据用户组查询任务
List<Task> tasks = taskService.createTaskQuery().taskCandidateGroup("boss").list();
System.out.println("分配到boss用户组下的任务数量:" + tasks.size());
// 根据用户查询任务
tasks = taskService.createTaskQuery().taskCandidateUser("angus").list();
System.out.println("用户angus下的任务数量为:" + tasks.size());
分配到boss用户组下的任务数量:1
用户angus下的任务数量为:1

2.2、分配任务代理人

可以为一个任务分配多个候选人,而一个任务只允许有一个代理人。可以使用TaskService的setAssignee方法设置任务的代理人,设置了任务代理人后,ACT_RU_TASK表的
ASSIGNEE字段会被设置为相应的值。除了使用setAssignee方法外,还可以使用XML配置的方式分配任务代理人。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Task 1">
		<humanPerformer>
			<resourceAssignmentExpression>
				<formalExpression>user1</formalExpression>
			</resourceAssignmentExpression>
		</humanPerformer>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

2.3、权限分配扩展

可以使用Activiti的扩展属性来实现这个功能。BPMN2.0规范允许各个流程引擎对规范进行扩展,可以为规范中定义的流程元素添加个性化的属性,前提是不能与BPMN
2.0规范相违背。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Assignee" activiti:assignee="user1"></userTask>
	<userTask id="usertask2" name="Candidate User"
		activiti:candidateUsers="user1, user2"></userTask>
	<userTask id="usertask3" name="Candidate Group"
		activiti:candidateGroups="group1,group2"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="usertask2"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask2"
		targetRef="usertask3"></sequenceFlow>
	<sequenceFlow id="flow4" name="" sourceRef="usertask3"
		targetRef="endevent1"></sequenceFlow>
</process>

代码中使用activiti:assignee属性分配任务代理人,使用activiti:candidateUsers属性来分配任务候选人,使用activiti::candidateGroups来分配任务的候选用户组。

2.4、使用任务监听器进行权限分配

除了可以使用BPMN2.0的ML元素和Activiti的扩展属性来分配任务候选人和任务代理人外,还可以编写自定义的任务监听器,在监听器的实现中使用编码方式进行权限分配。在般的应用系统中,用户组和用户均有可能发生变化,将用户和用户组写死到流程文件中显然是不合适的,因此可以使用任务监听器进行动态权限分配。

public class UserTaskListener implements TaskListener {
    public void notify(DelegateTask delegateTask) {
        System.out.println("使用任务监听器设置任务权限");
        delegateTask.setAssignee("user1");
        delegateTask.addCandidateGroup("group1");
        delegateTask.addCandidateUser("user1");
    }
}
<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<userTask id="usertask1" name="Assignee">
		<extensionElements>
			<activiti:taskListener event="create"
				class="pers.zhang.listener.UserTaskListener"></activiti:taskListener>
		</extensionElements>
	</userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/TaskListener.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
// 进行任务查询
List<Task> tasks = taskService.createTaskQuery().taskAssignee("user1").list();
System.out.println(tasks.size());
使用任务监听器设置任务权限
1

2.5、使用JUEL分配权限

Activiti默认对JUEL表达式提供支持,因此在进行任务权限分配时,也可以使用JUEL表达式来指定。使用JUEL可以直接调用自定义JavaBean里面的方法,例如可以使用
${object..method()}或者${object.field}来调用方法或者获取属性值,但是前提是该对象需要被设置到流程参数中。

<process id="process1" name="process1" isExecutable="true">
  <startEvent id="startevent1" name="Start"></startEvent>
  <userTask id="usertask2" name="Task 1" activiti:assignee="${authService.getUserAssignee()}"></userTask>
  <userTask id="usertask3" name="Task 2" activiti:candidateUsers="${authService.getCandidateUsers()}"></userTask>
  <userTask id="usertask4" name="Task 3" activiti:candidateGroups="${authService.getCandidateGroups()}"></userTask>
  <userTask id="usertask5" name="Task 4" activiti:assignee="${authService.lastUser}"></userTask>
  <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>
  <sequenceFlow id="flow2" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
  <sequenceFlow id="flow3" sourceRef="usertask3" targetRef="usertask4"></sequenceFlow>
  <endEvent id="endevent1" name="End"></endEvent>
  <sequenceFlow id="flow4" sourceRef="usertask4" targetRef="usertask5"></sequenceFlow>
  <sequenceFlow id="flow5" sourceRef="usertask5" targetRef="endevent1"></sequenceFlow>
</process>
public class AuthService implements Serializable {
    private String lastUser = "angus";

    public String getLastUser() {
        return this.lastUser;
    }

    public AuthService() {
        System.out.println("create AuthService");
    }

    //使用方法为任务指定代理人
    public String getUserAssignee() {
        return "crazyit";
    }

    //使用方法为任务指定候选人
    public List<String> getCandidateUsers() {
        List<String> result = new ArrayList<String>();
        result.add("user1");
        result.add("user2");
        return result;
    }

    //使用方法为任务指定候选用户组
    public List<String> getCandidateGroups() {
        List<String> result = new ArrayList<String>();
        result.add("group1");
        result.add("group2");
        return result;
    }
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
TaskService taskService = engine.getTaskService();
// 部署流程文件
repositoryService.createDeployment().addClasspathResource("demo12/JUELAuth.bpmn").deploy();
Map<String, Object> vars = new HashMap<String, Object>();
vars.put("authService", new AuthService());
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
// 查询第一个任务
Task task = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).singleResult();
System.out.println("第一个任务代理人:" + task.getAssignee());
//完成第一个任务
taskService.complete(task.getId());
// 查询第二个任务
task = taskService.createTaskQuery().processInstanceId(pi.getProcessInstanceId()).singleResult();
// 查询任务与用户的关联
List<IdentityLink> links = taskService.getIdentityLinksForTask(task.getId());
System.out.println("第二个任务的候选用户:");//结果2
for (IdentityLink link : links) {
    System.out.println("    " + link.getUserId());
}
//完成第二个任务
taskService.complete(task.getId());
// 查询第三个任务
task = taskService.createTaskQuery().singleResult();
links = taskService.getIdentityLinksForTask(task.getId());
System.out.println("第三个任务的候选用户组:");//结果2
for (IdentityLink link : links) {
    System.out.println("    " + link.getGroupId());
}
// 完成第三个任务
taskService.complete(task.getId());
// 查找第四个任务
task = taskService.createTaskQuery().singleResult();
System.out.println("第四个用户的代理人:" + task.getAssignee())

3、脚本任务

脚本任务由流程引擎执行,在定义脚本任务时,需要为流程引擎提供它可以解析并执行的脚本语言,流程到达脚本任务时,流程引擎会执行定义好的脚本,任务将会在脚本执行后完成。
使用以下配置片断可定义一个Script Task:

<scriptTask id="scripttaskl"name="Script Task"scriptFormat="juel">
<script></script>
</scriptTask>

定义一个脚本任务,需要指定脚本的格式,如果不指定,Activiti会认为提供的是UEL表达式。JUEL是统一表达式语言(Unified Expression Language)的Java实现。Activiti的流程文件中许多地方都可以使用JUEL表达式,例如User Task、Service Task、Script Task和网关等。

3.1、脚本任务

脚本任务支持多种脚本语言,前提是提供的语言与JSR-223规范兼容。随着PHP、Ruby、JavaScript等脚本语言的广泛使用,为了能在Java中使用这些脚本语言,从Java6开始,Java提供了JSR-223规范,该规范定义了Java对这些脚本语言进行解析与执行的标准,从而为Java执行这些脚本语言提供了可能。在Java6中,集成了Rhino作为默认的JavaScript引擎,而在Java8中将Rhino替换为Oracle Nashorn。

//创建脚本引擎管理对象
ScriptEngineManager manager = new ScriptEngineManager();
//获取JavaScript的脚本引擎
ScriptEngine engine = manager.getEngineByName("javascript");
//执行一段脚本
engine.eval("for (var i = 0; i < 5; i++) {print(i);}");

3.2、JavaScript脚本

Java默认支持执行JavaScript脚本,因此可以在Script Task中直接将JavaScript作为任务的脚本。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task"
		scriptFormat="javascript">
		<script><![CDATA[
			var myVar = "angus";
			execution.setVariable("user", myVar);	
		]]></script>
	</scriptTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<userTask id="usertask1" name="End Task"></userTask>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/JavaScriptTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");
// 获取在JavaScript中设置的参数
String user = (String)runtimeService.getVariable(pi.getId(), "user");
System.out.println("获取用JavaScript设置的参数:" + user);
获取用JavaScript设置的参数:angus

3.3、Groovy脚本

Groovy是基于JVM的一种动态语言,它结合了SmallTalk、Ruby等语言的特性,使用Groovy可以很好地与Java进行结合。Groovy官方提供的groovy-jsr223-2.4.8包中已经包含了JSR-223的实现,因此可以在脚本任务中指定使用Groovy脚本。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task" scriptFormat="groovy">
		<script>
			org.crazyit.activiti.GroovyScriptTask.print(execution);
		</script>
	</scriptTask>
	<userTask id="usertask1" name="End Task"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = engine.getRepositoryService();
RuntimeService runtimeService = engine.getRuntimeService();
repositoryService.createDeployment().addClasspathResource("demo12/GroovyScriptTask.bpmn").deploy();
// 启动流程
ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1");

3.4、设置返回值

在任务脚本中,可以得到execution变量,并且可以使用execution的方法,代码中就使用了execution的setVariable方法设置流程参数,除此之外,直接在脚本中定义的变量,也会被设置为流程参数,例如以下的JavaScript脚本:

<script>
	var user1 = "a";
	var user2 = "b";
</script>

那么在获取参数时,可以根据“user1”来获取参数值“a”,也可以根据“user2”来获取参数值“b”,而并不需要使用execution.setVariable方法。对于Groovy脚本,使用以下代码可以设置流程参数:

<script>
	user1 = "a";
	user2 = "b";
</script>

同样,也可以根据“user1”和“user2”来获取相应的参数值,但是如果使用以下Groovy脚本,就不能设置流程参数:

<script>
	def user1 = "a";
	def user2 = "b";
</script>

如果在脚本中想将某些值作为参数设置到流程中,并且想显式指定变量名称,则可以为scriptTask元素加上activiti:resultVariable属性,属性值为参数的变量名称。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task"
		scriptFormat="groovy" activiti:resultVariable="user">
		<script>
			execution.id
		</script>
	</scriptTask>
	<userTask id="usertask1" name="End Task"></userTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="usertask1"></sequenceFlow>
	<sequenceFlow id="flow3" name="" sourceRef="usertask1"
		targetRef="endevent1"></sequenceFlow>
</process>

3.5、JUEL脚本

除了可以使用支持JSR223规范的脚本语言外,默认情况下,还可以使用JUEL表达式,使用JUEL表达式可以进行值的输出和Java Bean的调用。在脚本任务中,同样支持使用UEL表达式。

<process id="process1" name="process1">
	<startEvent id="startevent1" name="Start"></startEvent>
	<scriptTask id="scripttask1" name="Script Task" scriptFormat="juel">
		<script>
			${myBean.print(execution)}
		</script>
	</scriptTask>
	<endEvent id="endevent1" name="End"></endEvent>
	<sequenceFlow id="flow1" name="" sourceRef="startevent1"
		targetRef="scripttask1"></sequenceFlow>
	<sequenceFlow id="flow2" name="" sourceRef="scripttask1"
		targetRef="endevent1"></sequenceFlow>
</process>
public class MyBean implements Serializable {
    
    public void print(Execution exe) {
        System.out.println("执行Java Bean的方法,流程ID为:" + exe.getId());
    }
}
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
        RepositoryService repositoryService = engine.getRepositoryService();
        RuntimeService runtimeService = engine.getRuntimeService();
        repositoryService.createDeployment().addClasspathResource("demo12/JUELScript.bpmn").deploy();
        Map<String, Object> vars = new HashMap<String, Object>();
        vars.put("myBean", new MyBean());
        // 启动流程
        ProcessInstance pi = runtimeService.startProcessInstanceByKey("process1", vars);
执行Java Bean的方法,流程ID为:15009
activiti节点撤回 activiti节点撤回 最近项目的需求是对已审批的节点进行撤回操作,核心的思路是: 校验任务和流程信息 处理已经完成审批的节点信息,做删除操作 处理下一节点未审批信息,做删除操作 public Boolean processWithdraw(ProcessWithdrawParam processWithdrawParam) { String taskId = processWithdrawParam.getTaskId(); String userId = p 阅读详情

相关推荐

2023最新版本Activiti7系列-流程中的任务

Activiti7中各种任务的详解

波波烤鸭的博客 1489

activiti中的服务任务(ServiceTask)

服务任务不同于用户任务(需人工处理),服务任务一般是一段可自动执行的任务而无需人工干预。 例如:当用户完成"任务1"后,想自动执行一个跑批任务处理后台数据库表的数据,那么只需要在"任务1"节点后放置一个ServiceTask(需要指定该服务任务所要执行的java类或spring容器的bean) ,当服务任务执行完成后,再继续执行任务2 。 服务任务的配置 例1: <serviceTask id="servicetask1" name="服务任务" activiti:delegateExpress

jasnet_u的博客 1万+

Activiti7 多种任务类型【十八】

Service如果没有指定名字,默认是类名的首字母小写,即myTaskService。} else {} } }} else {} } }} else {} } }} else {} } }} else {} } }} else {} } }} else {} } }} else {} } }Script Format:脚本类型,groovyScript:脚本代码。

2012年开始工作,全栈开发老兵,目前已是一个老师,分享这么多年的心得体会 1004

Activiti——流程任务详解(二)

目录Activiti流程任务4、服务任务4.1、Java 服务任务4.2、实现JavaDelegate4.3、使用普通JavaBean4.4、在Activiti中调用Web Service4.5、import元素4.6、itemDefinition和message元素4.7、interface与operation元素4.8、设置Web Service参数与返回值4.9、发布Web Service4.10、使用Web Sercice Task4.11、JavaDelegate属性注入4.12、在JavaDel

吴声子夜歌的博客 2268

BPMN2.0 任务-服务任务

默认情况下,异步作业是排他的,也就是说流程实例会被锁定,以保证流程实例中的其他活动不会影响到触发器的逻辑。这是最不线程安全的模式,但可以保证历史版本兼容性,也可以在委托表达式只在一个任务中使用的时候(因此不会产生并发竞争条件),安全使用。这种情况下,使用字段注入时,没有线程安全性问题:每次表达式解析时,都会注入新实例的字段。有的时候,需要在Java服务任务中使用Flowable服务(例如调用活动(call activity)不满足需要的场景下,使用RuntimeService启动流程实例)。

走在悬崖的边上 843

FPS游戏自动枪械识别+压枪(以PUBG为例)

使用Python3.9作为开发环境,实现一个通用的FPS游戏自动检测枪械配件+压枪宏的软件开发思路

weixin_37827742的博客 3万+

activiti5之学习之路,流程实例,任务,执行对象。说明都写在代码里,一看就明白

package com.ljw.processInstance; import java.util.List; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngines; import org.activiti.engine.history.HistoricProcessInstan...

黑科技的专栏 383

【Pytorch】DCGAN实战(三):二次元动漫头像生成

文章目录1.实现效果2.环境配置2.1Python2.2Pytorch、CUDA2.3Python IDE3.具体实现3.1数据预处理(data.py)(1)导入包(2)定义数据类3.2模型Generator,Discriminator,权重初始化(model.py)(1)导入包(2)Generator(3)Discriminator(4)权重初始化3.3网络训练(net.py)(1)导入包(2)创建类3.4 主函数(main.py)(1)导入文件(2)定义超参数(3)实例化(4)进行训练4.训练过程4.1

qq_44031210的博客 4918

Spting Boot 整合 Activiti 7 出现流程变量从上一任务复制到下一任务问题解决

application.yml spring: activiti: # 自动建表 database-schema-update: true history-level: full db-history-used: true copy-variables-to-local-for-tasks: false datasource: url: jdbc:mysql:///activiti?characterEncoding=utf-8&serve

u010637366的博客 843

ROS入门必学导航算法——Navigation

该平台集成了多款无人车底盘,包括履带式、四轮差速、阿克曼、麦克纳姆轮底盘等,以满足不同形式和配置的需求,并搭载了RTK定位系统、双目相机、深度相机和激光雷达等多种传感器,以满足开发者的科研需求。amcl节点接收里程计数据(通过"odom"话题)和激光雷达数据(通常通过"scan"话题),结合已知的地图,实时地估计出机器人在该地图上的位置。在ROS中,这是通过"tf库"变换实现的,通过将传感器数据转换到共同的参考系中,系统可以更容易地集成来自不同传感器的数据,并确保它们在相同的空间和时间范围内可用。

AMOVLAB(阿木实验室) 2909

InSAR_ISCE软件数据处理流程之:利用哨兵数据获取2015年尼泊尔地震同震形变场

ISCE软件数据处理流程之:利用哨兵数据获取2015年尼泊尔地震同震形变场 ISCE软件做干涉只需要将数据准备好,并配置好insarApp.xml文件即可进行。 一、数据准备 1、SAR数据获取 本利中使用的数据为欧空局提供的sentinel-1A/B数据,可从阿拉斯加数据服务器上下载,具体下载方法可参考: 哨兵数据下载方法. 2、哨兵卫星轨道文件下载 哨兵数据处理除了需要SAR影像外,还需提供轨道参数文件,可从https://qc.sentinel1.eo.esa.int/aux_poeorb/下载。下载

weixin_42128764的博客 1万+

轻松实现activiti会签(多人处理完成才进入下一节点)

activiti加签 提示:此为在bpmn流程图中设置加签前言一、bpmn设置二、代码实现 提示:此为在bpmn流程图中设置加签 前言 加签就是多人处理完成过后才进入下一节点,下一级节点处理人仅处理一次任务 一、bpmn设置 示例:${nrOfCompletedInstances/nrOfInstances==1} ==1表示所有任务实例完成才可以进入下一个节点 (==0.75则需要完成3/4) 以此类推 二、代码实现 @RequestMapping("confirmNodePr

HLiMr的博客 5150

AFSim插件开发实战:从环境搭建到功能扩展

本文详细介绍了AFSim插件开发的完整流程,从环境搭建到功能扩展,涵盖了SDK配置、插件创建、核心代码解析、功能扩展实战、调试优化以及高级开发技巧。通过实战案例和实用技巧,帮助开发者快速掌握AFSim插件开发,提升仿真系统的扩展性和灵活性。

weixin_29309475的博客 578

BPM引擎Activiti6.0任务撤回实现方法

当前使用的BPM引擎为Activiti6.0,客户需求是流程发起人能将整个流程撤销,对于某个流程节点,办理人可以撤回已经办理的任务,同时前提是该任务节点的下个节点未被办理。 1、流程撤销 首先说下发起人对整个流程的撤销,直接删除流程,传入流程实例ID,结束一个流程。执行此方法后,流程实例的当前任务act_ru_task会被删除,流程历史act_hi_taskinst不会被删除,并且流程历史的状态置为finished完成。 runtimeService.deleteProcessInstance(in

wangpf2011的博客 4245

TCGA之GDC-client工具下载安装与使用

文章主要是对GDC-client工具下载TCGA数据库数据整个过程的一个记录 1.下载GDC-client工具 GDC-client工具网址:GDC Data Transfer Tool | NCI Genomic Data Commons (cancer.gov) 我这里下的是上图中红圈中的版本, 2.解压安装 从网上了解的是不能解压到带中文的路径里,解压后是一个.exe文件,为了能直接在cmd命令行下使用,将其加入系统环境: 点击新建之后,输入将文件解压到的路径,然后...

better_strong的博客 1万+

HAMi 核心模块与架构设计

HAMi 的架构设计是围绕 Kubernetes 生态系统构建的,通过扩展 Kubernetes 的调度能力和设备管理能力,为用户提供了高效、灵活的异构设备虚拟化和管理解决方案。

北斗云的博客 2552

Activiti之单用户、多用户任务分配

我们在开发的时候,有一种情况是这样的, 我们有一个任务,可以让多个用户中的任何一个人办理即可,比如某个审批任务, 张三,李四,王五他们中的任何一人办理下都行,这时候,我们用到多用户任务分配。 方式一、直接流程图配置中写死 上面是某个人审批写死。 上面是组审批写死。这里我们分配2个人【3XXA、5KLM】 ,中间用逗号隔开。 实例代码为: public class AssignTest { /** * 获取默认流程引擎实例,会自动读取activiti.cf..

kay523393的博客 2891

从 VL02N 拣配到 ABAP 自动化,读懂 SD_DELIVERY_UPDATE_PICKING 的位置和风险

文章摘要:SAP SD模块中,SD_DELIVERY_UPDATE_PICKING函数模块用于处理出库交货单的拣配确认,更新交货项目的拣配数量。该函数适用于未启用WM/EWM的传统SD流程,能确保拣配状态与标准交货处理逻辑同步,比直接修改数据库更安全。但在S/4HANA Cloud等新环境中,应优先使用API_OUTBOUND_DELIVERY_SRV等公开发布接口。使用该函数时需注意参数完整性和按交货单整体处理的原则,避免逐项提交导致的数据不一致问题。(149字)

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 247

【activiti审批手动回退上一任务,处理垃圾数据,不是常规回退】

【代码】【activiti审批手动回退上一任务,处理垃圾数据,不是常规回退】

weixin_43932964的博客 792

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Activiti6.0获取下一节点任务的心路历程

在我的开发任务中,我被分配了一个像下一个节点审批人发送短信的任务,这个任务看起来非常的简单,但在开发过程中遇到了许多的坑,在这里进行记录。 首先,就是获取下一节点的任务信息,这里说简单也简单,说难也难,初期,我查阅了大量的资料,那些资料中都是在代码层面获取下一节点任务信息,我尝试了一下,非常的复杂,后来,我仔细研究了activiti流程变化与数据库变化之间的联系,发现act_ru_task表的执行特性,它会在当前节点任务完成后自动加载下一节点任务,根据这一点,我们就能能够获取到下一节点的相关信息。 /*

Mr 敦(A.Dun)Java历险记 3220

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

activiti流程回退与流程结束

【工作流Activiti7】3、Activiti7 回退与会签 【工作流Activiti7】4、Activiti7 结束/终止流程Activiti-跳转到指定节点、回退ativiti6.0 流程节点自由跳转实现、拒绝/不同意/返回上一节点、流程撤回、跳转、回退等操作(通用实现,亲测可用) - 掘金 activiti6.0源码剖析之节点任意跳转 -简书Activiti回退与跳转节点Activiti7 工作流非原流程终止2020-10-21Activiti会签以及会签驳回activiti学习(二十二)——常规任

pscool的博客 5218

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Activit的心路历程:Activiti6.0获取当前节点的上一节点【可能存在多个】的nodeId

在我的开发任务中,突然给我提出了一个待办任务需要获取当前任务节点上以任务节点的表单信息,刚开始搞得我有点措手不及,后来仔细是靠后,灵感一下,直接操作流程的bpmn信息就可以获取到节点信息嘛,顺着这个思路,我整理出了自己的思路: (1)将节点大体分为两类,一类是网关节点,另外一类就是用户任务节点,使用List集合,将网关与用户任务进行分类 (2)获取上一节点,我们就需要从bpmn的连线信息入手,固定连线的targtaetRef,辨别sourceRef节点的类型,当是用户任务时,放进 List frontNod

Mr 敦(A.Dun)Java历险记 3513

Activiti任务提交之前预知下一步节点(人工任务)

public void getCurrentNextUserTaskAssign(){ //流程定义Id String processDefId="process:1:7"; //当前流程节点Id,在任务表里面对应TASK_DEF_KEY_字段,可以根据taskId获取该字段数据 String flowElemetId = ...

u012736448的专栏 1507

activiti 选人的实现

activiti默认是不带有选人的功能的,它默认的是在调用complete 方法的时候自动根据下一个节点的 assignee属性或者candidate属性 设置下一节点的候选人或者 assginee。由于项目的原因我们需要实现在上一个节点提交的时候设置就要从几个候选审批人员中选择一个或者几个审批人员,下面的代码写了个Junit 的demo。 Java代码 packa...

weixin_33937778的博客 761

Activiti中使用TaskListener接口来分配个人任务

Activiti中TaskListener接口的使用

wyj180的博客 7449
上一篇: Activiti——历史数据和流程引擎管理HistoryService、ManagermentService API详解
下一篇: Activiti——流程任务详解(二)
吴声子夜歌
博客等级 码龄9年 2688粉丝 2273原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值