Activiti基础介绍/springboot整合
目录
activiti表介绍
大类
ACT_RE_*: ‘RE’表示repository.这个前缀的表包含了流程定义和流程静态资源(图片,规则,等等)
ACT_RU_*:’RU’表示runtime。这些运行时的表,包含流程实例,任务变量,异步任务,等运行中数据。Activiti只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。这样运行时表可以一直很小速度很快。
ACT_ID_*:’ID’表示identity。这些表包含身份信息,比如用户,组等等。
ACT_HI_*:’HI’表示history。这些表包含历史数据,比如历史流程实例,变量,任务等等。
ACT_GE_*:’GE’表示general。通用数据,用于不同场景下,如存放资源文件
资源库流程规则表
- ACT_RE_DEPLOYMENT 部署信息表
- ACT_RE_MODEL 流程设计模型部署表
- ACT_RE_PROCDEF 流程定义数据表
运行时数据库表
- ACT_RU_EXECUTION 运行时流程执行实例表
- ACT_RU_IDENTITYLINK 运行时流程人员表,主要存储任务节点与参与者的相关信息
- ACT_RU_TASK 运行时任务节点表
- ACT_RU_VARIABLE 运行时流程变量数据表
历史数据库表
- ACT_HI_ACTINST 历史节点表
- ACT_HI_ATTACHMENT 历史附件表
- ACT_HI_COMMENT 历史意见表
- ACT_HI_IDENTITYLINK 历史流程人员表
- ACT_HI_DETAIL 历史详情表,提供历史变量的查询
- ACT_HI_PROCINST 历史流程实例表
- ACT_HI_TASKINST 历史任务实例表
- ACT_HI_VARINST 历史变量表
组织结构表
- ACT_ID_GROUP 用户组信息表
- ACT_ID_INFO 用户扩展信息表
- ACT_ID_MEMBERSHIP 用户与用户组对应信息表
- ACT_ID_USER 用户信息表
这四张表是activiti用来认证的,一般项目中不会用,都是自己有实现的
activiti相关api
ProcessEngineConfiguration
流程引擎配置对象(配置数据库连接4个大配置和建表策略)
ProcessEngine
流程引擎核心对象,代码中一般都是使用它的实例
RepositoryService
仓库服务;管理规则相关的信息
RuntimeService
运行时服务;负责流程的启动,查询,执行等操作
TaskService
任务服务;管理任务的查看,接手,办理等操作。
规则管理相关
- DeploymentBuilder(ACT_RE_DEPLOYMENT与ACT_RE_PROCDEF表通过ACT_RE_DEPLOYMENT的主键关联)发布配置对象(配置发布规则文件和规则图片)
- Deployment(ACT_RE_DEPLOYMENT) 发布对象(用于描述一次发布行为)
- ProcessDefinition(ACT_RE_PROCDEF) 流程定义对象
- ActivityImpl 流程对象
流程执行相关
- ProcessInstance (流程启动信息插入ACT_HI_PROCINST表中) 流程实例,描述一个规则下一次实际的执行
- Execution 执行对象,描述一个流程当前活动的节点信息
- Task(ACT_HI_TASKINST任务表中的PROC_INT_ID对应ACT_HI_PROCINST中的PROC_INT_ID字段) 任务对象,对执行对象的一种扩展描述,针对人工任务的详细信息展示
Task对象包含:ACT_HI_TASKINST和ACT_HI_VARINST的处理
不包含子流程
- 项目中配置
@Configuration
@ComponentScan(value = {"org.activiti.rest.service"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = UserResource.class)})
public class ActivitiConfiguration {
@Autowired
DataSource dataSource;
@Autowired
PlatformTransactionManager transactionManager;
@Autowired
IdGenerator idGenerator;
@Bean
public SpringProcessEngineConfiguration processEngineConfiguration() {
SpringProcessEngineConfiguration springProcessEngineConfiguration = new SpringProcessEngineConfiguration();
springProcessEngineConfiguration.setAnnotationFontName("宋体");
springProcessEngineConfiguration.setLabelFontName("宋体");
springProcessEngineConfiguration.setActivityFontName("宋体");
springProcessEngineConfiguration.setDataSource(dataSource);
springProcessEngineConfiguration.setTransactionManager(transactionManager);
springProcessEngineConfiguration.setDbIdentityUsed(false);
springProcessEngineConfiguration.setIdGenerator(idGenerator);
/*try {
springProcessEngineConfiguration.setDeploymentResources(getResourceByClassPath("processes/"));
} catch (IOException e) {
throw new ActivitiException("can not load process file");
}*/
return springProcessEngineConfiguration;
}
public Resource[] getResourceByClassPath(String path) throws IOException {
List<Resource> resourceList = new ArrayList<>();
ClassPathResource classPathResource = new ClassPathResource(path);
File file = classPathResource.getFile();
if(file.isDirectory()){
File[] files= file.listFiles();
resourceList.addAll(Arrays.stream(files).map(fileItem->new FileSystemResource(fileItem)).collect(Collectors.toList()));
}else{
resourceList.add(new FileSystemResource(file));
}
return resourceList.toArray(new Resource[resourceList.size()]);
}
@Bean
public ProcessEngineFactoryBean processEngine() {
ProcessEngineFactoryBean processEngineFactoryBean = new ProcessEngineFactoryBean();
processEngineFactoryBean.setProcessEngineConfiguration(processEngineConfiguration());
return processEngineFactoryBean;
}
@Bean
public RestResponseFactory restResponseFactory() {
return new RestResponseFactory();
}
@Bean
public RuntimeService runtimeService() throws Exception {
return processEngine().getObject().getRuntimeService();
}
@Bean
public TaskService taskService() throws Exception {
return processEngine().getObject().getTaskService();
}
@Bean
public ManagementService managementService() throws Exception {
return processEngine().getObject().getManagementService();
}
@Bean
public IdentityService identityService() throws Exception {
return processEngine().getObject().getIdentityService();
}
@Bean
public HistoryService historyService() throws Exception {
return processEngine().getObject().getHistoryService();
}
@Bean
public FormService formService() throws Exception {
return processEngine().getObject().getFormService();
}
@Bean
public DynamicBpmnService dynamicBpmnService() throws Exception {
return processEngine().getObject().getDynamicBpmnService();
}
@Bean
public RepositoryService repositoryService() throws Exception {
return processEngine().getObject().getRepositoryService();
}
@Bean
public ContentTypeResolver contentTypeResolver() {
return new DefaultContentTypeResolver();
}
}
2.引入jar包
org.activiti:activiti-spring-boot-starter-basic:6.0.0
3.流程图
执行的操作是指定这个task的处理人是谁
<activiti:taskListener event="create" delegateExpression="${initExpertCheckUsersListener}"></activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="flow3" sourceRef="declde_submit" targetRef="engineering_check">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "true"}]]></conditionExpression>
</sequenceFlow>
<exclusiveGateway id="declde_engineering" name="判断工程部是否通过"></exclusiveGateway>
<sequenceFlow id="flow4" sourceRef="engineering_check" targetRef="declde_engineering"></sequenceFlow>
<userTask id="group_check" name="集团审核">
<extensionElements>
<activiti:taskListener event="create" delegateExpression="${initExpertCheckUsersListener}"></activiti:taskListener>
</extensionElements>
</userTask>
<sequenceFlow id="flow5" sourceRef="declde_engineering" targetRef="group_check">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "true"}]]></conditionExpression>
</sequenceFlow>
<endEvent id="cancel_end_event" name="取消提交"></endEvent>
<sequenceFlow id="flow7" sourceRef="declde_submit" targetRef="cancel_end_event">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "false"}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="flow10" sourceRef="declde_engineering" targetRef="init_expert_status_info">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "false"}]]></conditionExpression>
</sequenceFlow>
<exclusiveGateway id="declde_group" name="判断集团审核是否通过"></exclusiveGateway>
<sequenceFlow id="flow11" sourceRef="group_check" targetRef="declde_group"></sequenceFlow>
<sequenceFlow id="flow13" sourceRef="declde_group" targetRef="init_expert_status_info">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "false"}]]></conditionExpression>
</sequenceFlow>
<endEvent id="end_event" name="结束"></endEvent>
<sequenceFlow id="flow14" sourceRef="declde_group" targetRef="end_event">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "true"}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_EXPERT_STATUS_UPDATE_CHECK">
<bpmndi:BPMNPlane bpmnElement="EXPERT_STATUS_UPDATE_CHECK" id="BPMNPlane_EXPERT_STATUS_UPDATE_CHECK">
<bpmndi:BPMNShape bpmnElement="start_event" id="BPMNShape_start_event">
<omgdc:Bounds height="35.0" width="35.0" x="110.0" y="200.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="init_expert_status_info" id="BPMNShape_init_expert_status_info">
<omgdc:Bounds height="55.0" width="105.0" x="190.0" y="190.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="declde_submit" id="BPMNShape_declde_submit">
<omgdc:Bounds height="40.0" width="40.0" x="340.0" y="198.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="engineering_check" id="BPMNShape_engineering_check">
<omgdc:Bounds height="110.0" width="156.0" x="430.0" y="163.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="declde_engineering" id="BPMNShape_declde_engineering">
<omgdc:Bounds height="40.0" width="40.0" x="631.0" y="199.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="group_check" id="BPMNShape_group_check">
<omgdc:Bounds height="79.0" width="151.0" x="717.0" y="181.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="cancel_end_event" id="BPMNShape_cancel_end_event">
<omgdc:Bounds height="35.0" width="35.0" x="343.0" y="330.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="declde_group" id="BPMNShape_declde_group">
<omgdc:Bounds height="40.0" width="40.0" x="913.0" y="201.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end_event" id="BPMNShape_end_event">
<omgdc:Bounds height="35.0" width="35.0" x="998.0" y="204.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
<omgdi:waypoint x="145.0" y="217.0"></omgdi:waypoint>
<omgdi:waypoint x="190.0" y="217.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
<omgdi:waypoint x="295.0" y="217.0"></omgdi:waypoint>
<omgdi:waypoint x="340.0" y="218.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
<omgdi:waypoint x="380.0" y="218.0"></omgdi:waypoint>
<omgdi:waypoint x="430.0" y="218.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
<omgdi:waypoint x="586.0" y="218.0"></omgdi:waypoint>
<omgdi:waypoint x="631.0" y="219.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
<omgdi:waypoint x="671.0" y="219.0"></omgdi:waypoint>
<omgdi:waypoint x="717.0" y="220.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
<omgdi:waypoint x="360.0" y="238.0"></omgdi:waypoint>
<omgdi:waypoint x="360.0" y="330.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
<omgdi:waypoint x="651.0" y="199.0"></omgdi:waypoint>
<omgdi:waypoint x="651.0" y="131.0"></omgdi:waypoint>
<omgdi:waypoint x="242.0" y="131.0"></omgdi:waypoint>
<omgdi:waypoint x="242.0" y="190.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow11" id="BPMNEdge_flow11">
<omgdi:waypoint x="868.0" y="220.0"></omgdi:waypoint>
<omgdi:waypoint x="913.0" y="221.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow13" id="BPMNEdge_flow13">
<omgdi:waypoint x="933.0" y="241.0"></omgdi:waypoint>
<omgdi:waypoint x="932.0" y="294.0"></omgdi:waypoint>
<omgdi:waypoint x="242.0" y="294.0"></omgdi:waypoint>
<omgdi:waypoint x="242.0" y="245.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="flow14" id="BPMNEdge_flow14">
<omgdi:waypoint x="953.0" y="221.0"></omgdi:waypoint>
<omgdi:waypoint x="998.0" y="221.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
4.监听器
@Component("initExpertCheckUsersListener")
public class InitExpertCheckUsersListener implements TaskListener {
@Autowired
private HistoryService historyService;
@Autowired
private BpmTaskOptionRepository bpmTaskOptionRepository;
@Override
public void notify(DelegateTask delegateTask) {
List<String> candoUser = Lists.newArrayList();
// String variable = (String)delegateTask.getVariable(NormalConstants.PROGRESS.PARAMETER_KEY.RESULT);
// String processInstanceId = delegateTask.getProcessInstanceId();
String taskDefinitionKey = delegateTask.getTaskDefinitionKey();
switch (taskDefinitionKey){
case NormalConstants.PROGRESS.TASK_KEY.ENGINNER:
//todo 查找各个 流程节点 能审核的人
break;
case NormalConstants.PROGRESS.TASK_KEY.GROUP:
break;
}
//todo 暂时写能审核的人
candoUser.add("314700026");
candoUser.add("192900003");
delegateTask.addCandidateUsers(candoUser);
}
}
5.开启流程
//开启 哪个流程 哪个人的流程
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(NormalConstants.PROGRESS.EXPERT.SAVE_EXPERT, String.valueOf(expertId), variables);
6.审核任务
//查询哪个流程 哪个人(和业务挂钩)的任务
Task task = taskService.createTaskQuery().processDefinitionKey(NormalConstants.PROGRESS.EXPERT.SAVE_EXPERT).processInstanceBusinessKey(String.valueOf(expertId)).singleResult();
//设置处理结果
taskService.setVariable(task.getId(), NormalConstants.PROGRESS.PARAMETER_KEY.RESULT, NormalConstants.PROGRESS.RESULT.TRUE);
//提交任务
taskService.complete(task.getId());
7.驳回
如果是驳回的 可以在监听器里面处理 获取流程变量 如果为false那么就是驳回 可以指派任务谁可以做,我这里是如果驳回了就把之前谁做的重新指派给他
Task task = taskService.createTaskQuery().processDefinitionKey(NormalConstants.PROGRESS.EXPERT.SAVE_EXPERT).processInstanceBusinessKey(String.valueOf(expertId)).singleResult();
String taskDefinitionKey = task.getTaskDefinitionKey();
//之前这一步的审批记录
Optional<BpmTaskOption> bpmTaskOption = bpmTaskOptionRepository.findTopByProcessIdAndTaskKeyOrderByCreateTimeDesc(processId, taskDefinitionKey);
//还是将这一步的审核人 指定之前的审核的人
taskService.addCandidateUser(task.getId(), bpmTaskOption.get().getApproverUserID().toString());
Task task = taskService.createTaskQuery().processDefinitionKey(NormalConstants.PROGRESS.EXPERT.SAVE_EXPERT).processInstanceBusinessKey(String.valueOf(expertId)).singleResult();
String taskDefinitionKey = task.getTaskDefinitionKey();
//之前这一步的审批记录
Optional<BpmTaskOption> bpmTaskOption = bpmTaskOptionRepository.findTopByProcessIdAndTaskKeyOrderByCreateTimeDesc(processId, taskDefinitionKey);
//还是将这一步的审核人 指定之前的审核的人
taskService.addCandidateUser(task.getId(), bpmTaskOption.get().getApproverUserID().toString());
8.将一些信息脱离流程引擎
流程引擎关联业务表
记录 哪种流程 发起的记录 以及一些相关信息
DROP TABLE [dbo].[BPM_BUS_LINK]
GO
CREATE TABLE [dbo].[BPM_BUS_LINK] (
[ID] varchar(64) NOT NULL ,
[PROCESS_ID] varchar(64) NOT NULL ,
[PROCESS_DEF_ID] varchar(64) NOT NULL ,
[BUS_ID] int NOT NULL ,
[START_USER_NAME] varchar(50) NULL ,
[START_USER_ID] int NULL ,
[BIZ_CODE] varchar(64) NULL ,
[STATUS] int NULL ,
[BPM_NAME] varchar(60) NULL ,
[CREATE_TIME] datetime NULL ,
[END_TIME] datetime NULL ,
[BUS_NAME] varchar(60) NULL
)
@ApiModel(value = "流程引擎关联业务")
@Table(name = "BPM_BUS_LINK")
public class BpmBusLink {
@Id
@Column(name = "ID", nullable = false)
@GenericGenerator(name = "bus-uuid", strategy = "uuid")
@GeneratedValue(generator = "bus-uuid")
private String id;
@Column(name = "PROCESS_ID")
@ApiModelProperty(value = "流程实例id")
private String processId;
@Column(name = "PROCESS_DEF_ID")
@ApiModelProperty(value = "流程定义id")
private String processDefId;
@Column(name = "BUS_ID")
@ApiModelProperty(value = "业务主键")
private Integer busId;
@Column(name = "BUS_NAME")
@ApiModelProperty(value = "业务人名称")
private String busName;
@Column(name = "START_USER_NAME")
@ApiModelProperty(value = "发起人姓名")
private String startUserName;
@Column(name = "START_USER_ID")
@ApiModelProperty(value = "发起人id")
private Integer startUserId;
@Column(name = "BIZ_CODE")
@ApiModelProperty(value = "流程区分")
private String bizCode;
@Column(name = "STATUS")
@ApiModelProperty(value = "当前状态")
private Integer status;
@Column(name = "BPM_NAME")
@ApiModelProperty(value = "流程简介")
private String bpmName;
@Column(name = "CREATE_TIME")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "流程发起时间")
private LocalDateTime createTime;
@Column(name = "END_TIME")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "流程结束时间")
private LocalDateTime endTime;
流程引擎审批记录表
记录 那种流程 每个task 处理信息
DROP TABLE [dbo].[BPM_TASK_OPINION]
GO
CREATE TABLE [dbo].[BPM_TASK_OPINION] (
[ID] varchar(64) NOT NULL ,
[PROCESS_ID] varchar(64) NOT NULL ,
[TASK_ID] varchar(64) NOT NULL ,
[TASK_KEY] varchar(64) NULL ,
[TASK_NAME] varchar(255) NULL ,
[TASK_TOKEN] varchar(255) NULL ,
[APPROVER_USER_NAME] varchar(50) NULL ,
[APPROVER_USER_ID] int NULL ,
[APPROVER_USER_OPTION] varchar(255) NULL ,
[APPROVER_STATUS] int NULL ,
[CREATE_TIME] datetime NULL ,
[APPROVER_TIME] datetime NULL ,
[BIZ_CODE] varchar(64) NULL ,
[BUS_ID] int NULL
)
@ApiModel(value = "流程任务审批记录")
@Table(name = "BPM_TASK_OPINION")
public class BpmTaskOption {
@Id
@Column(name = "ID", nullable = false)
@GenericGenerator(name = "bus-uuid", strategy = "uuid")
@GeneratedValue(generator = "bus-uuid")
private String id;
@Column(name = "PROCESS_ID")
@ApiModelProperty(value = "流程实例id")
private String processId;
@Column(name = "TASK_ID")
@ApiModelProperty(value = "任务id")
private String taskId;
@Column(name = "TASK_KEY")
@ApiModelProperty(value = "任务定义key")
private String taskKey;
@Column(name = "TASK_NAME")
@ApiModelProperty(value = "任务Name")
private String taskName;
@Column(name = "TASK_TOKEN")
@ApiModelProperty(value = "任务令牌")
private String taskToken;
@Column(name = "APPROVER_USER_NAME")
@ApiModelProperty(value = "审批人名称")
private String approverUserName;
@Column(name = "APPROVER_USER_ID")
@ApiModelProperty(value = "审批人ID")
private Integer approverUserID;
@Column(name = "APPROVER_USER_OPTION")
@ApiModelProperty(value = "审批人意见")
private String approverUserOPTION;
/**
* 1 发起 3 同意 6驳回
*/
@Column(name = "APPROVER_STATUS")
@ApiModelProperty(value = "审批状态")
private Integer approverStatus;
@Column(name = "CREATE_TIME")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "创建时间")
private LocalDateTime createTime;
@Column(name = "APPROVER_TIME")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
@ApiModelProperty(value = "审批时间")
private LocalDateTime approverTime;
@Column(name = "BIZ_CODE")
@ApiModelProperty(value = "流程区分")
private String bizCode;
@Column(name = "BUS_ID")
@ApiModelProperty(value = "业务主键")
private Integer busId;
总结:
到目前为止只是简单的没有子流程的使用,一些流程变量,流程实例,流程定义概念还需要理解