workflow,工作流,通过计算机对业务流程自动化执行管理。
Activiti
工作流引擎(一堆jar包API),业务系统访问activiti的接口,就可以方便操作流程相关的数据,这样就可以把工作流环境与业务系统环境集成在一起。
BPM/BPMN
BPM:Business Process Management,业务流程管理;
BPMN:Business Process Model And Notation,业务流程模型和符号。业务流程图文件后缀:.bpmn
工作表创建
activiti的流程数据是存储在数据库中的,因此需要先创建activiti工作所需要用到的表(25张表)。工作表的创建方式分为两种:默认配置方式和自定义配置方式。
默认方式:resource 目录下创建 activiti的配置文件 activiti.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--使用activiti默认的方式来创建mysql表:要求 在resources下创建activiti.cfg.xml文件
(默认方式下路径和文件名不能修改);下面的beanid固定为processEngineConfiguration-->
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--配置数据库连接参数-->
<property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql:///activiti?serverTimezone=UTC" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="003300" />
<!--activiti 在生成数据库表时的策略,true:如果表存在则直接使用,不存在则创建-->
<property name="databaseSchemaUpdate" value="true" />
</bean>
</beans>
自定义方式:resource目录(包含子目录)下创建 activiti的配置文件(自定义文件名) aciviti.mu.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/contex
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql:///activiti?serverTimezone=UTC" />
<property name="username" value="root"/>
<property name="password" value="089033"/>
<property name="maxIdle" value="3"/>
<property name="minIdle" value="1"/>
</bean>
<!--使用activiti自定义的方式来创建mysql表:要求 在resources下创建activiti.mu.xml文件;下面的beanid可自定义名称-->
<bean id="definedProcessEngine" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<!--配置数据库连接参数-->
<property name="dataSource" ref="dataSource"/>
<!--activiti 在生成数据库表时的策略,true:如果表存在则直接使用,不存在则创建-->
<property name="databaseSchemaUpdate" value="true" />
</bean>
</beans>
创建表的代码分别为:
/**
* 使用activiti默认的方式来创建mysql的25张表
*/
@Test
public void createDefaultTable(){
/**
* ProcessEngines.getDefaultProcessEngine() 会默认读取resources路径下的activiti.cfg.xml文件
* 创建ProcessEngine时就会创建mysql表
*/
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
}
/**
* 使用自定义的方式来创建mysql表
*/
@Test
public void createDefineTable(){
// 通过指定的配置文件(和指定id的bean)来创建activiti引擎配置ProcessEngineConfiguration,通过buildProcessEngine()创建流程引擎
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
}
这些生成的表名以act_开头,分别代表不同的存储用途:
ACT_RE_*: ’RE’表示repository。带此前缀的表包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
ACT_RU_*: ’RU’表示runtime。这是运行时(记住一定是运行时)的表存储着流程变量,用户任务,变量,等运行时的数据。Activiti只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。
ACT_ID_*: ’ID’表示identity。这些表包含标识的信息,如用户,用户组,等等。
ACT_HI_*: ’HI’表示history。就是这些表包含着历史的相关数据,如结束的流程实例,变量,任务,等等。
ACT_GE_*: 普通数据,各种情况都使用的数据。
由activiti配置文件 ——> ProcessEngineConfiguration ——> ProcessEngine ——> RepositoryService、RuntimeService、TaskService、HistoryService、ManagementService,由这些不同的 service 去操作不同的流程阶段。
创建Activiti工作流
分为3步:定义流程、部署流程、启动流程
定义流程
创建bpmn文件(实为xml文件):使用流程定义工具,按照BPMN规范,用流程符号将流程描述出来
部署流程
通过ProcessEngine获得repositoryservice,指定流程定义文件进行部署。可以单独部署和zip包部署。
/**
* 流程部署,通过processEngine获取部署服务进行部署,将数据写入数据库中
*/
@Test
public void testDeployment(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
// 定义流程的名字,流程文件bpmn和png
Deployment deployment = processEngine.getRepositoryService().createDeployment().name("出差申请").addClasspathResource("bpmn/envction.bpmn").addClasspathResource("bpmn/envction.png").deploy();
System.out.println("出差申请id:"+deployment.getId());
System.out.println("出差申请名称"+deployment.getName());
}
/**
* 使用zip包方式部署
*/
@Test
public void testZipDeployment(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
DeploymentBuilder deployment = repositoryService.createDeployment();
// 获取打包文件的输入流
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream("bpmn/envction.zip");
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = deployment.addZipInputStream(zipInputStream).deploy();
}
部署完成后会在表:act_re_deployment、act_re_procdef、act_ge_bytearray 中生成数据。
部署完成就可进行流程的查询及删除操作
/**
* 流程定义信息查询: 主要操作表 act_re_procdef
* 创建流程定义查询:createProcessDefinitionQuery(),指定流程key
*/
@Test
public void queryDefinition(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").orderByProcessDefinitionVersion().desc().list();
for (ProcessDefinition processDefinition : myEnvction) {
System.out.println("流程定义id:"+processDefinition.getId());
System.out.println("流程部署id:"+processDefinition.getDeploymentId());
System.out.println("流程定义名称:"+processDefinition.getName());
System.out.println("流程定义key"+processDefinition.getKey());
}
}
/**
* 删除流程定义信息, 级联删除
*/
@Test
public void deleteDefinition(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
repositoryService.deleteDeployment("1", true);
}
启动流程
使用runtimeService启动流程后生成流程实例
工作流程需要与业务挂钩,才能知道该工作流是干什么的,所以需要在启动流程实例的同时添加业务的 BusinessKey,此key会存入act_ru_execution表中
/**
* 启动流程实例
* act_hi_actinst: 流程实例执行历史
* act_hi_identitylink: 流程参与者的历史信息
* act_hi_procinst: 流程实例的历史信息
* act_hi_taskinst: 任务的历史信息
* act_ru_execution: 流程执行的信息
* act_ru_identitylink: 流程参与者信息
* act_ru_task: 流程任务信息
*/
@Test
public void testRun(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根据bpmn定义的流程id启动流程实例
// ProcessInstance myEnvction = runtimeService.startProcessInstanceByKey("myEnvction");
ProcessInstance myEnvction = runtimeService.startProcessInstanceByKey("myEnvction","envctionbusiness");
System.out.println("流程定义id:"+myEnvction.getProcessDefinitionId());
System.out.println("流程实例id:"+myEnvction.getId());
System.out.println("当前活动的id:"+myEnvction.getActivityId());
}
/**
* 查询个人待执行的任务
*/
@Test
public void testQueryTask(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 指定流程key和任务负责人
List<Task> list = taskService.createTaskQuery().processDefinitionKey("myEnvction").taskAssignee("张三").list();
for (Task task : list) {
System.out.println("任务负责人:"+task.getAssignee());
System.out.println("任务名称:"+task.getName());
System.out.println(task.getTaskDefinitionKey());
System.out.println("任务id:"+task.getId());
System.out.println("流程id:"+task.getProcessDefinitionId());
}
}
/**
* 完成个人任务
*/
@Test
public void testCompleteTask(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 指定任务id
// taskService.complete("5005");
List<Task> list = taskService.createTaskQuery().processDefinitionKey("myEnvction").taskAssignee("赵六").list();
for (Task task : list) {
taskService.complete(task.getId());
}
}
下载流程定义文件
/**
* 获取流程定义文件
* 关键:获取流程定义文件png和bpmn的输入流
*/
@Test
public void getDefinitionResource() throws IOException {
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获取流程定义信息
List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").orderByProcessDefinitionVersion().desc().list();
ProcessDefinition processDefinition = myEnvction.get(0);
// 获取png和bpmn的输入流
InputStream bpmnInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName());
InputStream pngInputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getDiagramResourceName());
// 定义输出流
File bpmnFile = new File("e:/evc.bpmn");
File pngFile = new File("e:/evc.png");
FileOutputStream bpmnOutputStream = new FileOutputStream(bpmnFile);
FileOutputStream pngOutputStream = new FileOutputStream(pngFile);
IOUtils.copy(bpmnInputStream, bpmnOutputStream);
IOUtils.copy(pngInputStream, pngOutputStream);
pngOutputStream.close();
bpmnOutputStream.close();
pngInputStream.close();
bpmnInputStream.close();
}
动态指定流程负责人
指定负责人:在定义流程bpmn时写死(实用性不强);动态指定
动态指定:uel表达式(流程变量);监听器
uel表达式方式:bpmn设计时使用${a0},${a1},...来指定负责人,在启动实例时再具体指定a0,a1,...的值,启动时全部指定好。
/**
* 启动流程时指定对应的流程负责人
* 启动时全部指定好了
*/
@Test
public void runUelInstance(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> map = new HashMap<String, Object>();
// 指定流程图中预设的负责人
map.put("assignee0","张1");
map.put("assignee1","李2");
map.put("assignee2","王3");
map.put("assignee3","赵4");
runtimeService.startProcessInstanceByKey("myProcess_1","businessKey", map);
}
监听器方式:
创建监听器实现TaskListener接口,每创建一个节点时指定节点的负责人
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
public class MyTaskListener implements TaskListener {
public void notify(DelegateTask delegateTask) {
String eventName = delegateTask.getEventName();
String name = delegateTask.getName();
if("创建出差申请".equals(name) && "create".equals(eventName))
delegateTask.setAssignee("王一");
else if("经理审批".equals(name) && "create".equals(eventName))
delegateTask.setAssignee("王二");
else if("总经理审批".equals(name) && "create".equals(eventName))
delegateTask.setAssignee("王三");
else if("财务审批".equals(name) && "create".equals(eventName))
delegateTask.setAssignee("王四");
else if("申请完成".equals(name) && "create".equals(eventName))
delegateTask.setAssignee("王五");
}
}
在bpmn流程节点指定Task Listener 对应的监听器class的全限定名
/**
* 使用 指定监听器(实现TaskListener接口) 监听流程节点信息同时指定流程负责人5
*
* 启动一个节点指定一个
*/
@Test
public void runUelListener(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
runtimeService.startProcessInstanceByKey("myProcess_listener1234", "businessKey");
}
流程变量
activiti在管理工作流时根据管理需要而设置的变量,存储在act_ru_variable 表中。
流程变量的数据类型有:String、integer、short、long、double、boolean、date、binary、对象(需实现序列化接口Serializable)
变量作用域:globa(默认流程实例),变量名不允许重复,重名后会被后一个同名的覆盖。
local(作用域在节点):作用域互不影响,可与globa变量重名。
使用方式:在节点属性上使用uel表达式:${xxx}或${pojo.attr},如指定负责人、分组...
在连线上使用uel表达式:${xxx}或${pojo.attr},根据表达式的布尔值决定流程的执行方向。
指定连线上流程变量时机:实例启动前;实例启动时;任务完成前;任务完成时。
定死 | 灵活 | |
runtimeService | 实例启动前 | 实例启动时 |
taskService | 任务完成前 | 任务完成时 |
@Test
public void complete1(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "猪组长0";
Task myEvection_var = taskService.createTaskQuery().processDefinitionKey("myEvection_var").taskAssignee(assignee).singleResult();
Map<String, Object> map = new HashMap<String, Object>();
// 指定连线中的流程变量 pojo方式
Evection evection = new Evection();
evection.setNum(3);
map.put("evection",evection);
taskService.complete(myEvection_var.getId(),map);
}
当连线未设置条件时,会按照bpmn中flow值小的执行。
组任务
一个任务可以由不止一个特定的负责人来完成,将其他候选人放入bpmn的candidate User中,组员之间用,分隔。
1. 查询特定候选人的某个流程实例;
2.拾取任务:指定当前候选人为此任务的负责人,claim(taskId,userId);
3.归还任务:设置当前任务的负责人为null,setAssignee(taskId,null);
4.交接任务:设置当前任务的负责人为其他的候选人,serAssignee(taskId,otherUserId)
@Test
public void runInstance(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> map = new HashMap<String, Object>();
map.put("assignee","小员工");
// 指定任务组中候选人,组员用 , 隔开
map.put("approve0","审批1,审批2");
runtimeService.startProcessInstanceByKey("myEvection_candidate",map);
}
/**
* 拾取任务
*/
@Test
public void pickTask(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 查询指定候选人的任务
Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskCandidateUser("审批2").singleResult();
if (myEvection_candidate != null){
// 给任务指定负责人
taskService.claim(myEvection_candidate.getId(),"审批2");
}
}
/**
* 归还任务(当前任务先要有负责人)
*/
@Test
public void resetTask(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 查询指定候选人的任务
Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskAssignee("审批2").singleResult();
if (myEvection_candidate != null){
// 给任务指定负责人
taskService.setAssignee(myEvection_candidate.getId(),null);
}
}
/**
* 交接任务-改变负责人(当前任务先要有负责人)
*/
@Test
public void changeAssigneeTask(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 查询指定候选人的任务
Task myEvection_candidate = taskService.createTaskQuery().processDefinitionKey("myEvection_candidate").taskAssignee("审批2").singleResult();
if (myEvection_candidate != null){
// 给任务指定负责人
taskService.setAssignee(myEvection_candidate.getId(),"审批1");
}
}
流程的挂起和激活
挂起方式 | 批量挂起 | 非批量挂起 |
api | repositoryService | runtimeService |
影响的数据表 | act_re_procedef act_ru_task act_ru_execution | act_ru_task act_ru_execution |
影响的表字段 | SUSPENDSION_STATUS:1-激活,2-挂起 |
判断激活或挂起:.isSuspended(),挂起的流程不能被完成。
/**
* 批量流程实例的挂起和激活(流程定义下的所有流程实例挂起):使用的是 repositoryService
* 会操作 act_re_procdef act_ru_task act_ru_execution 这3张表的 SUSPENSION_STATE_ 字段:1-激活,2-挂起
*/
@Test
public void testBatchSuspended(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
// 挂起和激活使用的是 repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
List<ProcessDefinition> myEnvction = repositoryService.createProcessDefinitionQuery().processDefinitionKey("myEnvction").list();
for (ProcessDefinition processDefinition : myEnvction) {
String id = processDefinition.getId();
// 判断当前流程是否被挂起
boolean suspended = processDefinition.isSuspended();
if(suspended) {
// 要激活流程的id;是否要激活;激活时间
repositoryService.activateProcessDefinitionById(id, true, null);
} else {
// 要挂起的流程id;是否要挂起;挂起时间
repositoryService.suspendProcessDefinitionById(id,true,null);
}
}
}
/**
* 单个流程实例的激活和挂起
* 只操作 act_ru_task act_ru_execution 这两张表
*/
@Test
public void testSingleSuspended(){
ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.mu.xml", "definedProcessEngine");
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
// 使用 runtimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processInstanceId("5001").list();
for (ProcessInstance processInstance : list) {
boolean suspended = processInstance.isSuspended();
if(suspended){
runtimeService.activateProcessInstanceById(processInstance.getId());
} else {
runtimeService.suspendProcessInstanceById(processInstance.getId());
}
}
}
网关
排他网关
根据分支条件的boolean值决定执行的任务,当分支条件都为true时,选择下个任务id小的执行。
并行网关
并行网关不会解析判断条件,即使定义了分支条件也会别忽略。会执行并行网关后的每一个分支,每个并行网关分支都执行完成后,流程才会继续往下走。
包含网关
集成了排他网关和并行网关的特点,会根据分支条件进入包含网关后的任务分支,当进入的任务分支都执行完成汇聚后才会继续执行后续的流程。
完整过程
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.bpmn.model.FlowElement;
import org.activiti.bpmn.model.SequenceFlow;
import org.activiti.bpmn.model.UserTask;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;
public class TestReal {
@Autowired
RepositoryService repositoryService;
@Autowired
RuntimeService runtimeService;
@Autowired
TaskService taskService;
/**
* 上传打包好的流程文件,并部署
* @param file
* @param deployName 流程部署名称
*/
void deploy(MultipartFile file, String deployName){
DeploymentBuilder deployment = repositoryService.createDeployment();
// 获取打包文件的输入流
ZipInputStream zipInputStream = null;
try {
zipInputStream = new ZipInputStream(file.getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
Deployment deploy = deployment.addZipInputStream(zipInputStream).name(deployName).deploy();
}
/**
* 新建业务后,业务发起指定流程,同时传入该业务的id(业务表数据的id)到流程实例中
* @param evectionId
* @param instanceKey
*/
void startInstance(String evectionId, String instanceKey) {
// 1 根据evectionId查询业务信息
Evection evection = new Evection();
// 设置处理人
Map<String, Object> map = new HashMap<String, Object>();
map.put("loadPeople", evection.getName());// 流程图上动态参数
runtimeService.startProcessInstanceByKey(instanceKey, evectionId, map);
// 修改业务单状态 审核中
evection.setStatus("审核中");
// evection 业务更新入数据库
}
/**
* 查询指定人正在执行中的任务列表
* @return
*/
List<Task> queryMyTask(){
return taskService.createTaskQuery().taskAssignee("指定的人").orderByTaskId().desc().list();
}
/**
* 根据任务查询业务详情
* @param taskId
*/
void queryTaskBusiness(String taskId) {
// 查询任务对应的业务信息
// 1. 根据taskId查询任务信息
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 2. 根据流程实例id查询流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
// 3. 根据流程实例查询业务id
String businessKey = processInstance.getBusinessKey();
// 4. 根据据业务id查询业务详情
// 获取流程的整个批注信息
List<Comment> taskComments = taskService.getTaskComments(taskId);
}
/**
* 查询某任务节点的流向连线集合,按钮形式展示到前端,供前端点击流程走向
* @param taskId
* @return
*/
List<String> queryLines(String taskId) {
// 1. 根据taskId查询任务信息
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 2. 获取当前流程模型
BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
// 3. 获取当前流程节点
FlowElement flowElement = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
// 这里不转也有方法拿到,我这是为了后人阅读方便
UserTask userTask = (UserTask)flowElement;
// 获取节点出口线段
List<SequenceFlow> outgoingFlows = userTask.getOutgoingFlows();
List<String> flowNames = new ArrayList<>();
outgoingFlows.forEach(flow -> {
flowNames.add(flow.getName());
});
return flowNames;
}
/**
* 完成任务
* @param taskId 任务id
* @param buttonValue 前端点击的按钮,即流程连线的值
* @param comment 批注信息
*/
void completeMyTask(String taskId, String buttonValue, String comment) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
// 先设置批注人
Authentication.setAuthenticatedUserId("批注人");
// 后添加批注信息
taskService.addComment(taskId, task.getProcessInstanceId(), comment);
Map<String, Object> map = new HashMap<>();
// 赋值流程图的连线动态定义的条件参数 lineValue
map.put("lineValue", buttonValue);
taskService.complete(taskId, map);
// 修改请假单状态
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
if (processInstance == null) {// 流程实例查不到则整个流程结束
evection.setStatus("审核完成");
}
}
}