本文内容主要为如下两点,由于内容有交叉,因此会放在一块儿介绍。java
关于自由跳转的内容我就再也不多说,主要介绍如何修改Activiti生成的实体的id,以达到驳回时从新生成的任务id与原先的任务id一致。(某些业务场景下可能会用到,例如某流程中A环节提交的表单与task id绑定,当环节提交又被驳回时,为保证表单内容与任务关系不变,驳回后的任务id与原先任务id要一致)spring
结合上述内容咱们就能够知道,只要在TASK_CREATED进行监听,直接在监听器中将id改成须要的值便可。理论上是这样,可是须要注意,Activiti6中历史任务实体建立是在TASK_CREATED以前的,若是你在TASK_CREATED中修改任务id,实际上历史任务实体建立时是获取不到的,这样就会致使历史任务的id与运行时任务id不一致。解决的办法也很简单,改成监听ENTITY_CREATED,判断是否时须要修改id的任务实体便可。数据库
# 是否更新数据库表 spring.activiti.databaseSchemaUpdate=true # 是否激活异步执行器 spring.activiti.asyncExecutorActivate=false # 流程历史记录登陆 spring.activiti.historyLevel=audit # 是否检查更新流程定义 spring.activiti.checkProcessDefinitions=false # 流程定义所在前缀 spring.activiti.processDefinitionLocationPrefix=classpath*:/procDef/ # 流程定义后缀 spring.activiti.processDefinitionLocationSuffixes=**.bpmn # 部署流程定义时是否生成图片 spring.activiti.createDiagramOnDeploy=false # 字体 下面内容为转成unicode的'宋体' spring.activiti.activityFontName=\u5b8b\u4f53 spring.activiti.labelFontName=\u5b8b\u4f53
@ConfigurationProperties("spring.activiti") public class ActivitiProperties { private boolean checkProcessDefinitions = true; private boolean asyncExecutorActivate = true; private boolean restApiEnabled; private String deploymentName; private String mailServerHost = "localhost"; private int mailServerPort = 1025; private String mailServerUserName; private String mailServerPassword; private String mailServerDefaultFrom; private boolean mailServerUseSsl; private boolean mailServerUseTls; private String databaseSchemaUpdate = "true"; private String databaseSchema; private boolean isDbIdentityUsed = true; private boolean isDbHistoryUsed = true; private HistoryLevel historyLevel = HistoryLevel.AUDIT; private String processDefinitionLocationPrefix = "classpath:/processes/"; private List<String> processDefinitionLocationSuffixes = Arrays.asList("**.bpmn20.xml", "**.bpmn"); private String restApiMapping = "/api/*"; private String restApiServletName = "activitiRestApi"; private boolean jpaEnabled = true; // true by default private List<String> customMybatisMappers; private List<String> customMybatisXMLMappers; private boolean createDiagramOnDeploy; private String activityFontName; private String labelFontName; //省略getter、setter }
@Configuration @EnableConfigurationProperties(ActivitiProperties.class) public class ActivitiConfig { private static final Logger logger = LoggerFactory.getLogger(ActivitiConfig.class); @Autowired private ActivitiProperties activitiProperties; @Autowired private DataSource dataSource; @Autowired private PlatformTransactionManager transactionManager; @Autowired private TaskCreatedListener taskCreatedListener; @Autowired private TaskCompletedListener taskCompletedListener; @Autowired private EntityCreatedListener entityCreatedListener; @Autowired private ResourcePatternResolver resourceLoader; @Bean public SpringProcessEngineConfiguration processEngineConfiguration() throws IOException { SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration(); configuration.setDataSource(dataSource); configuration.setTransactionManager(transactionManager); configuration.setDatabaseSchemaUpdate(activitiProperties.getDatabaseSchemaUpdate()); configuration.setAsyncExecutorActivate(activitiProperties.isAsyncExecutorActivate()); configuration.setHistory(activitiProperties.getHistoryLevel().getKey()); configuration.setCreateDiagramOnDeploy(activitiProperties.isCreateDiagramOnDeploy()); configuration.setActivityFontName(activitiProperties.getActivityFontName()); configuration.setLabelFontName(activitiProperties.getLabelFontName()); //todo 修改自动部署,当前自动部署直接搬自[activit-spring-boot] //若是checkProcessDefinitions为true,则发布新版流程定义,后续可能根据流程定义文件MD5等判断是否真正变化而进行发布 List<Resource> procDefResources = discoverProcessDefinitionResources(activitiProperties.getProcessDefinitionLocationPrefix(), activitiProperties.getProcessDefinitionLocationSuffixes(),this.activitiProperties.isCheckProcessDefinitions()); configuration.setDeploymentResources(procDefResources.toArray(new Resource[procDefResources.size()])); Map<String, List<ActivitiEventListener>> typedListeners = new HashMap<>(); typedListeners.put("ENTITY_CREATED", Collections.singletonList(entityCreatedListener)); typedListeners.put("TASK_CREATED", Collections.singletonList(taskCreatedListener)); typedListeners.put("TASK_COMPLETED", Collections.singletonList(taskCompletedListener)); configuration.setTypedEventListeners(typedListeners); return configuration; } private List<Resource> discoverProcessDefinitionResources(String prefix, List<String> suffixes, boolean checkPDs) throws IOException { if (checkPDs) { List<Resource> result = new ArrayList<>(); for (String suffix : suffixes) { String path = prefix + suffix; Resource[] resources = resourceLoader.getResources(path); if (resources != null && resources.length > 0) { CollectionUtils.mergeArrayIntoCollection(resources, result); } } if (result.isEmpty()) { logger.info("No process definitions were found for autodeployment"); } return result; } return new ArrayList<>(); } @Bean public ProcessEngineFactoryBean processEngine() throws IOException { ProcessEngineFactoryBean factoryBean = new ProcessEngineFactoryBean(); factoryBean.setProcessEngineConfiguration(processEngineConfiguration()); return factoryBean; } @Bean public RuntimeService runtimeService(ProcessEngine processEngine) { return processEngine.getRuntimeService(); } @Bean public RepositoryService repositoryService(ProcessEngine processEngine) { return processEngine.getRepositoryService(); } @Bean public TaskService taskService(ProcessEngine processEngine) { return processEngine.getTaskService(); } @Bean public HistoryService historyService(ProcessEngine processEngine) { return processEngine.getHistoryService(); } @Bean public ManagementService managementService(ProcessEngine processEngine) { return processEngine.getManagementService(); } @Bean public IdentityService identityService(ProcessEngine processEngine) { return processEngine.getIdentityService(); }
@Component public class EntityCreatedListener implements ActivitiEventListener { public void onEvent(ActivitiEvent event){ Object entity = ((ActivitiEntityEvent)event).getEntity(); if(entity instanceof TaskEntity){ TaskEntity taskEntity = (TaskEntity)entity; // 这个要改变的id值,能够在上篇文章中的SetFLowNodeAndGoCmd中设置相应流程变量便可。 String changeTaskId = (String)taskEntity.getVariable("changeTaskIdVarKey"); if(!StringUtils.isEmpty(changeTaskId)){ taskEntity.setId(changeTaskId); taskEntity.setVariable("changeTaskIdKey",""); } } } public boolean isFailOnException(){ return true; } }
咱们知道Activiti中有TASK_CREATED和TASK_COMPLETED事件,在同一个流程实例中,一个任务A若是不是最后的结束任务,那么在它完成后,一定会有一个新的任务B建立,而咱们简单理解为A为B的来源任务。(假设A是申请任务,B就时审批任务,B的处理人对当前审批不一样意要驳回时,流程就要回退到任务A。)
这样一来,咱们能够监听TASK_COMPLETED,在此时为流程设置一个变量fromTaskId,值为任务A的id,当任务A的TASK_COMPLETED结束后,就来到的了任务B的TASK_CREATED中,咱们此时从流程变量中获取fromTaskId,并将次id做为任务B的来源id持久化到一张本身建立的任务关系表中。这样后面要进行驳回时,只要经过这样关系表,立刻就能够定位到要驳回到的任务id了。segmentfault
// 关于监听器的注册看上面配置类中typedListeners部分已有 @Component public class TaskCompletedListener implements ActivitiEventListener { public void onEvent(ActivitiEvent event){ TaskEntity taskEntity = (TaskEntity)((ActivitiEntityEvent)event).getEntity(); taskEntity.setVariable("fromTaskIdVarKey", taskEntity.getId()); } public boolean isFailOnException(){ return true; } }
@Component public class TaskCreatedListener implements ActivitiEventListener { public void onEvent(ActivitiEvent event){ TaskEntity taskEntity = (TaskEntity)((ActivitiEntityEvent)event).getEntity(); String fromTaskId = (String)taskEntity.getVariable(WfVarKeyConstants.fromTaskId); if(StringUtils.isEmpty(fromTaskId)) return; xxxTaskInfo info = new xxxTaskInfo(); info.setId(taskEntity.getId()); info.setFromId(fromTaskId); //此处进行任务关系持久化,自行实现 xxxTaskInfoRepository.save(info); } public boolean isFailOnException(){ return true; } }
原本打算作一个Activiti小贴士列表,不过看篇幅已经很长了,小贴士好像也凑不齐一篇文章,并且还没人看:)
那就放到下次来讲
todo
1.Activiti命令执行模式
2.持久化过程与会话缓存(CRUD)
3.BPMN流程执行计划api