SpringBoot整合Activiti7(二)

之前只是一个springboot整合activiti的demo,在真正的开发中可能还需使用到它的其他api

Activiti核心api有六个:

RepositoryService 管理流程定义
RuntimeService 执行管理,包括启动、推进、删除流程实例等操作
TaskService 任务管理
HistoryService 历史管理(执行完的数据的管理)
IdentityService 组织机构管理
FormService 一个可选择的服务
ManagerService 管理服务

一、RepositoryService

1、部署流程

RepositoryService是Activiti流程引擎的仓库服务类,包含流程部署的两个文件:bpmn文件和流程图

1
2
3
4
Deployment deployment = repositoryService.createDeployment()
.name("我的流程") //流程部署名
.addClasspathResource("processes/test.bpmn")//流程部署的bpmn文件,在classpath下新建processes文件夹,里面的流程会自动部署
.deploy();//部署

上面代码是如何部署一个流程通过repositoryService的createDeployment方法创建部署对象,指定资源文件,最后.deploy部署

2、激活、挂起流程实例

1
2
3
4
5
6
7
8
9
//通过流程部署ID来挂起流程
repositoryService.suspendProcessDefinitionById("defId",true,null);
//通过流程部署的key来挂起流程
repositoryService.suspendProcessDefinitionByKey("key",true,null);

//通过流程部署的key激活流程
repositoryService.activateProcessDefinitionByKey("key",true,null);
//通过流程部署的ID激活流程
repositoryService.activateProcessDefinitionById("id",true,null);

在上面的四个方法中,第二个参数表示是否挂起或激活流程实例,第三个参数则是激活挂起的时间

3、查询流程定义

1
Deployment deployment = repositoryService.createDeploymentQuery().processDefinitionKey("key").singleResult();

在activiti中进行查询操作,其均为链式调用,如上方法可以.singleResult()查询一条记录,也可以.list()查询一个列表

二、RuntimeService

RuntimeService主要用于流程的启用,推进,删除等操作

1、查询

1
runtimeService.createProcessInstanceQuery().processInstanceId("id").singleResult();

2、启用流程

1
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("key"null);

在通过调用RuntimeService中的start***方法,就可以启动一个流程实例,在上方法中,第一个参数为启动流程的key,第二个参数为一个map,其中可能包含一些流程变量及流程批注等信息

3、判断流程实例是否结束

1
2
3
4
5
6
7
8
9
10
11

ProcessInstance processInstance = processEngine.getRuntimeService()//正在执行的流程
.createProcessInstanceQuery()//创建流程实例查询对象
.processInstanceId("流程实例ID")
.singleResult();
//如果为空,流程已结束
if(processInstance==null){
System.out.println("流程已结束");
}else{
System.out.println("流程未结束");
}

以上代码就是通过流程实例的id查询流程实例,如果为null,说明整个流程已经走完了。如果不为null,表示还在走

三、TaskService

TaskService用于任务相关的操作

1、查询任务

1
List<Task> user = taskService.createTaskQuery().taskAssignee("user").list();

上面的方法为查询‘user’用户当前的所有待办任务

2、完成任务

1
taskService.complete("id",null);

完成任务只需调用complete方法即可完成任务,方法中的第一个参数为要完成任务的taskid,第二个参数为一个map,其中包含流程变量信息

3、添加批注

1
taskService.addComment("批注1","批注2");

添加任务批注,使用addComment方法,里面可传入多个参数

4、查询当前任务的批注信息

1
2
3
4
5
6
7
//通过任务id查询到当前任务       
Task task = taskService.createTaskQuery().taskId(id).singleResult();


String processInstanceId = task.getProcessInstanceId();
//通过当前任务的流程实例id获取批注信息
List<Comment> comments = taskService.getProcessInstanceComments(processInstanceId);

四、HistoryService

HistoryService用于历史信息的管理

1、查询历史信息

1
2
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processDefinitionKey("key").list();
HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery().singleResult();

查询历史任务信息

五、查看流程图

查看流程图功能需要单独引入:

1
2
3
4
5
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-image-generator</artifactId>
<version>6.0.0</version>
</dependency>

使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public InputStream queryTaskCoordinateByTaskId(String taskId) {
//1、先通过任务id获取到任务对象
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
//2、获取到流程部署id和流程实例id
String processDefinitionId = task.getProcessDefinitionId();
String processInstanceId = task.getProcessInstanceId();
//3、通过流程实例id获取到流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//4、通过流程部署id获取到bpmn文件对象
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
//5、通过executionId获取到节点信息
String executionId=processInstance.getId();
List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
//得到已经走过的节点的id集合
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
List<HistoricActivityInstance> historicActivityInstanceList = historicActivityInstanceQuery.processInstanceId(processInstanceId).list();
for(HistoricActivityInstance hi:historicActivityInstanceList) {
String taskKey=hi.getActivityId();
activeActivityIds.add(taskKey);
}
ProcessDiagramGenerator diagramGenerator = processEngine.getProcessEngineConfiguration().getProcessDiagramGenerator();
//注意要设置字体否则图片中文会出现乱码
return diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, Collections.<String>emptyList(), "宋体", "宋体", "宋体", null, 1.0);

}

图片文字乱码问题

在生成的流程图中,很有可能会出现图片中的中文变成方块的问题:

解决方法

1、在生成图片时设置

1
diagramGenerator.generateDiagram(bpmnModel, "png", activeActivityIds, Collections.<String>emptyList(), "宋体", "宋体", "宋体", null, 1.0);

2、在配置类中配置

1
2
3
4
5
6
7
8
9
10
@Component
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {
@Override
public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
//配置流程图文字乱码问题。。。。。。巨坑
processEngineConfiguration.setActivityFontName("宋体");
processEngineConfiguration.setAnnotationFontName("宋体");
processEngineConfiguration.setLabelFontName("宋体");
}
}

六、设置代理人

在Activiti中提供了三种设置代理人的方式:

1、直接在bpmn文件中设置

在创建流程图时,在图中设置代理人,但这种方法拓展性不好,不建议使用

2、使用UEL表达式动态设置

在创建流程图设置代理人的时候,不需要直接写死,而是用${user}代替,在启动流程的时候:

1
2
3
Map<String,Object> map = new HashMap<>();
map.put("user",hr.getId());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, id, map);

需要注意的是,这里map中方的是一个流程变量,这里必须要与uel表达式中的变量一致

3、使用监听类的方式

使用监听类,在创建bpmn文件的时候,只需要在相应的节点创建一个监听,类名就是我们自己创建的监听类,这样在流程被创建或启动时可以进行监听

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Component
public class LeaveBillActivitiListener implements TaskListener {

@Override
public void notify(DelegateTask delegateTask) {

Hr hr = UserInfoUtils.getUserInfo();
HrService hrService = SpringUtil.getObject(HrService.class);

Hr lead = hrService.processBoss(hr.getId());
delegateTask.setAssignee(String.valueOf(lead.getLeadid()));

}
}

需要注意的是,在我们实现TaskListener接口后,会出现java bean无法实例化的情况,这种情况需要我们手动获取bean

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Component
public class SpringUtil implements ApplicationContextAware {

/**
* 当前IOC
*
*/
private static ApplicationContext applicationContext;

/**
* 设置applicationContext
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}

public static <T> T getObject(Class<T> clazz){
return applicationContext.getBean(clazz);
}
}