使用步骤:
静态阶段 : 包含流程设计和流程部署 —xml模型
运行时阶段: 用户发起流程,各责任人对流程进行审核驳回等操作,Activiti 自动的根据流程状态
历史阶段:对于以关闭或审核通过的历史流程,进行查询的管理
Activiti内置数据库的作用:
流程部署:将绘制好的流程上传到引擎
流程定义:部署之后,流程定义对象
流程实例:用户发起流程
流程任务:流程实例中每个节点的处理任务
activiti 的引擎配置文件,包括: ProcessEngineConfiguration 的定义、数据源定义、事务管理器等,
此文件其实就是一个 spring 配置文件
两种配置方式:
一:Standalone,通常在 activiti.cfg.xml 配置文件中定义一个 id 为 processEngineConfiguration 的 bean,这里会使用 spring 的依赖注入来构建引擎。
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfig
uration">
<property name="dataSource" ref="dataSource" />
<property name="databaseSchemaUpdate" value="true"/>
bean>
二:与spring整合配置文件
<bean id="processEngineConfiguration"
class="org.activiti.spring.SpringProcessEngineConfiguration">
<property name="dataSource" ref="dataSource" />
<property name="transactionManager" ref="transactionManager" />
<property name="databaseSchemaUpdate" value="drop-create" />
<property name="jobExecutorActivate" value="false" />
bean>
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration"
ref="processEngineConfiguration" />
bean>
<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" />
<bean id="identityService" factory-bean="processEngine"
factory-method="getIdentityService" />
<bean id="managementService" factory-bean="processEngine"
factory-method="getManagementService" />
创建ProcessEngineConfiguration对象:
//要求 activiti.cfg.xml 中必须有一个 processEngineConfiguration 的 bean
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
//也可以使用下边的方法,更改 bean 的名字
ProcessEngineConfiguration.createProcessEngineConfigurationFromResource(String resource, String beanName);
//通过ProcessEngineConfiguration创建ProcessEngine
ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
//使用classpath下的activiti.cfg.xml中的配置创建processEngine (activiti.cfg.xml 文件名及路径固定,且 activiti.cfg.xml 文件中有 processEngineConfiguration 的配置)
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
Service | 描述 |
---|---|
RepositoryService | activiti 的资源管理类,部署查询流程定义,暂停激活,获取多种资源 |
RuntimeService | activiti 的流程运行管理类 |
TaskService | activiti 的任务管理类 |
HistoryService | activiti 的历史管理类 |
ManagerService | activiti 的引擎管理类 |
使用processEngine.getXXXService() 创建 |
单个文件方式
//1.创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.进行部署
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("diagram/holiday2.bpmn20.xml") //添加bpmn资源
.addClasspathResource("diagram/holiday2.bpmn20.png")
.name("请假申请单流程")
.deploy();
以上传文件方式部署
public void deployProcess(MultipartFile file, String companyId) throws IOException {
//1.获取上传的文件名
String fileName = file.getOriginalFilename();
//2.通过repositoryService进行流程部署
//DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
//文件名称,文件的bytes数组
//deploymentBuilder.addBytes(fileName,file.getBytes()); //部署流程
//deploymentBuilder.tenantId(companyId);//不同系统用一个流程定义来启动流程实例,tenantId用以区分同一个流程定义下分属不同系统的流程实例
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().addBytes(fileName, file.getBytes()).tenantId(companyId);
Deployment deploy = deploymentBuilder.deploy();
//3.打印部署结果
System.out.println(deploy);
}
压缩包方式
//1.创建ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService实例
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.转化出ZipInputStream流对象
InputStream is = ActivitiDeployment.class.getClassLoader().getResourceAsStream("diagram/holidayBPMN.zip");
//将 inputstream流转化为ZipInputStream流
ZipInputStream zipInputStream = new ZipInputStream(is);
//3.进行部署
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(zipInputStream) .name("请假申请单流程")
.deploy();//部署
Deployment
@Internal
public interface Deployment {
String getId();
String getName();
Date getDeploymentTime();
String getCategory();
String getKey();
String getTenantId();
}
背后影响的表:
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RunService对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.创建流程实例 流程定义的key需要知道 processDefinitionKey
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
// 流程定义key
String processDefinitionKey = "holiday";
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 查询流程定义
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//遍历查询结果
List<ProcessDefinition> list = processDefinitionQuery
.processDefinitionKey(processDefinitionKey)
.orderByProcessDefinitionVersion().desc().list();
//通过tenantId查询
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionTenantId(companyId)
.latestVersion().list();
ProcessDefinition
@Internal
public interface ProcessDefinition {
String getId();
String getCategory();
String getName();
String getKey();
String getDescription();
int getVersion();
String getResourceName();
String getDeploymentId();
String getDiagramResourceName();
boolean hasStartFormKey();
boolean hasGraphicalNotation();
boolean isSuspended();
String getTenantId();
String getEngineVersion();
}
流程在运行过程中可以查询流程实例的状态,当前运行结点等信息
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 流程定义key
String processDefinitionKey = "holiday";
//3.得到ProcessInstanceQuery对象,可以认为它就是一个查询器
//4.设置条件,并查询出当前的所有流程定义 查询条件:流程定义的key=holiday
//orderByProcessDefinitionVersion() 设置排序方式,根据流程定义的版本号进行排序 ProcessInstance中没有version
List<ProcessInstance> list = runtimeService
.createProcessInstanceQuery()
.processDefinitionKey(processDefinitionKey)//
.list();
//5.输出流程定义信息
for(ProcessInstance processInstance :list){
System.out.println("----------------------------");
System.out.println("流程实例id: " + processInstance.getProcessInstanceId());
System.out.println("所属流程定义id: " + processInstance.getProcessDefinitionId());
System.out.println("是否执行完成: " + processInstance.isEnded());
System.out.println("是否暂停: " + processInstance.isSuspended());
System.out.println(" 当 前 活 动 标 识 : " +
processInstance.getActivityId());
根据自己的业务id查询流程实例如自定义proc_instance表中的processId
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey( String processInstanceBusinessKey).singleResult();
全部流程实例RepositoryService
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.查询流程定义的对象,可以根据id或key查询,但此时id需要去表中查看
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("holiday").singleResult();
//或根据processKey和tenantId查询
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey)
.processDefinitionTenantId(companyId).latestVersion().singleResult();
//4.得到当前流程定义的实例是否都为暂停状态
boolean suspended = processDefinition.isSuspended();
String processDefinitionId = processDefinition.getId();
//5.判断
if(suspended){
//说明是暂停,就可以激活操作,可以根据id或key,此时id已可以查出
repositoryService.activateProcessDefinitionById(processDefinitionId,true
,null);
System.out.println("流程定义:"+processDefinitionId+"激活");
}else{
repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);
System.out.println("流程定义:"+processDefinitionId+"挂起");
}
单个流程实例
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.查询流程实例对象 .processEngineInstanceBusinessKey("holiday")报错
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("2501").singleResult();
//4.得到当前流程定义的实例是否都为暂停状态
boolean suspended = processInstance.isSuspended();
String processInstanceId = processInstance.getId();
//5.判断
if(suspended){
//说明是暂停,就可以激活操作
runtimeService.activateProcessInstanceById(processInstanceId); System.out.println("流程:"+processInstanceId+"激活");
}else{
runtimeService.suspendProcessInstanceById(processInstanceId); System.out.println("流程:"+processInstanceId+"挂起");
}
背后影响的表:
/**
* 注意事项:
* 1.当我们正在执行的这一套流程没有完全审批结束的时候,此时如果要删除流程定义信息就会失败
* 2.如果公司层面要强制删除,可以使用repositoryService.deleteDeployment("1",true);
* //参数true代表级联删除,此时就会先删除没有完成的流程结点,最后就可以删除流程定义信息 false的值代表不级联
*
*/
repositoryService.deleteDeployment(deploymentId);
repositoryService.deleteDeployment(deploymentId, true);
删除流程实例
runtimeService.deleteProcessInstance( String processInstanceId,
String deleteReason)
通过流程定义对象获取流程定义资源,获取 bpmn 和 png。
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService对象
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.得到查询器:ProcessDefinitionQuery对象
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//4.设置查询条件 processDefinitionKey,也可通过id查询
processDefinitionQuery.processDefinitionKey("holiday");//参数是流程定义的key
//5.执行查询操作,查询出想要的流程定义(目前只有一条,用singleResult)
ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
//6.通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
//7.通过repositoryService的方法,实现读取图片信息及bpmn文件信息(输入流)
//getResourceAsStream()方法的参数说明:第一个参数部署id,第二个参数代表资源名称
//processDefinition.getDiagramResourceName() 代表获取png图片资源的名称
//processDefinition.getResourceName()代表获取bpmn文件的名称
/*InputStream pngIs = repositoryService
.getResourceAsStream(deploymentId,processDefinition.getDiagramResourceName());*/
InputStream bpmnIs = repositoryService
.getResourceAsStream(deploymentId,processDefinition.getResourceName());
//8.构建出OutputStream流
System.out.println(processDefinition.getDiagramResourceName());//diagram/
OutputStream pngOs = new FileOutputStream("path\\"+processDefinition.getDiagramResourceName());
*/
OutputStream bpmnOs =
new FileOutputStream("path\\"+processDefinition.getResourceName());
//9.输入流,输出流的转换 commons-io-xx.jar中的方法
//IOUtils.copy(pngIs,pngOs);
IOUtils.copy(bpmnIs,bpmnOs);
//10.关闭流
//pngOs.close();
bpmnOs.close();
//pngIs.close();
bpmnIs.close();
通过查询流程部署信息获取流程定义资源。
// 通过流程引擎获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//读取资源名称
List<String> resources = repositoryService.getDeploymentResourceNames(deploymentId);
String resource_image = null;
//获取图片
for(String resource_name :resources){
if(resource_name.indexOf(".png")>=0){
resource_image = resource_name;
}
}
//图片输入流
InputStream inputStream =repositoryService.getResourceAsStream(deploymentId, resource_image);
File exportFile = new File("d:/holiday.png");
FileOutputStream fileOutputStream = newFileOutputStream(exportFile);
byte[] buffer = new byte[1024];
int len = -1;
//输出图片
while((len = inputStream.read(buffer))!=-1){
fileOutputStream.write(buffer, 0, len);
}
inputStream.close();
fileOutputStream.close();
说明:
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到HistoryService
HistoryService historyService = processEngine.getHistoryService();
//3.得到HistoricActivitiInstanceQuery对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
historicActivityInstanceQuery.processInstanceId("2501");//设置流程实例的id PROC_INST_ID_
//4.执行查询
List<HistoricActivityInstance> list = historicActivityInstanceQuery
.orderByHistoricActivityInstanceStartTime().asc().list();//排序StartTime
//5.遍历查询结果
for (HistoricActivityInstance instance :list){
//1.得到ProcessEngine对象 这是简单方式,将 activiti.cfg.xml 文件名及路径固定,且 activiti.cfg.xml 文件中有 processEngineConfiguration 的配置
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到TaskService对象
TaskService taskService = processEngine.getTaskService();
//3.根据流程定义的key,负责人assignee来实现当前用户的任务列表查询
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey("holiday")
.taskAssignee("lisi")
.list();
//根据流程实例ID获取任务节点
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
背后操作的表:
for(Task task :taskList){
...
taskService.complete(task.getId());
字段 BUSINESS_KEY 就是存放业务 KEY 的。再通过主键 ID 去查询业务信息,比如通过请假单的 ID,去查询更多的
请假信息(请假人,请假时间,请假天数,请假事由等)
//第一个参数:是指流程定义key
//第二个参数:业务标识businessKey
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday", "请假流程人id");
//4.输出processInstance相关的属性,取出businessKey使用:processInstance.getBusinessKey()
System.out.println(processInstance.getBusinessKey());
固定分配:Assignee指定
UEL 表达式: UEL-value
- ${assignee0}
和${user.assignee}
, assignee 这个变量是 activiti 的一个流程变量。user 也是 activiti 的一个流程变量, user.assignee 表示通过调用 user 的 getter 方法获取值。
UEL-method:
${userBean.getHolidayId()}
userBean 是 spring 容器中的一个 bean,表示调用该 bean 的 getUserId()方法。
UEL-method 与 UEL-value 结合:
${ldapService.findManagerForEmployee(emp)}
ldapService 是 spring 容器的一个 bean,findManagerForEmployee 是该 bean 的一个方法, emp 是 activiti 流程变量, emp 作为参数传到 ldapService.findManagerForEmployee 方法中。
表达式支持解析基础类型、 bean、 list、 array 和 map,也可作为条件判断:
${order.price > 100 && order.price < 250}
启动流程时设置
ProcessInstance processInstance=runtimeService.startProcessInstanceByKey( String processDefinitionKey,
java.util.Map<String, Object> variables);
任务办理时设置taskService.complete(String taskId,
java.util.Map
通过当前流程实例id设置全局变量,该流程实例必须未执行完成
//第一个参数:流程实例的id
//第二个参数:流程变量名
//第三个变量:流程变量名,所对应的值
runtimeService.setVariable(String executionId,
String variableName,
Object value);
//一次设置多个值
runtimeService.setVariables(executionId, variables)
通过当前任务设置
taskService.setVariable( String taskId,
String variableName,
Object value);
//一次设置多个值
taskService.setVariables(taskId, variables)
任务办理时
// 设置local变量,作用域为该任务,每个任务可以设置同名的变量,互不影响
taskService.setVariablesLocal(tasked, variables);
taskService.complete(taskId);
通过当前任务设置
taskService.setVariableLocal( String taskId,
String variableName,
Object value);
//一次设置多个值
taskService.setVariablesLocal(taskId, variables)
candidate-users(候选人),多个候选人之间用逗号分开
流程:
启动流程实例,有任务申请之后
第一步:查询组任务
指定候选人,查询该候选人当前的待办任务。
候选人不能办理任务。
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(key) //流程定义的key
.taskCandidateUser(candidate_users)//设置候选用户
.list();
第二步:拾取(claim)任务
该组任务的所有候选人都能拾取。
将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。
if(task!=null){
taskService.claim(task.getId(),candidate_users);//第一个参数任务ID,第二个参数为具体的候选用户名
System.out.println("任务拾取完毕!");
}
//任务交接,前提要保证当前用户是这个任务的负责人,这时候他才可以有权限去将任务交接给其他候选人 taskService.setAssignee(task.getId(),"lisi")
//如果只是归还任务 taskService.setAssignee(task.getId(),null)建议不要这样使用
if(task!=null){
taskService.setAssignee(task.getId(),"lisi");//交接任务为lisi ,交接任务就是一个候选人拾取用户的过程
System.out.println("交接任务完成~!");
}
第三步:查询个人任务
查询方式同个人任务部分,根据 assignee 查询用户负责的个人任务。
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(key) .taskAssignee(assignee) //设置任务的负责人
.list();
第四步:办理个人任务taskService.complete(task.getId());
排他网关:排他网关只会选择一个为 true 的分支执行。 (即使有两个分支条件都为 true, 排他网关也会只
选择一条分支去执行),如果从网关出去的线所有条件都不满足则系统抛出异常,经过排他网关必须要有一条且只有一条分支走。
并行网关:
包含网关:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.itheima.activitigroupId>
<artifactId>activiti01artifactId>
<version>1.0-SNAPSHOTversion>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>2.6.9version>
plugin>
plugins>
build>
<properties>
<slf4j.version>2.0.0slf4j.version>
<log4j.version>1.2.17log4j.version>
properties>
<dependencies>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-engineartifactId>
<version>7.0.0.SR1version>
<exclusions>
<exclusion>
<artifactId>mybatisartifactId>
<groupId>org.mybatisgroupId>
exclusion>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-springartifactId>
<version>7.0.0.SR1version>
<exclusions>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-bpmn-modelartifactId>
<version>7.0.0.SR1version>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-bpmn-converterartifactId>
<version>7.0.0.SR1version>
<exclusions>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-json-converterartifactId>
<version>7.0.0.SR1version>
<exclusions>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activitigroupId>
<artifactId>activiti-bpmn-layoutartifactId>
<version>7.0.0.SR1version>
<exclusions>
<exclusion>
<artifactId>slf4j-apiartifactId>
<groupId>org.slf4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.activiti.cloudgroupId>
<artifactId>activiti-cloud-services-apiartifactId>
<version>7.0.0.Beta1version>
<exclusions>
<exclusion>
<artifactId>activiti-engineartifactId>
<groupId>org.activitigroupId>
exclusion>
<exclusion>
<artifactId>jackson-coreartifactId>
<groupId>com.fasterxml.jackson.coregroupId>
exclusion>
<exclusion>
<artifactId>spring-contextartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
<exclusion>
<artifactId>jackson-databindartifactId>
<groupId>com.fasterxml.jackson.coregroupId>
exclusion>
<exclusion>
<artifactId>activiti-bpmn-modelartifactId>
<groupId>org.activitigroupId>
exclusion>
<exclusion>
<artifactId>spring-beansartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<version>8.0.29version>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
<dependency>
<groupId>log4jgroupId>
<artifactId>log4jartifactId>
<version>${log4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-log4j12artifactId>
<version>${slf4j.version}version>
<exclusions>
<exclusion>
<artifactId>log4jartifactId>
<groupId>log4jgroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-nopartifactId>
<version>${slf4j.version}version>
dependency>
<dependency>
<groupId>org.mybatisgroupId>
<artifactId>mybatisartifactId>
<version>3.5.11version>
dependency>
<dependency>
<groupId>commons-dbcpgroupId>
<artifactId>commons-dbcpartifactId>
<version>1.4version>
dependency>
<dependency>
<groupId>commons-iogroupId>
<artifactId>commons-ioartifactId>
<version>2.11.0version>
dependency>
dependencies>
<repositories>
<repository>
<id>alfrescoid>
<name>Activiti Releasesname>
<url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/url>
<releases>
<enabled>trueenabled>
releases>
repository>
repositories>
project>
**Springboot整合activiti时:
activiti-spring-boot默认集成了spring security用于权限管理如需禁用security启动类中屏蔽ActivitiSpringIdentityAutoConfiguration,再增加一个配置类即可 Application中禁用权限相关集成
package com.meijm.activiti;
import org.activiti.core.common.spring.identity.config.ActivitiSpringIdentityAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(exclude = {ActivitiSpringIdentityAutoConfiguration.class})
public class ActivitiApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiApplication.class); }
}
数据库连接池添加activiti相关数据库如act
datasource:
act:
jdbc-url: jdbc:mysql://localhost:3306/act?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
activiti:
history-level: full
db-history-used: true
如果activiti 初始化表 问题:Error querying database. Cause: java.sql.SQLSyntaxErrorException: Table ‘activiti_dev.act_ge_property’ doesn’t exist: 因为mysql使用schema标识库名而不是catalog,因此mysql会扫描所有的库来找表,如果其他库中有相同名称的表,activiti就以为找到了,本质上这个表在当前数据库中并不存在。
设置nullCatalogMeansCurrent=true,表示mysql默认当前数据库操作,在mysql-connector-java 5.xxx该参数默认为true,在6.xxx以上默认为false,因此需要设置nullCatalogMeansCurrent=true。
useUnicode=true``&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC
多数据源配置
将activiti数据库连接池作为默认主源,业务数据库连接池明确指定DataSource
@Configuration
public class AuditDatasourceConfig extends AbstractProcessEngineAutoConfiguration {
//主数据源,用来支持act数据库
@Bean//创建对象
@Primary//默认主源
@ConfigurationProperties(prefix = "spring.datasource.act")//从application.yml配置文件中拿到act的信息
@Qualifier("activitiDataSource")
public DataSource activitiDataSource() {
return DataSourceBuilder.create().build();
}
//业务数据源,使用jpa开发(entityManager和transactionManager)
@Bean
@ConfigurationProperties(prefix = "spring.datasource.ihrm")
@Qualifier("ihrmDataSource")
public DataSource ihrmDataSource() {
return DataSourceBuilder.create().build();
}
}
业务数据库的配置(使用SpringDataJpa开发,entityManager和transactionManager)
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
/**
* 业务数据库的配置
*/
@Configuration
//自己去定义jpa相关信息
@EnableJpaRepositories(
//代理的dao接口所在的包,这里指定了dao的位置,要想业务生效只能将相关dao放到这个位置
basePackages = "com.ihrm.audit.dao",
entityManagerFactoryRef = "ihrmEntityManager",//entityManager工厂需自己创建
transactionManagerRef = "ihrmTransactionManager"
)
public class JpaRepositoriesConfig {
@Autowired
private Environment env;
//entityManager和transactionManager都需要指定datasource
@Autowired
@Qualifier("ihrmDataSource")
private DataSource ihrmDataSource;
//创建entityManagerFactory工厂
@Bean
@Primary public LocalContainerEntityManagerFactoryBean ihrmEntityManager() {
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setDataSource(ihrmDataSource);
//配置扫描的实体类包(springdatajpa会自动扫描),要用到的实体类统一放到这个位置
em.setPackagesToScan(new String[] { "com.ihrm.audit.entity","com.ihrm.domain.system" });
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
em.setJpaVendorAdapter(vendorAdapter);
HashMap<String, Object> properties = new HashMap<>();
properties.put("hibernate.hbm2ddl.auto", env.getProperty("hibernate.hbm2ddl.auto"));
properties.put("hibernate.show_sql", "true");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
properties.put("hibernate.implicit_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy");
properties.put("hibernate.physical_naming_strategy", "org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy");
em.setJpaPropertyMap(properties);
return em;
}
//创建事务管理器
@Primary
@Bean public PlatformTransactionManager ihrmTransactionManager() {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory( ihrmEntityManager().getObject());
return transactionManager;
}
}
在activiti中具有自己的用户,用户组等概念。但是在实际的项目中很少用到,并且流程实例的
发起,审核往往会和具体的业务挂钩。为了更好的进行流程控制并逐步审核,所以我们需要自己定义一
些列表,结合已有的用户数据进行操作:
审批列表查询
流程申请信息查询
发起流程
提交流程(通过,驳回,撤销)
新添加几个表
proc_instance业务流程实例表(保存业务流程的数据)
proc_data申请的业务数据以json字符串形式存入如{"startTime":"2020-03-24T09:31:37.000Z","endTime":"2020-03-28T09:31:40.000Z","reasonsForApplication":"111","processName":"请假","duration":12,"userId":"1075383135459430400","processKey":"process_leave"}
CREATE TABLE `proc_instance` (
`process_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '流程实例ID',
`process_key` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '流程标识',
`process_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '流程名称',
`process_definition_id` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '流程定义ID',
`process_state` varchar(3) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '流程状态(0已提交;1审批中;2审批\r\n通过;3审批不通过;4撤销)',
`user_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '申请人ID',
`username` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '申请人',
`proc_apply_time` datetime DEFAULT NULL COMMENT '申请时间',
`proc_curr_node_user_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '当前节点审批人ID',
`proc_curr_node_user_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '当前节点审批人',
`proc_end_time` datetime DEFAULT NULL COMMENT '结束流程时间',
`proc_data` longtext CHARACTER SET utf8mb3 COLLATE utf8_general_ci,
`department_id` varchar(40) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
`department_name` varchar(40) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL,
`time_of_entry` datetime DEFAULT NULL,
PRIMARY KEY (`process_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT
proc_task_instance业务流程的任务(业务任务明细数据,每个节点的审批意见,状态)
CREATE TABLE `proc_task_instance` (
`process_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '流程实例ID',
`task_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务实例ID',
`task_key` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务节点key',
`task_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '任务节点',
`should_user_id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '应审批用户ID',
`should_user_name` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '应审批用户',
`handle_user_id` varchar(2000) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '实际处理用户ID',
`handle_user_name` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '实际处理用户',
`handle_time` datetime DEFAULT NULL COMMENT '处理时间',
`handle_opinion` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '处理意见',
`handle_type` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '处理类型(2审批通过;3审批不通过;4\r\n撤销)',
PRIMARY KEY (`process_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT
proc_user_group自定义业务流程的用户组表
CREATE TABLE `proc_user_group` (
`id` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci NOT NULL COMMENT '主键',
`name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '组名',
`param` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '入参',
`isql` varchar(1000) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '对应sql',
`isvalid` varchar(2) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '有效标记',
`create_user` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '创建人',
`create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',
`update_user` varchar(45) CHARACTER SET utf8mb3 COLLATE utf8_general_ci DEFAULT NULL COMMENT '最后更新人',
`update_time` timestamp NULL DEFAULT NULL COMMENT '最后更新时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT
为了更加灵活的处理流程,加入了自定义组表。在此表中通过SQL语句的形式和流程中的侯选组进行关
联。也就意味着我们在操作流程的时候,需要通过组名称获取到待执行sql,执行得到获选人
添加相应的实体类和dao层
最后在网关中加入微服务相应配置。
/**
* 部署新流程
* 前端将绘制好的流程模型图(bpmn)文件上传到方法中
* 参数 : 上传的文件
* MultipartFile
*/@RequestMapping(value = "/deploy",method = RequestMethod.POST)
public Result deployProcess(@RequestParam("file") MultipartFile file) throws IOException {
processService.deployProcess(file,companyId);
return new Result(ResultCode.SUCCESS);
}
/**
* 流程部署
* @param file 上传bpmn文件
* @param companyId 企业id
*/public void deployProcess(MultipartFile file, String companyId) throws IOException {
//1.获取上传的文件名
String fileName = file.getOriginalFilename();
//2.通过repositoryService进行流程部署
//DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
//文件名称,文件的bytes数组
//deploymentBuilder.addBytes(fileName,file.getBytes()); //部署流程
//deploymentBuilder.tenantId(companyId); //不同系统用一个流程定义来启动流程实例,tenantId用以区分同一个流程定义下分属不同系统的流程实例
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment().addBytes(fileName, file.getBytes()).tenantId(companyId);
Deployment deploy = deploymentBuilder.deploy();
//3.打印部署结果
System.out.println(deploy);
}
查询所有
@RequestMapping(value = "/definition",method = RequestMethod.GET)
public Result definitionList() throws IOException {
//调用service查询
List list = processService.getProcessDefinitionList(companyId);
return new Result(ResultCode.SUCCESS,list);
}
//根据企业id查询所有的流程定义对象
public List getProcessDefinitionList(String companyId) {
//借助repositoryService,createProcessDefinitionQuery得到流程定义查询对象,
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionTenantId(companyId)
.latestVersion().list();
return list;
}
设置流程的挂起与激活状态
@RequestMapping(value = "/suspend/{processKey}",method = RequestMethod.GET)
public Result suspendProcess(@PathVariable String processKey) throws IOException {
processService.suspendProcess(processKey,companyId);
return new Result(ResultCode.SUCCESS);
}
//挂起或者激活流程
public void suspendProcess(String processKey,String companyId) {
//1.根据processKey查询流程定义,只要涉及到查询createProcessDefinitionQuery,processDefinitionKey设置key条件,TenantId租户id,singleResult唯一对象
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey)
.processDefinitionTenantId(companyId).latestVersion().singleResult();
//2.判断是否为挂起状态
if(definition.isSuspended()) {
//2.1 如果是挂起状态:设置为激活
repositoryService.activateProcessDefinitionById(definition.getId());
}else {
//2.2 如果不是激活状态: 设置为挂起
repositoryService.suspendProcessDefinitionById(definition.getId());
}
}
查询申请列表(查询proc_instance表)
/**
* 查询申请列表
* 参数:
* page,size * 业务参数: 这些参数封装到ProcInstance对象中
* 审批类型
* 审批状态(多个,每个状态之间使用","隔开)
* 当前节点的待处理人
*/
@RequestMapping(value = "/instance/{page}/{size}",method = RequestMethod.PUT)
public Result instanceList(@RequestBody ProcInstance instance,@PathVariable int page,@PathVariable int size) throws IOException {
//1.调用service分页查询(得到的是springdatajpa封装的page对象),还应该传递companyId,在数据库中暂未设置
Page pages = auditService.getInstanceList(instance,page,size);
//2.page对象转化为自己的pageResult对象
PageResult pr = new PageResult(pages.getTotalElements(),pages.getContent());
//3.返回
return new Result(ResultCode.SUCCESS,pr);
}
/**
* 查询所有的业务的申请流程
*/
public Page getInstanceList(ProcInstance instance, int page, int size) {
//1.使用Specification查询,构造Specification
Specification<ProcInstance> spec = new Specification<ProcInstance>() {
//2.构造查询条件 (根据传入参数判断,构造)
public Predicate toPredicate(Root<ProcInstance> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
//一list形式接收多个条件
List<Predicate> list = new ArrayList<>();
//审批类型 -- processKey if(!StringUtils.isEmpty(instance.getProcessKey())) {
list.add(cb.equal(root.get("processKey").as(String.class),instance.getProcessKey()));
}
//审批状态(多个,每个状态之间使用","隔开) --processState
if(!StringUtils.isEmpty(instance.getProcessState())) {
Expression<String> exp = root.<String>get("processState");
list.add(exp.in(instance.getProcessState().split(",")));
}
//当前节点的待处理人 --procCurrNodeUserId ,待处理人可能有多个,所以不能用equal用like+%
if(!StringUtils.isEmpty(instance.getProcCurrNodeUserId())) {
list.add(cb.like(root.get("procCurrNodeUserId").as(String.class),"%"+instance.getProcCurrNodeUserId()+"%"));
}
//发起人 -- userId if(!StringUtils.isEmpty(instance.getUserId())) {
list.add(cb.equal(root.get("userId").as(String.class),instance.getUserId()));
}
return cb.and(list.toArray(new Predicate[list.size()]));
}
};
//3.调用dao进行Specification查询,带分页的findAll
return procInstanceDao.findAll(spec,PageRequest.of(page-1,size));//
}
需要注意的时,对于待审批的流程需要传入参数(ProcCurrNodeUserId),这也就以为者此字段
需要进行维护(如发起申请之后,需要查询下个节点的审批人,更新到此字段)。
查询申请详情(即查询某一条proc_instance表的记录)
/**
* 查询申请的详情数据
* 参数 : 申请对象的id
*/@RequestMapping(value = "/instance/{id}",method = RequestMethod.GET)
public Result instanceDetail(@PathVariable String id) throws IOException {
//调用service根据id查询
ProcInstance instance = auditService.findInstanceDetail(id);
return new Result(ResultCode.SUCCESS,instance);
}
//根据id查询申请数据响应
public ProcInstance findInstanceDetail(String id) {
return procInstanceDao.findById(id).get();
}
根据id获取发起的业务流程。在返回值中包含一个string类型字符串 procData
procData针对不同的流程,内容是不一样的。为了更加灵活的控制流程业务数据,需要将发起流
程的所有信息已json的形式保存到此字段中
构造业务数据
获取候选人组:通过下一任务id,taskService.getIdentityLinksForTask(nextTask.getId())获取时间参与者内包含GroupId,通过procUserGroupDao.findById(groupId).get();查询自定义组表,根据param替换组表中的sql语句
@RequestMapping(value = "/startProcess",method = RequestMethod.POST)
public Result startProcess(@RequestBody Map map) throws IOException {
//调用service
auditService.startProcess(map,companyId);
return new Result(ResultCode.SUCCESS);
}
//流程申请
public void startProcess(Map map, String companyId) {
//1.构造业务数据
String userId =(String) map.get("userId");
String processKey =(String) map.get("processKey");
String processName =(String) map.get("processName");
//用户数据通过远程微服务
User user = feignClientService.getUserInfoByUserId(userId);
ProcInstance instance = new ProcInstance();
BeanUtils.copyProperties(user,instance);
instance.setUserId(userId);
instance.setProcessId(idWorker.nextId()+"");
instance.setProcApplyTime(new Date());
instance.setProcessKey(processKey);
instance.setProcessName(processName);
instance.setProcessState("1");
//procData中的数据为json形式
String data = JSON.toJSONString(map);
instance.setProcData(data);
//2.查询流程定义
ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionKey(processKey)
.processDefinitionTenantId(companyId).latestVersion().singleResult();
//3.开启流程,用到runtimeService
Map vars = new HashMap();
if("process_leave".equals(processKey)) {
//请假
vars.put("days",map.get("duration"));
}
//startProcessInstanceById(流程定义的id,业务数据id,内置的参数) ,启动流程实例时设置流程变量
ProcessInstance processInstance = runtimeService.startProcessInstanceById(definition.getId(), instance.getProcessId(), vars);
//4.自动执行第一个任务节点
//4.1 获取待执行的任务节点 taskservice Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
//4.2 执行即可
taskService.complete(task.getId());
//5.获取下一个节点数据,填充业务数据中当前待审批人
//获取下一个节点,这行语句表示获取的永远都是待处理的节点
Task next = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
if(next != null) {
List<User> users = findCurrUsers(next, user);
String usernames = "", userIdS = "";
for (User user1 : users) {
usernames += user1.getUsername() + " ";
userIdS += user1.getId();
}
instance.setProcCurrNodeUserId(userIdS);
instance.setProcCurrNodeUserName(usernames);
}
procInstanceDao.save(instance);
ProcTaskInstance pti = new ProcTaskInstance();
pti.setTaskId(idWorker.nextId()+"");
pti.setProcessId(instance.getProcessId());
pti.setHandleTime(new Date());
//处理类型(2审批通过;3审批不通过;4\r\n撤销
pti.setHandleType("2");
pti.setHandleUserId(userId);
pti.setHandleUserName(user.getUsername());
pti.setTaskKey(task.getTaskDefinitionKey());
pti.setTaskName(task.getName());
//处理意见
pti.setHandleOpinion("发起申请");
procTaskInstanceDao.save(pti);
}
private List<User> findCurrUsers(Task nextTask,User user) {
//查询任务的节点数据(候选人组)
List<IdentityLink> list = taskService.getIdentityLinksForTask(nextTask.getId());
List<User> users = new ArrayList<>();
for (IdentityLink identityLink : list) {
String groupId = identityLink.getGroupId(); //候选人组id
ProcUserGroup userGroup = procUserGroupDao.findById(groupId).get();//查询userGroup
String param = userGroup.getParam();
String paramValue = null;
if ("user_id".equals(param)) {
paramValue = user.getId();
}
else if ("department_id".equals(param)) {
paramValue = user.getDepartmentId();
}
else if ("company_id".equals(param)) {
paramValue = user.getCompanyId();
}
//根据userGroup得到sql语句,sql语句中有些参数需要替换如${department_id}
String sql = userGroup.getIsql().replaceAll("\\$\\{" + param + "\\}", paramValue);
//执行proc_user_group表中获取到的sql语句
Query query = entityManager.createNativeQuery(sql);
query.unwrap(NativeQueryImpl.class).setResultTransformer(Transformers.aliasToBean(User.class));
users.addAll(query.getResultList());
}
return users;
}
1.查询业务流程对象
2.设置业务流程状态
3.根据不同的操作类型,完成不同的业务处理
4.更新业务流程对象,保存业务任务对象
/**
* 提交审核,传递接收任务实例对象
* handleType; // 处理类型(2审批通过;3审批不通过;4撤销)
*/
@RequestMapping(value = "/instance/commit",method = RequestMethod.PUT)
public Result commit(@RequestBody ProcTaskInstance taskInstance) throws IOException {
//调用service
auditService.commit(taskInstance,companyId);
return new Result(ResultCode.SUCCESS);
}
/**
* 提交审核
* handleType; // 处理类型(2审批通过;3审批不通过;4撤销)
*
* ProcTaskInstance * handleOpinion: "xxxxxxc" 操作说明
handleType: "4" 处理类型(2审批通过;3审批不通过;4撤销)
handleUserId: "1063705989926227968" 处理人
processId: "1175593305465352192" 业务流程id
* */ public void commit(ProcTaskInstance taskInstance, String companyId) {
//1.查询业务流程对象
String processId = taskInstance.getProcessId();
ProcInstance instance = procInstanceDao.findById(processId).get();
//2.设置业务流程状态(0已提交;1审批中;2审批通过;3审批不通过;4撤销)
instance.setProcessState(taskInstance.getHandleType());
//3.根据不同的操作类型,完成不同的业务处理
//查询出activiti中的流程实例 (根据自己的业务id查询activiti中的流程实例)
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(processId).singleResult();
User user = feignClientService.getUserInfoByUserId(taskInstance.getHandleUserId());
if ("2".equals(taskInstance.getHandleType())) {
//3.1 如果审核通过,完成当前的任务
//查询出当前节点,并完成当前节点任务
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
taskService.complete(task.getId());
//查询出下一个任务节点,如果存在下一个流程没有结束
Task next = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
if(next != null) {
List<User> users = findCurrUsers(next, user);
String usernames = "", userIdS = "";
for (User user1 : users) {
usernames += user1.getUsername() + " ";
userIdS += user1.getId();
}
instance.setProcCurrNodeUserId(userIdS);
instance.setProcCurrNodeUserName(usernames);
//流程没有结束将状态改回1
instance.setProcessState("1");
}else{
//如果不存在下一个节点,任务结束
instance.setProcessState("2");
}
} else {
//3.2 如果审核不通过,或者撤销(删除activiti流程),不能直接传递processId,这是我们自己定义的id,应该删除activiti的id,先获取activiti中的流程实例
runtimeService.deleteProcessInstance(processInstance.getId(),taskInstance.getHandleOpinion());
}
//4.更新业务流程对象,保存业务任务对象
procInstanceDao.save(instance);
taskInstance.setTaskId(idWorker.nextId()+"");
taskInstance.setHandleUserName(user.getUsername());
taskInstance.setHandleTime(new Date());
procTaskInstanceDao.save(taskInstance);
}
//根据processId查询业务流程明细
public List<ProcTaskInstance> findTasksByProcess(String id) {
return procTaskInstanceDao.findByProcessId(id);
}
}
查询流程明细
//查询流程任务明细
@RequestMapping(value = "/instance/tasks/{id}",method = RequestMethod.GET)
public Result tasks(@PathVariable String id) throws IOException {
//调用service
return new Result(ResultCode.SUCCESS,auditService.findTasksByProcess(id));
}
//根据processId查询业务流程明细
public List<ProcTaskInstance> findTasksByProcess(String id) {
return procTaskInstanceDao.findByProcessId(id);
}