Activiti工作流入门详解完整教程
BPMN工作流的基本概念!详解工作流框架Activiti
BPMN⼯作流的基本概念!详解⼯作流框架Activiti⼯作流⼯作流简介⼯作流(Workflow): ⼯作流就是通过计算机技术对业务流程进⾏⾃动化管理。
实现多个参与者按照预定的流程去⾃动执⾏业务流程。
定义: 通过计算机对业务流程⾃动化执⾏管理主要解决的是: 使在多个参与者之间按照某种预定义的规则⾃动进⾏传递⽂档,信息或任务的过程.从⽽实现某个预期的业务⽬标,或者促使此⽬标的实现⼯作流管理系统的⽬标:管理⼯作的流程以确保⼯作在正确的时间被期望的⼈员所执⾏在⾃动化进⾏的业务过程中插⼊⼈⼯的执⾏和⼲预⼯作流框架:Activiti,JBPM,OSWorkFlow,WorkFlow⼯作流框架底层需要有数据库提供⽀持⼯作流术语⼯作流引擎ProcessEngine对象: 这是Activiti⼯作的核⼼.负责⽣成流程运⾏时的各种实例及数据,监控和管理流程的运⾏BPM业务流程管理:是⼀种以规范化的构造端到端的卓越业务流程为中⼼,以持续的提⾼组织业务绩效为⽬的的系统化⽅法常见商业管理教育如EMBA,MBA等均将BPM包含在内BPMN业务流程建模与标注:这些图如何组合成⼀个业务流程图(Business Process Diagram)讨论BPMN的各种的⽤途:包括以何种精度来影响⼀个流程图中的模型BPMN作为⼀个标准的价值BPMN未来发展的远景流对象⼀个业务流程图有三个流对象的核⼼元素事件⼀个事件⽤圆圈来描述,表⽰⼀个业务流程期间发⽣的东西事件影响流程的流动.⼀般有⼀个原因(触发器)或⼀个影响(结果)基于它们对流程的影响,有三种事件:开始事件,中间事件,终⽌事件活动⽤圆⾓矩形表⽰,⼀个流程由⼀个活动或多个活动组成条件条件⽤菱形表⽰,⽤于控制序列流的分⽀与合并。
可以作为选择,包括路径的分⽀与合并内部的标记会给出控制流的类型Activiti开源⼯作流框架Activiti简介Activiti是⼀个开源的⼯作流引擎,它实现了BPMN 2.0规范,可以发布设计好的流程定义,并通过api进⾏流程调度Activiti 作为⼀个遵从 Apache 许可的⼯作流和业务流程管理开源平台,其核⼼是基于Java的超快速,超稳定的 BPMN2.0 流程引擎,强调流程服务的可嵌⼊性和可扩展性,同时更加强调⾯向业务⼈员Activiti 流程引擎重点关注在系统开发的易⽤性和轻量性上.每⼀项BPM业务功能Activiti流程引擎都以服务的形式提供给开发⼈员.通过使⽤这些服务,开发⼈员能够构建出功能丰富,轻便且⾼效的BPM应⽤程序Activiti服务结构Activiti系统服务结构图核⼼类:ProcessEngine: 流程引擎的抽象,可以通过此类获取需要的所有服务服务类:XxxService: 通过ProcessEngine获取,Activiti将不同⽣命周期的服务封装在不同Service中,包括定义,部署,运⾏.通过服务类可获取相关⽣命周期中的服务信息RepositoryServiceRepository Service提供了对repository的存取服务Activiti中每⼀个不同版本的业务流程的定义都需要使⽤⼀些定义⽂件,部署⽂件和⽀持数据(例如BPMN2.0XML⽂件,表单定义⽂件,流程定义图像⽂件等),这些⽂件都存储在Activiti内建的Repository中RuntimeServiceRuntime Service提供了启动流程,查询流程实例,设置获取流程实例变量等功能.此外它还提供了对流程部署,流程定义和流程实例的存取服务TaskServiceTask Service提供了对⽤户Task和Form相关的操作.它提供了运⾏时任务查询,领取,完成,删除以及变量设置等功能HistoryServiceHistory Service⽤于获取正在运⾏或已经完成的流程实例的信息,与Runtime Service中获取的流程信息不同,历史信息包含已经持久化存储的永久信息,并已经被针对查询优化FormService使⽤Form Service可以存取启动和完成任务所需的表单数据并且根据需要来渲染表单Activiti中的流程和状态Task均可以关联业务相关的数据IdentityServiceIdentity Service提供了对Activiti系统中的⽤户和组的管理功能Activiti中内置了⽤户以及组管理的功能,必须使⽤这些⽤户和组的信息才能获取到相应的TaskManagementServiceManagement Service提供了对Activiti流程引擎的管理和维护功能这些功能不在⼯作流驱动的应⽤程序中使⽤,主要⽤于 Activiti 系统的⽇常维护核⼼业务对象:org.activiti.engine.impl.persistence.entity包下的类,包括Task,ProcessInstance,Execution等根据不同职责实现相应接⼝的⽅法(如需要持久化则继承PersistentObject接⼝),与传统的实体类不同Activiti组件Activiti上下⽂组件Context: ⽤来保存⽣命周期⽐较长,全局性的信息,类似Application.主要包括如下三类:CommandContext: 命令上下⽂-保存每个命令必要的资源,如持久化需要的sessionProcessEngineConfigurationImpl: 流程引擎相关配置信息-整个引擎全局的配置信息.如数据源DataSource等.该对象为单例,在流程引擎创建的时候初始化ExecutionContext: 持有ExecutionEntity对象持久化组件:Activiti使⽤mybatis作OR映射,并在此基础上增加设计了⾃⼰的持久化框架在流程引擎创建时初始化,顶层接⼝Session,SessionFactorySession有两个实现类:DbSqlSession: 负责sql表达式的执⾏AbstractManager: 负责对象的持久化操作SessionFactory有两个实现类:DbSqlSessionFactory: 负责DbSqlSession相关操作GenericManagerFactory: 负责AbstractManager相关操作Event-Listener组件:Activiti允许客户代码介⼊流程执⾏,提供了事件监听组件监听的事件类型:TaskListenerJavaDelegateExpressionExecutionListenerProcessEngineConfigurationImpl持有DelegateInterceptor的某个实例,⽅便调⽤handleInvocation Cache组件DbSqlSession中有cache的实现Activiti基于List和Map来做缓存:如查询时先查缓存,没有则直接查询并放⼊缓存异步执⾏组件Activiti可以执⾏任务,JobExecutor为其核⼼类,JobExecutor包含三个主要属性:JobAcquisitionThreadBlockingQueueThreadPoolExecutor⽅法ProcessEngines在引擎启动时调⽤JobExecutor.start,JobAcquisitionThread 线程即开始⼯作,其run⽅法不断循环执⾏AcquiredJobs中的job,执⾏⼀次后线程等待⼀定时间直到超时或者JobExecutor.jobWasAdded⽅法,因为有新任务⽽被调⽤。
activiti入门
activiti⼊门最近项⽬有个⼯作流的需求,从头开始学⼀下activiti,记录⼀些问题。
1.去官⽹下载activiti7.0或者使⽤maven下载,并在idea中下载activiBPM流程插件2.创建⼀个普通的maven依赖,添加activiti、mysql、mybatis、连接池、junit等jar包。
推荐使⽤相关配置如下:<properties><activiti.version>7.0.0.Beta1</activiti.version></properties><dependencies><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>${activiti.version}</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring</artifactId><version>${activiti.version}</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-converter</artifactId><version>${activiti.version}</version></dependency><!--<dependency>--><!--<groupId>org.activiti</groupId>--><!--<artifactId>activiti-json-converte</artifactId>--><!--<version>${activiti.version}</version>--><!--</dependency>--><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-layout</artifactId><version>${activiti.version}</version></dependency><!--<dependency>--><!--<groupId>org.activiti</groupId>--><!--<artifactId>activiti-cloud-services</artifactId>--><!--<version>${activiti.version}</version>--><!--</dependency>--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.46</version></dependency><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.4</version></dependency><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>1.2.17</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>1.7.32</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.28</version></dependency></dependencies>有两个依赖下不下来,先不管它,后⾯再填坑3.在resource下配置log4j,activiti.cfg.xml配置⽂件(<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"/><!--数据库⽤户名和密码--><property name="jdbcUsername" value="root"/><property name="jdbcPassword" value="root"/><!--activiti数据库表在⽣成时的策略--><!--true表⽰数据库中存在相应的表就直接使⽤,不存在则创建--><property name="databaseSchemaUpdate" value="true"/></bean>),注意bean的id和配置⽂件的名称都不能修改。
Activiti6.0工作流使用说明文档V1.0
Activiti工作流使用说明文档V1.02019年8月9日目录一、模型设计器 (4)1.1任务 (5)1.1.1 用户任务 (5)1.1.2 服务任务 (5)1.1.3 脚本任务 (6)1.1.4 业务规则任务 (7)1.1.5 接收任务 (7)1.1.6 手动任务 (7)1.1.7 邮件任务 (8)1.1.8 Camel任务 (8)1.1.9 Mule任务 (8)1.1.10 决策任务 (9)1.2构造 (10)1.2.1 子流程 (10)1.2.2 事件子流程 (11)1.3泳道列表 (11)1.4分支 (12)1.4.1 排他分支 (12)1.4.2 并行分支 (12)1.4.3 包容分支 (13)1.4.4 事件分支 (13)1.5事件 (14)1.5.1 定时器事件 (14)1.5.2 信号事件 (14)1.5.3 消息事件 (16)1.5.4 错误事件 (16)1.5.5 边界事件 (17)1.5.6 中间事件 (18)1.5.7 开始事件 (18)1.5.8 结束事件 (18)1.6属性元素 (18)1.6.1 异步 (18)1.6.2 排他 (19)1.6.3 补偿 (19)1.6.4 中断任务 (20)1.6.5 分配 (21)1.6.6 到期时间 (22)1.6.7 表单 (22)1.6.8 表达式 (24)1.6.9 多实例 (25)1.7监听器配置 (28)1.7.1 执行监听器 (29)1.7.2 任务监听器 (30)1.7.3 事件监听器 (32)1.7.4 全局事件监听器 (33)二、workflow-service (34)2.1数据更新逻辑 (34)2.2方法表达式配置 (35)2.3自定义外置表单 (36)2.4事件监听器配置 (37)2.5方法调用说明 (37)三、常见问题 (37)一、模型设计器模型设计器项目qqdznyyglpt-workflow-designer主要完成自定义流程、表单设计,可以在模型设计器中完成整个功能的流转,但仅限与admin(密码默认为test)相同租户的用户可使用全功能,其他租户用户登录后只有流程设计、表单配置、决策表配置功能,无法在设计器进行流程执行。
Activiti演示PPT
/**查询当前人的个人任务*/ @Test public void findMyPersonalTask(){ String assignee = “张三"; List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的 Service .createTaskQuery()//创建任务查询对象 .taskAssignee(assignee)//指定个人任务查询,指定办理人 .list(); if(list!=null && list.size()>0){ for(Task task:list){ System.out.println("任务ID:"+task.getId()); System.out.println("任务名称:"+task.getName()); System.out.println("任务的创建时间:"+task.getCreateTime()); System.out.println("任务的办理人:"+task.getAssignee()); System.out.println("流程实例ID:"+task.getProcessInstanceId()); System.out.println("执行对象ID:"+task.getExecutionId()); System.out.println("流程定义ID:"+task.getProcessDefinitionId()); System.out.println("############################################"); } } }
Activiti使用步骤(IDEA)
Activiti使⽤步骤(IDEA)⼀.Activiti7体系架构通过加载activiti.cfg.xml⽂件得到ProcessEngineConfiguration对象,通过ProcessEngineConfiguration对象可以得到ProcessEngine对象得到该对象后,可以通过流程引擎对象ProcessEngine来得到各种Service,每⼀种Service接⼝有每个⽤途RepositoryService activiti 的资源管理类RuntimeService activiti 的流程运⾏管理类TaskService activiti 的任务管理类HistoryService activiti 的历史管理类ManagerService activiti 的引擎管理类⼆.Activiti使⽤步骤1.流程定义使⽤Activiti Designer⼯具创建流程图新建⼀个BPMNFile流程图,可更改该流程图的ID 和每个任务环节的执⾏⼈,流程图就是⼀个xml⽂件,每⼀个流程需要⽣成⼀张流程图保存, ⾸先将.bpmn⽂件改为.xml⽂件 然后右键该xml⽂件Diagrams--->show BPMN 2.0 Designer就能⽣成⼀张流程图, 将流程图导出保存到项⽬对应⽬录即可,然后将xml改回bpmn即可2.流程部署需要将流程部署到Activiti当中,代表当前有该流程/*** 流程部署* `act_ge_bytearray` 流程定义的资源信息,包含bpmn和png流程⽂件信息* `act_re_deployment` 流程部署信息,包含流程名称,ID,Key等* `act_re_procdef` 流程定义信息*/@Testpublic void deployment() {//获取ProcessEngine对象默认配置⽂件名称:activiti.cfg.xml 并且configuration的Bean实例ID为processEngineConfiguration ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//获取RepositoryService对象进⾏流程部署RepositoryService repositoryService = processEngine.getRepositoryService();//进⾏部署,将对应的流程定义⽂件⽣成到数据库当中,作为记录进⾏保存Deployment deployment = repositoryService.createDeployment().addClasspathResource("bpmn/holiday.bpmn") //加载流程⽂件.addClasspathResource("bpmn/holiday.png").name("请假流程") //设置流程名称.key("holidayKey").deploy(); //部署//输出部署信息System.out.println("流程名称:" + deployment.getName());System.out.println("流程ID:" + deployment.getId());System.out.println("流程Key:" + deployment.getKey());}3.创建流程实例流程定义相当于类流程实例相当于类的实例(对象)/*** 启动流程实例* `act_hi_actinst` 已开始和执⾏完毕的活动信息* `act_hi_identitylink` 历史参与者信息* `act_hi_procinst` 流程实例信息* `act_hi_taskinst` 历史任务实例* act_ru_execution 任务执⾏信息* act_ru_identitylink 当前任务参与者* `act_ru_task` 任务信息*/@Testpublic void startInstance() {//获取ProcessEngine对象默认配置⽂件名称:activiti.cfg.xml 并且configuration的Bean实例ID为processEngineConfiguration ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//获取到RuntimeService对象RuntimeService runtimeService = processEngine.getRuntimeService();//创建流程实例ProcessInstance holiday = runtimeService.startProcessInstanceByKey("myProcess_1");//红字是流程图的key值//输出实例信息System.out.println("流程部署ID:" + holiday.getDeploymentId());System.out.println("流程实例ID:" + holiday.getId());System.out.println("活动ID:" + holiday.getActivityId());}执⾏效果:`act_hi_actinst` 已开始和执⾏完毕的活动信息`act_hi_identitylink` 历史参与者信息`act_hi_procinst` 流程实例信息`act_hi_taskinst` 历史任务实例* act_ru_execution 任务执⾏信息* act_ru_identitylink 当前任务参与者* `act_ru_task` 任务信息4.⽤户查询代办任务/*** 查看代办任务*/@Testpublic void getTask() {//获取ProcessEngine对象默认配置⽂件名称:activiti.cfg.xml 并且configuration的Bean实例ID为processEngineConfigurationProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//获取⼀个TaskService对象TaskService taskService = processEngine.getTaskService();//查询代办业务 createTaskQuery查询任务 taskCandidateOrAssigned查询任务执⾏者 processDefinitionKey:查询流程/*** taskCandidateOrAssigned匹配规则:1.Assigned 2.配置bpmn⽂件中定义的值* taskAssignee匹配规则:1.Assigned*//*List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned("lisi").processDefinitionKey("holiday").list();*/List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").processDefinitionKey("myProcess_1").list();//分页:List<Task> list = taskService.createTaskQuery().taskAssignee("zhangsan").processDefinitionKey("holiday").listPage(i,j);for (Task task : list) {System.out.println("任务名称:" + task.getName());System.out.println("任务执⾏⼈:" + task.getAssignee());System.out.println("任务ID:" + task.getId());System.out.println("流程实例ID:" + task.getProcessInstanceId());}}5.⽤户进⾏任务处理/*** 任务处理:当所有任务处理完毕,对应当前流程实例信息删除,但是可以在历史中查看到该信息*/@Testpublic void completeTask() {//获取ProcessEngine对象默认配置⽂件名称:activiti.cfg.xml 并且configuration的Bean实例ID为processEngineConfiguration ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//获取⼀个TaskService对象TaskService taskService = processEngine.getTaskService();//任务处理plete("2505");}先查看代办任务,再调⽤ plete(); ⽅法传⼊代办ID任务就被处理掉了上⼀步zhangsan被处理掉了,没有了代办任务,再查找zhangsan的下⼀步,lisi的代办任务发现lisi有了代办任务,数据库表也更新了处理完所有流程后ru表就为空了,数据都保存到了hi历史表6.流程结束7.当业务流程结束后通过历史可以查看到已经⾛完的流程/*** 查看历史任务*/@Testpublic void getHistory() {//获取ProcessEngine对象默认配置⽂件名称:activiti.cfg.xml 并且configuration的Bean实例ID为processEngineConfiguration ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();//获取HistoryService接⼝HistoryService historyService = processEngine.getHistoryService();//获取历史任务HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();//获取指定流程实例的任务historicActivityInstanceQuery.processInstanceId("2501");//获取任务列表List<HistoricActivityInstance> list = historicActivityInstanceQuery.list();for (HistoricActivityInstance ai : list) {System.out.println("任务节点ID:"+ai.getActivityId());System.out.println("任务节点名称:"+ai.getActivityName());System.out.println("流程实例ID信息:"+ai.getProcessDefinitionId());System.out.println("流程实例ID信息:"+ai.getProcessInstanceId());System.out.println("==============================");}}。
Activiti之流程通过、驳回、会签、转办、中止、挂起等核心操作封装(Activiti5.9)
Activiti之流程通过、驳回、会签、转办、中⽌、挂起等核⼼操作封装(Activiti5.9)/rosten/article/details/383002671package com.famousPro.process.service.impl;23import java.util.ArrayList;4import java.util.HashMap;5import java.util.List;6import java.util.Map;78import org.activiti.engine.FormService;9import org.activiti.engine.HistoryService;10import org.activiti.engine.RepositoryService;11import org.activiti.engine.RuntimeService;12import org.activiti.engine.TaskService;13import org.activiti.engine.history.HistoricActivityInstance;14import org.activiti.engine.impl.RepositoryServiceImpl;15import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;16import org.activiti.engine.impl.persistence.entity.TaskEntity;17import org.activiti.engine.impl.pvm.PvmTransition;18import org.activiti.engine.impl.pvm.process.ActivityImpl;19import org.activiti.engine.impl.pvm.process.ProcessDefinitionImpl;20import org.activiti.engine.impl.pvm.process.TransitionImpl;21import org.activiti.engine.runtime.ProcessInstance;22import org.activiti.engine.task.Task;2324import mon.service.impl.BaseServiceImp;25import mon.util.IDGenerator;26import mon.util.StringUtil;27import com.famousPro.process.service.ProcessCoreService;28import com.famousPro.process.service.ProcessOtherService;2930/**31 * 流程操作核⼼类<br>32 * 此核⼼类主要处理:流程通过、驳回、会签、转办、中⽌、挂起等核⼼操作<br>33 *34 * @author wangfuwei35 *36*/37public class ProcessCoreServiceImpl extends BaseServiceImp implements38 ProcessCoreService {39protected RepositoryService repositoryService;4041protected RuntimeService runtimeService;4243protected TaskService taskService;4445protected FormService formService;4647protected HistoryService historyService;4849protected ProcessOtherService processOtherService;5051/**52 * 根据当前任务ID,查询可以驳回的任务节点53 *54 * @param taskId55 * 当前任务ID56*/57public List<ActivityImpl> findBackAvtivity(String taskId) throws Exception {58 List<ActivityImpl> rtnList = null;59if (processOtherService.isJointTask(taskId)) {// 会签任务节点,不允许驳回60 rtnList = new ArrayList<ActivityImpl>();61 } else {62 rtnList = iteratorBackActivity(taskId, findActivitiImpl(taskId,63null), new ArrayList<ActivityImpl>(),64new ArrayList<ActivityImpl>());65 }66return reverList(rtnList);67 }6869/**70 * 审批通过(驳回直接跳回功能需后续扩展)71 *72 * @param taskId73 * 当前任务ID74 * @param variables75 * 流程存储参数78public void passProcess(String taskId, Map<String, Object> variables)79throws Exception {80 List<Task> tasks = taskService.createTaskQuery().parentTaskId(taskId)81 .taskDescription("jointProcess").list();82for (Task task : tasks) {// 级联结束本节点发起的会签任务83 commitProcess(task.getId(), null, null);84 }85 commitProcess(taskId, variables, null);86 }8788/**89 * 驳回流程90 *91 * @param taskId92 * 当前任务ID93 * @param activityId94 * 驳回节点ID95 * @param variables96 * 流程存储参数97 * @throws Exception98*/99public void backProcess(String taskId, String activityId,100 Map<String, Object> variables) throws Exception {101if (StringUtil.isNull(activityId)) {102throw new Exception("驳回⽬标节点ID为空!");103 }104105// 查询本节点发起的会签任务,并结束106 List<Task> tasks = taskService.createTaskQuery().parentTaskId(taskId) 107 .taskDescription("jointProcess").list();108for (Task task : tasks) {109 commitProcess(task.getId(), null, null);110 }111112// 查找所有并⾏任务节点,同时驳回113 List<Task> taskList = findTaskListByKey(findProcessInstanceByTaskId( 114 taskId).getId(), findTaskById(taskId).getTaskDefinitionKey());115for (Task task : taskList) {116 commitProcess(task.getId(), variables, activityId);117 }118 }119120/**121 * 取回流程122 *123 * @param taskId124 * 当前任务ID125 * @param activityId126 * 取回节点ID127 * @throws Exception128*/129public void callBackProcess(String taskId, String activityId)130throws Exception {131if (StringUtil.isNull(activityId)) {132throw new Exception("⽬标节点ID为空!");133 }134135// 查找所有并⾏任务节点,同时取回136 List<Task> taskList = findTaskListByKey(findProcessInstanceByTaskId( 137 taskId).getId(), findTaskById(taskId).getTaskDefinitionKey());138for (Task task : taskList) {139 commitProcess(task.getId(), null, activityId);140 }141 }142143/**144 * 中⽌流程(特权⼈直接审批通过等)145 *146 * @param taskId147*/148public void endProcess(String taskId) throws Exception {149 ActivityImpl endActivity = findActivitiImpl(taskId, "end");150 commitProcess(taskId, null, endActivity.getId());151 }152153/**154 * 会签操作155 *156 * @param taskId157 * 当前任务ID158 * @param userCodes159 * 会签⼈账号集合162public void jointProcess(String taskId, List<String> userCodes)163throws Exception {164for (String userCode : userCodes) {165 TaskEntity task = (TaskEntity) taskService.newTask(IDGenerator166 .generateID());167 task.setAssignee(userCode);168 task.setName(findTaskById(taskId).getName() + "-会签");169 task.setProcessDefinitionId(findProcessDefinitionEntityByTaskId(170 taskId).getId());171 task.setProcessInstanceId(findProcessInstanceByTaskId(taskId)172 .getId());173 task.setParentTaskId(taskId);174 task.setDescription("jointProcess");175 taskService.saveTask(task);176 }177 }178179/**180 * 转办流程181 *182 * @param taskId183 * 当前任务节点ID184 * @param userCode185 * 被转办⼈Code186*/187public void transferAssignee(String taskId, String userCode) {188 taskService.setAssignee(taskId, userCode);189 }190191/**192 * ***************************************************************************************************************************************************<br>193 * ************************************************以下为流程会签操作核⼼逻辑******************************************************************************<br> 194 * ***************************************************************************************************************************************************<br>195*/196197/**198 * ***************************************************************************************************************************************************<br>199 * ************************************************以上为流程会签操作核⼼逻辑******************************************************************************<br> 200 * ***************************************************************************************************************************************************<br>201*/202203/**204 * ***************************************************************************************************************************************************<br>205 * ************************************************以下为流程转向操作核⼼逻辑******************************************************************************<br> 206 * ***************************************************************************************************************************************************<br>207*/208209/**210 * @param taskId211 * 当前任务ID212 * @param variables213 * 流程变量214 * @param activityId215 * 流程转向执⾏任务节点ID<br>216 * 此参数为空,默认为提交操作217 * @throws Exception218*/219private void commitProcess(String taskId, Map<String, Object> variables,220 String activityId) throws Exception {221if (variables == null) {222 variables = new HashMap<String, Object>();223 }224// 跳转节点为空,默认提交操作225if (StringUtil.isNull(activityId)) {226 plete(taskId, variables);227 } else {// 流程转向操作228 turnTransition(taskId, activityId, variables);229 }230 }231232/**233 * 清空指定活动节点流向234 *235 * @param activityImpl236 * 活动节点237 * @return节点流向集合238*/239private List<PvmTransition> clearTransition(ActivityImpl activityImpl) {240// 存储当前节点所有流向临时变量241 List<PvmTransition> oriPvmTransitionList = new ArrayList<PvmTransition>();242// 获取当前节点所有流向,存储到临时变量,然后清空243 List<PvmTransition> pvmTransitionList = activityImpl244 .getOutgoingTransitions();245for (PvmTransition pvmTransition : pvmTransitionList) {246 oriPvmTransitionList.add(pvmTransition);247 }248 pvmTransitionList.clear();249250return oriPvmTransitionList;251 }252253/**254 * 还原指定活动节点流向255 *256 * @param activityImpl257 * 活动节点258 * @param oriPvmTransitionList259 * 原有节点流向集合260*/261private void restoreTransition(ActivityImpl activityImpl,262 List<PvmTransition> oriPvmTransitionList) {263// 清空现有流向264 List<PvmTransition> pvmTransitionList = activityImpl265 .getOutgoingTransitions();266 pvmTransitionList.clear();267// 还原以前流向268for (PvmTransition pvmTransition : oriPvmTransitionList) {269 pvmTransitionList.add(pvmTransition);270 }271 }272273/**274 * 流程转向操作275 *276 * @param taskId277 * 当前任务ID278 * @param activityId279 * ⽬标节点任务ID280 * @param variables281 * 流程变量282 * @throws Exception283*/284private void turnTransition(String taskId, String activityId,285 Map<String, Object> variables) throws Exception {286// 当前节点287 ActivityImpl currActivity = findActivitiImpl(taskId, null);288// 清空当前流向289 List<PvmTransition> oriPvmTransitionList = clearTransition(currActivity);290291// 创建新流向292 TransitionImpl newTransition = currActivity.createOutgoingTransition();293// ⽬标节点294 ActivityImpl pointActivity = findActivitiImpl(taskId, activityId);295// 设置新流向的⽬标节点296 newTransition.setDestination(pointActivity);297298// 执⾏转向任务299 plete(taskId, variables);300// 删除⽬标节点新流⼊301 pointActivity.getIncomingTransitions().remove(newTransition);302303// 还原以前流向304 restoreTransition(currActivity, oriPvmTransitionList);305 }306307/**308 * ***************************************************************************************************************************************************<br>309 * ************************************************以上为流程转向操作核⼼逻辑******************************************************************************<br> 310 * ***************************************************************************************************************************************************<br>311*/312313/**314 * ***************************************************************************************************************************************************<br>315 * ************************************************以下为查询流程驳回节点核⼼逻辑***************************************************************************<br> 316 * ***************************************************************************************************************************************************<br>317*/318319/**320 * 迭代循环流程树结构,查询当前节点可驳回的任务节点321 *322 * @param taskId323 * 当前任务ID324 * @param currActivity325 * 当前活动节点326 * @param rtnList327 * 存储回退节点集合328 * @param tempList329 * 临时存储节点集合(存储⼀次迭代过程中的同级userTask节点)330 * @return回退节点集合331*/332private List<ActivityImpl> iteratorBackActivity(String taskId,333 ActivityImpl currActivity, List<ActivityImpl> rtnList,334 List<ActivityImpl> tempList) throws Exception {335// 查询流程定义,⽣成流程树结构336 ProcessInstance processInstance = findProcessInstanceByTaskId(taskId);337338// 当前节点的流⼊来源339 List<PvmTransition> incomingTransitions = currActivity340 .getIncomingTransitions();341// 条件分⽀节点集合,userTask节点遍历完毕,迭代遍历此集合,查询条件分⽀对应的userTask节点342 List<ActivityImpl> exclusiveGateways = new ArrayList<ActivityImpl>();343// 并⾏节点集合,userTask节点遍历完毕,迭代遍历此集合,查询并⾏节点对应的userTask节点344 List<ActivityImpl> parallelGateways = new ArrayList<ActivityImpl>();345// 遍历当前节点所有流⼊路径346for (PvmTransition pvmTransition : incomingTransitions) {347 TransitionImpl transitionImpl = (TransitionImpl) pvmTransition;348 ActivityImpl activityImpl = transitionImpl.getSource();349 String type = (String) activityImpl.getProperty("type");350/**351 * 并⾏节点配置要求:<br>352 * 必须成对出现,且要求分别配置节点ID为:XXX_start(开始),XXX_end(结束)353*/354if ("parallelGateway".equals(type)) {// 并⾏路线355 String gatewayId = activityImpl.getId();356 String gatewayType = gatewayId.substring(gatewayId357 .lastIndexOf("_") + 1);358if ("START".equals(gatewayType.toUpperCase())) {// 并⾏起点,停⽌递归359return rtnList;360 } else {// 并⾏终点,临时存储此节点,本次循环结束,迭代集合,查询对应的userTask节点361 parallelGateways.add(activityImpl);362 }363 } else if ("startEvent".equals(type)) {// 开始节点,停⽌递归364return rtnList;365 } else if ("userTask".equals(type)) {// ⽤户任务366 tempList.add(activityImpl);367 } else if ("exclusiveGateway".equals(type)) {// 分⽀路线,临时存储此节点,本次循环结束,迭代集合,查询对应的userTask节点368 currActivity = transitionImpl.getSource();369 exclusiveGateways.add(currActivity);370 }371 }372373/**374 * 迭代条件分⽀集合,查询对应的userTask节点375*/376for (ActivityImpl activityImpl : exclusiveGateways) {377 iteratorBackActivity(taskId, activityImpl, rtnList, tempList);378 }379380/**381 * 迭代并⾏集合,查询对应的userTask节点382*/383for (ActivityImpl activityImpl : parallelGateways) {384 iteratorBackActivity(taskId, activityImpl, rtnList, tempList);385 }386387/**388 * 根据同级userTask集合,过滤最近发⽣的节点389*/390 currActivity = filterNewestActivity(processInstance, tempList);391if (currActivity != null) {392// 查询当前节点的流向是否为并⾏终点,并获取并⾏起点ID393 String id = findParallelGatewayId(currActivity);394if (StringUtil.isNull(id)) {// 并⾏起点ID为空,此节点流向不是并⾏终点,符合驳回条件,存储此节点395 rtnList.add(currActivity);396 } else {// 根据并⾏起点ID查询当前节点,然后迭代查询其对应的userTask任务节点397 currActivity = findActivitiImpl(taskId, id);398 }399400// 清空本次迭代临时集合401 tempList.clear();402// 执⾏下次迭代403 iteratorBackActivity(taskId, currActivity, rtnList, tempList);404 }405return rtnList;406 }407408/**409 * 反向排序list集合,便于驳回节点按顺序显⽰410 *411 * @param list412 * @return413*/414private List<ActivityImpl> reverList(List<ActivityImpl> list) {415 List<ActivityImpl> rtnList = new ArrayList<ActivityImpl>();416// 由于迭代出现重复数据,排除重复417for (int i = list.size(); i > 0; i--) {418if (!rtnList.contains(list.get(i - 1)))419 rtnList.add(list.get(i - 1));420 }421return rtnList;422 }423424/**425 * 根据当前节点,查询输出流向是否为并⾏终点,如果为并⾏终点,则拼装对应的并⾏起点ID 426 *427 * @param activityImpl428 * 当前节点429 * @return430*/431private String findParallelGatewayId(ActivityImpl activityImpl) {432 List<PvmTransition> incomingTransitions = activityImpl433 .getOutgoingTransitions();434for (PvmTransition pvmTransition : incomingTransitions) {435 TransitionImpl transitionImpl = (TransitionImpl) pvmTransition;436 activityImpl = transitionImpl.getDestination();437 String type = (String) activityImpl.getProperty("type");438if ("parallelGateway".equals(type)) {// 并⾏路线439 String gatewayId = activityImpl.getId();440 String gatewayType = gatewayId.substring(gatewayId441 .lastIndexOf("_") + 1);442if ("END".equals(gatewayType.toUpperCase())) {443return gatewayId.substring(0, stIndexOf("_"))444 + "_start";445 }446 }447 }448return null;449 }450451/**452 * 根据流⼊任务集合,查询最近⼀次的流⼊任务节点453 *454 * @param processInstance455 * 流程实例456 * @param tempList457 * 流⼊任务集合458 * @return459*/460private ActivityImpl filterNewestActivity(ProcessInstance processInstance,461 List<ActivityImpl> tempList) {462while (tempList.size() > 0) {463 ActivityImpl activity_1 = tempList.get(0);464 HistoricActivityInstance activityInstance_1 = findHistoricUserTask(465 processInstance, activity_1.getId());466if (activityInstance_1 == null) {467 tempList.remove(activity_1);468continue;469 }470471if (tempList.size() > 1) {472 ActivityImpl activity_2 = tempList.get(1);473 HistoricActivityInstance activityInstance_2 = findHistoricUserTask(474 processInstance, activity_2.getId());475if (activityInstance_2 == null) {476 tempList.remove(activity_2);477continue;478 }479480if (activityInstance_1.getEndTime().before(481 activityInstance_2.getEndTime())) {482 tempList.remove(activity_1);483 } else {484 tempList.remove(activity_2);485 }486 } else {487break;488 }489 }490if (tempList.size() > 0) {491return tempList.get(0);492 }493return null;494 }495496/**497 * 查询指定任务节点的最新记录498 *499 * @param processInstance500 * 流程实例501 * @param activityId502 * @return503*/504private HistoricActivityInstance findHistoricUserTask(505 ProcessInstance processInstance, String activityId) {506 HistoricActivityInstance rtnVal = null;507// 查询当前流程实例审批结束的历史节点508 List<HistoricActivityInstance> historicActivityInstances = historyService509 .createHistoricActivityInstanceQuery().activityType("userTask")510 .processInstanceId(processInstance.getId()).activityId(511 activityId).finished()512 .orderByHistoricActivityInstanceEndTime().desc().list();513if (historicActivityInstances.size() > 0) {514 rtnVal = historicActivityInstances.get(0);515 }516517return rtnVal;518 }519520/**521 * *******************************************************************************************************<br>522 * ********************************以上为查询流程驳回节点核⼼逻辑***********************************************<br> 523 * ********************************************************************************************************<br>524*/525526/**527 * ********************************************************************************<br>528 * **********************以下为activiti 核⼼service529 * set⽅法***************************<br>530 * *********************************************************************************<br>531*/532public void setFormService(FormService formService) {533this.formService = formService;534 }535536public void setHistoryService(HistoryService historyService) {537this.historyService = historyService;538 }539540public void setRepositoryService(RepositoryService repositoryService) {541this.repositoryService = repositoryService;542 }543544public void setRuntimeService(RuntimeService runtimeService) {545this.runtimeService = runtimeService;546 }547548public void setTaskService(TaskService taskService) {549this.taskService = taskService;550 }551552/**553 * ********************************************************************************<br>554 * **********************以上为activiti 核⼼service555 * set⽅法***************************<br>556 * *********************************************************************************<br>557*/558559/**560 * ********************************************************************************<br>561 * **********************以下为根据任务节点ID 获取流程各对象查询⽅法**********************<br>562 * *********************************************************************************<br>563*/564565public void setProcessOtherService(ProcessOtherService processOtherService) {566this.processOtherService = processOtherService;567 }568569/**570 * 根据任务ID获得任务实例571 *572 * @param taskId573 * 任务ID574 * @return575 * @throws Exception576*/577private TaskEntity findTaskById(String taskId) throws Exception {578 TaskEntity task = (TaskEntity) taskService.createTaskQuery().taskId(579 taskId).singleResult();580if (task == null) {581throw new Exception("任务实例未找到!");582 }583return task;584 }585586/**587 * 根据流程实例ID和任务key值查询所有同级任务集合588 *589 * @param processInstanceId590 * @param key591 * @return592*/593private List<Task> findTaskListByKey(String processInstanceId, String key) {594return taskService.createTaskQuery().processInstanceId(595 processInstanceId).taskDefinitionKey(key).list();596 }597598/**599 * 根据任务ID获取对应的流程实例600 *601 * @param taskId602 * 任务ID603 * @return604 * @throws Exception605*/606private ProcessInstance findProcessInstanceByTaskId(String taskId)607throws Exception {608// 找到流程实例609 ProcessInstance processInstance = runtimeService610 .createProcessInstanceQuery().processInstanceId(611 findTaskById(taskId).getProcessInstanceId())612 .singleResult();613if (processInstance == null) {614throw new Exception("流程实例未找到!");615 }616return processInstance;617 }618619/**620 * 根据任务ID获取流程定义621 *622 * @param taskId623 * 任务ID624 * @return625 * @throws Exception626*/627private ProcessDefinitionEntity findProcessDefinitionEntityByTaskId(628 String taskId) throws Exception {629// 取得流程定义630 ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) ((RepositoryServiceImpl) repositoryService) 631 .getDeployedProcessDefinition(findTaskById(taskId)632 .getProcessDefinitionId());633634if (processDefinition == null) {635throw new Exception("流程定义未找到!");636 }637638return processDefinition;639 }640641/**642 * 根据任务ID和节点ID获取活动节点 <br>643 *644 * @param taskId645 * 任务ID646 * @param activityId647 * 活动节点ID <br>648 * 如果为null或"",则默认查询当前活动节点 <br>649 * 如果为"end",则查询结束节点 <br>650 *651 * @return652 * @throws Exception653*/654private ActivityImpl findActivitiImpl(String taskId, String activityId)655throws Exception {656// 取得流程定义657 ProcessDefinitionEntity processDefinition = findProcessDefinitionEntityByTaskId(taskId);658659// 获取当前活动节点ID660if (StringUtil.isNull(activityId)) {661 activityId = findTaskById(taskId).getTaskDefinitionKey();662 }663664// 根据流程定义,获取该流程实例的结束节点665if (activityId.toUpperCase().equals("END")) {666for (ActivityImpl activityImpl : processDefinition.getActivities()) {667 List<PvmTransition> pvmTransitionList = activityImpl668 .getOutgoingTransitions();669if (pvmTransitionList.isEmpty()) {670return activityImpl;671 }672 }673 }674675// 根据节点ID,获取对应的活动节点676 ActivityImpl activityImpl = ((ProcessDefinitionImpl) processDefinition)677 .findActivity(activityId);678679return activityImpl;680 }681682/**683 * ********************************************************************************<br>684 * **********************以上为根据任务节点ID 获取流程各对象查询⽅法**********************<br> 685 * *********************************************************************************<br>686*/687 }。
《Activiti6.0工作流引擎深度解析与实战》笔记
《Activiti6.0⼯作流引擎深度解析与实战》笔记1.1 课程导学--- 什么是⼯作流引擎?是⽤来驱动业务按照流程图逐步流转的核⼼框架。
--- 为什么学习⼯作流引擎?早期:企业OA、CRM、流程审批现在:电商购物、⾦融出⾏、中台⽀撑--- Activiti6.0流程引擎配置--- 核⼼API--- 数据模型设计--- BPMN2.0规范--- BPMN2.0元素2.1 本章概述⼯作流⼊门:⼯作流介绍、⼯作流技术选型、Activiti6.0快速体验。
2.2 ⼯作流介绍⼯作流是什么?为什么学习⼯作流?如何去学习⼯作流?1、审批业务场景(如请假,有⼀系列步骤)2、审批流程模型化(抽象出⼀系列流程图模型)“开始节点”(开始StartEvent)->填写审批信息的“⽤户节点”->通过“流程判断”(排他⽹关Exclusive Gateway)可以流转到“主管审批”(任务UserTask)->...->“结束节点”(结束EndEvent)3、常见的⽹上购物流程4、购物⼯作流程模型化有3个参与者,“电商购物流程”是泳池Pool,“仓储物流”等是泳道Line,“检验库存”是服务任务ServiceTask(服务任务是指不是由⼈⼯操作,⽽是由系统⾃动完成实现的逻辑)。
5、⼯作流是什么6、为什么需要⼯作流2.3 ⼯作流引擎技术选型2.4 Activiti6.0快速体验--部署环境介绍默认的⽤户名和密码是:admin和test2.5 Activiti6.0快速体验--部署环境实操win10下打开Cygwin,进⾏如下操作:1、curl -s "http://get.sdkman.io" | bash报错:Looking for a previous installation of SDKMAN...Looking for unzip...Looking for zip...Not found.Please install zip on your system using your favourite package manager.参考:https:///IOIO_/article/details/84946257解决⽅法是重新点击cygwin的安装包,把zip的package安装⼀遍,重启cygwin,再输⼊⼀遍这个命令即可。
activiti工作流原理
activiti工作流原理Activiti是一个基于Java的开源工作流引擎,用于管理和执行业务流程。
它遵循BPMN 2.0规范,提供了一套完整的工作流管理功能。
工作流引擎的原理是将业务流程抽象成可执行的流程模型,并通过运行时执行引擎来管理和执行这些流程模型。
以下是Activiti工作流引擎的原理:1. 流程定义:工作流的基本单位是流程定义,它是一个可执行的模型,描述了业务流程的各个步骤和在这些步骤间的流程流转条件。
流程定义可以使用BPMN2.0规范的图形化编辑器进行设计和定义。
2. 流程部署:流程定义需要被部署到工作流引擎中才能被执行。
部署过程包括将流程定义的XML文件和相关的资源文件上传到工作流引擎,并生成相应的数据库表和其他必要的配置。
3. 流程实例化:当流程定义被部署后,可以通过工作流引擎的API来实例化一个流程,创建一个流程实例。
每个流程实例都是根据流程定义创建的,它代表了一个业务流程的具体执行状态。
4. 任务分配:在流程实例化后,流程中的各个步骤被转换为任务节点。
任务节点定义了需要由哪个用户或用户组来执行该步骤,并在任务节点上生成相应的待办任务。
5. 任务执行:工作流引擎根据任务节点的定义将待办任务分配给相应的执行者,并通过API提供相应的方法来执行任务。
执行者可以在任务界面上处理任务并提交执行结果。
6. 流程流转:在任务执行过程中,工作流引擎根据事先定义好的流程流转条件来控制流程的流转。
当一个任务被完成时,工作流引擎会根据流程定义中的条件判断,决定下一个要执行的任务是哪一个。
7. 监控和管理:工作流引擎可以提供监控和管理功能,用于跟踪和管理流程实例的执行情况。
监控和管理功能可以通过工作流引擎的管理控制台或API来实现。
通过以上原理,Activiti工作流引擎实现了一套完整的工作流管理和执行功能,可以帮助企业提高业务流程的效率和可控性。
Activiti7工作流引擎
Activiti7⼯作流引擎Activiti7⼯作流引擎官⽅⽹站:Alfresco软件公司在2010 年 5 ⽉17 ⽇宣布Activiti业务流程管理(BPM)开源项⽬的正式启动,其⾸席架构师由业务流程管理BPM的专家 Tom Baeyens 担任,Tom Baeyens 就是原来jbpm的架构师,⽽jbpm是⼀个⾮常有名的⼯作流引擎,当然activiti也是⼀个⼯作流引擎。
activiti 可以将业务系统中复杂的业务流程抽取出来,使⽤专门的建模语⾔(BPMN2.0)进⾏定义,业务系统按照预先定义的流程进⾏执⾏,实现了业务系统的业务流程由activiti进⾏管理,减少业务系统由于流程变更进⾏系统升级改造的⼯作量,从⽽提⾼系统的健壮性,同时也减少了系统开发维护成本。
以前:程序员控制流程单状态,当到达某个状态时,就给谁审批,但是如果中间环节断开,即缺少⼀级的审批,则需要重新修改审批流程代码。
Activiti7:通过流程图⽣成代码,在数据库中会保存当前流程节点的数据,每次执⾏完流程节点,数据库数据会删除,并且进⼊下⼀个节点(⽣成⼀条数据),如果某个节点不需要了,也不会影响程序的正常运⾏。
通过流程图⽣成代码:本质上是⼀个xml⽂件,通过解析xml⽂件就能获取每⼀个节点的数据,然后保存到数据库。
简介BPM(Business Process Management),即业务流程管理,是⼀种以规范化的构造端到端的卓越业务流程为中⼼,以持续的提⾼组织业务绩效为⽬的系统化⽅法,常见商业管理教育如EMBA、MBA 等均将 BPM 包含在内。
企业流程管理主要是对企业内部改⾰,改变企业职能管理机构重叠、中间层次多、流程不闭环等,做到机构不重叠、业务不重复,达到缩短流程周期、节约运作资本、提⾼企业效益的作⽤。
BPM软件BPM软件就是根据企业中业务环境的变化,推进⼈与⼈之间、⼈与系统之间以及系统与系统之间的整合及调整的经营⽅法与解决⽅案的 IT ⼯具。
工作流引擎activiti表结构和代码详解
工作流引擎activiti表结构和代码详解工作流引擎Activiti的表结构和代码详解Activiti是一个基于Java语言的工作流引擎,它提供了一种可执行业务流程的方式,实现了对流程进行定义、部署、执行、监控等全生命周期的管理,具有高效、灵活、可扩展等优点。
本文将详细介绍Activiti 的表结构和代码实现。
1. 表结构Activiti引擎定义了多张表,这些表按照功能可以分为以下几类:(1) 流程定义相关表ACT_GE_BYTEARRAY:流程定义和流程实例相关的二进制文件存储表,包括BPMN 2.0 XML文件和各种图片等资源文件。
ACT_RE_DEPLOYMENT:部署信息表,包含部署时间、部署后的ID 和名称。
ACT_RE_PROCDEF:流程定义信息表,包含流程ID、XML文件名、键值和流程部署ID等信息。
(2) 运行时数据表ACT_RU_EXECUTION:流程实例运行时数据表,包含流程实例ID、业务ID、当前任务ID等信息。
ACT_RU_TASK:任务运行时数据表,包含任务分配人、执行候选人、任务完成时间等信息。
(3) 历史数据表ACT_HI_PROCINST:流程实例历史数据表,包含流程实例ID、开始时间、结束时间等信息。
ACT_HI_TASKINST:任务历史数据表,包含任务分配人、执行人、开始时间等信息。
(4) 操作记录相关表ACT_HI_ACTINST:历史记录,包含流程实例ID、开始时间、结束时间等信息。
ACT_HI_COMMENT:批注表,记录了流程的操作记录和评论等信息。
2. 代码实现Activiti引擎在代码实现方面遵循了面向对象的思想和设计模式,其中核心类包括ProcessEngine、RepositoryService、RuntimeService和TaskService等。
下面通过实例代码来展示Activiti的各个组件之间的调用关系。
(1) 初始化ProcessEngineProcessEngine是Activiti引擎的核心组件,负责管理运行时数据、历史记录、任务等等。
activity工作流
activity工作流Activity工作流。
Activity工作流是一种用于管理和协调业务流程的技术。
它可以帮助组织更好地理解、管理和优化其业务流程,从而提高效率和质量。
本文将介绍Activity工作流的基本概念、特点和应用,以及如何在实际项目中使用它。
Activity工作流的基本概念。
Activity工作流是基于活动(Activity)的业务流程管理技术。
它将业务流程抽象为一系列有序的活动,每个活动代表一个业务操作或决策点。
这些活动之间通过流程图中的连线来表示其先后顺序和条件关系。
通过定义和组织这些活动,可以形成一个完整的业务流程模型。
Activity工作流的特点。
Activity工作流具有以下特点:1. 灵活性,Activity工作流可以灵活地定义和组织业务流程,适应不同的业务需求和变化。
2. 可视化,通过流程图形式展现业务流程,便于人们理解和沟通。
3. 可扩展性,可以根据业务需求进行定制和扩展,满足不同规模和复杂度的业务流程。
4. 可重用性,可以将常用的业务流程模型进行封装和复用,提高开发效率和质量。
5. 可监控性,可以实时监控和跟踪业务流程的执行情况,及时发现和解决问题。
Activity工作流的应用。
Activity工作流广泛应用于各种业务场景,如订单处理、审批流程、客户关系管理等。
以订单处理为例,可以将整个订单处理流程抽象为一系列活动,如订单创建、审核、支付、发货、完成等。
通过Activity工作流,可以规范和自动化订单处理流程,提高处理效率和准确性。
在实际项目中使用Activity工作流。
在实际项目中,可以通过以下步骤来使用Activity工作流:1. 定义业务流程,根据业务需求和流程特点,定义业务流程模型,包括活动、连线和条件。
2. 实现业务逻辑,根据业务流程模型,实现各个活动的业务逻辑,包括数据处理、决策判断、状态转换等。
3. 集成工作流引擎,选择合适的工作流引擎,将业务流程模型和业务逻辑集成到工作流引擎中。
activiti用法
activiti用法Activiti是一个基于Java的开源工作流引擎,它提供了完整的工作流程概念和一套完善的管理工具,包括典型的BPMN 2.0图形建模,在业务处理和应用开发中有着广泛的应用。
以下是使用Activiti的详细步骤:1.安装和配置Activiti首先,需要将Activiti工作流引擎下载并且解压缩,然后在应用程序中添加相关依赖。
在Spring框架中集成Activiti,只需要在Spring配置文件中添加Activiti相应的XML配置即可。
2.设计和部署应用程序在Activiti中,首先需要设计和构建工作流流程,通过Activiti Designer可以轻松地进行BPMN 2.0流程图的设计。
设计好后,将其导出为XML文件并部署到Activiti Engine中。
在Activiti中可以通过REST API来部署工作流程。
另外,也可以在命令行中执行相关的命令来部署工作流程。
3.使用Activiti API开发可以在应用程序中通过Activiti API来访问Activiti Engine提供的相关操作。
首先,需要创建流程引擎,之后可以使用它来访问Activiti工作流引擎。
然后,可以使用Activiti的API来启动流程实例、查询任务、完成任务等操作,在具体实现中,需要使用Activiti提供的Java代码段来完成相应的工作。
4.监控和管理在Activiti中,可以使用Activiti Explorer或者Activiti Admin应用程序来监控和管理工作流流程。
可以使用Activiti Explorer来查看/管理实例、任务、用户、组等信息,也可以在Activiti Admin中进行高级的调优和监控操作。
5.测试和优化在完成Activiti的开发之后,需要进行全面的测试和优化。
可以使用Junit来进行单元测试,使用性能测试工具来检测系统在高负载条件下的性能表现等。
可以通过具体的优化方案来提高Activiti系统的性能和稳定性,例如使用缓存、对数据库进行优化等方法。
activiti工作流表名及字段详解
1. activiti工作流简介activiti是一个轻量级的工作流引擎,它是一个开源的、Java语言的工作流和业务过程管理(BPM)评台。
activiti可以帮助开发者简化和优化企业的业务流程,提高工作效率,降低成本。
2. activiti工作流表名及字段详解在activiti的工作流引擎中,有一些核心的数据表用来存储流程定义、流程实例、任务等信息。
下面我们就来详细解释activiti的工作流表名及字段。
2.1 ACT_RE_*:流程存储表ACT_RE_*表是存储流程静态信息的表,包括流程定义、流程资源等。
ACT_RE_*表的常见字段包括:- ID: 唯一标识- NAME: 名称- KEY: 关键字- DEPLOYMENT_ID: 部署ID- RESOURCE_NAME: 资源名称- DGRM_RESOURCE_NAME: 流程图名称2.2 ACT_RU_*:运行时表ACT_RU_*表是存储流程运行时数据的表,包括流程实例、任务实例等。
ACT_RU_*表的常见字段包括:- ID: 唯一标识- REV: 版本号- EXECUTION_ID: 执行ID- PROC_DEF_ID: 流程定义ID- NAME: 名称- ASSIGNEE: 指派人- CREATE_TIME: 创建时间2.3 ACT_HI_*:历史数据表ACT_HI_*表是存储历史数据的表,包括流程实例的历史数据、任务的历史数据等。
ACT_HI_*表的常见字段包括:- PROC_DEF_ID: 流程定义ID- PROC_INST_ID: 流程实例ID- TASK_ID: 任务ID- START_TIME: 开始时间- END_TIME: 结束时间- DURATION: 持续时间2.4 其他表及字段在activiti工作流引擎中,还有一些其他重要的表和字段,包括ACT_ID_*表(存储用户、角色等信息)、ACT_GE_*表(存储通用的流程引擎数据)等。
Activiti工作流框架中的任务调度!工作流框架中的任务流程元素详解,使用监听器监听任务执行
Activiti⼯作流框架中的任务调度!⼯作流框架中的任务流程元素详解,使⽤监听器监听任务执⾏任务⽤户任务描述⽤户任务⽤来设置必须由⼈员完成的⼯作当流程执⾏到⽤户任务,会创建⼀个新任务,并把这个新任务加⼊到分配⼈或群组的任务列表中图形标记⽤户任务显⽰成⼀个普通任务(圆⾓矩形),左上⾓有⼀个⼩⽤户图标XML内容XML中的⽤户任务定义:id属性是必须的,name属性是可选的:<userTask id="theTask" name="Important task" />⽤户任务可以设置描述,添加documentation元素可以定义描述:<userTask id="theTask" name="Schedule meeting" ><documentation>Schedule an engineering meeting for next week with the new hire.</documentation>描述⽂本可以通过标准的java⽅法来获取:task.getDescription()持续时间任务可以⽤⼀个字段来描述任务的持续时间可以使⽤查询API来对持续时间进⾏搜索,根据在时间之前或之后进⾏搜索Activiti提供了⼀个节点扩展,在任务定义中设置⼀个表达式,这样在任务创建时就可以设置初始持续时间表达式应该是:java.util.Datejava.util.String(ISO8601格式),ISO8601持续时间(⽐如PT50M)null在流程中使⽤上述格式输⼊⽇期,或在前⼀个服务任务中计算⼀个时间.这⾥使⽤了持续时间,持续时间会基于当前时间进⾏计算,再通过给定的时间段累加: 使⽤"PT30M"作为持续时间,任务就会从现在开始持续30分钟<userTask id="theTask" name="Important task" activiti:dueDate="${dateVariable}"/>任务的持续时间也可以通过TaskService修改,或在TaskListener中通过传⼊的DelegateTask参数修改⽤户分配⽤户任务可以直接分配给⼀个⽤户,通过humanPerformer元素定义humanPerformer定义需要⼀个resourceAssignmentExpression来实际定义⽤户.⽬前只⽀持formalExpressions<process ... >...<userTask id='theTask' name='important task' ><humanPerformer><resourceAssignmentExpression><formalExpression>kermit</formalExpression></resourceAssignmentExpression></humanPerformer></userTask>只有⼀个⽤户可以作为任务的执⾏者分配⽤户在activiti中,⽤户叫做执⾏者拥有执⾏者的⽤户不会出现在其他⼈的任务列表中,只能出现执⾏者的个⼈任务列表中直接分配给⽤户的任务可以通过TaskService获取:List<Task> tasks = taskService.createTaskQuery().taskAssignee("kermit").list();任务也可以加⼊到⼈员的候选任务列表中.需要使⽤potentialOwner元素⽤法和humanPerformer元素类似,需要指定表达式中的每个项⽬是⼈员还是群组<process ... >...<userTask id='theTask' name='important task' ><potentialOwner><resourceAssignmentExpression><formalExpression>user(kermit), group(management)</formalExpression></resourceAssignmentExpression></potentialOwner></userTask>使⽤potentialOwner元素定义的任务可以通过TaskService获取:List<Task> tasks = taskService.createTaskQuery().taskCandidateUser("kermit");这会获取所有kermit为候选⼈的任务,表达式中包含user(kermit).这也会获得所有分配包含kermit这个成员的群组(⽐如,group(management),前提是kermit是这个组的成员,并且使⽤了activiti的账号组件).⽤户所在的群组是在运⾏阶段获取的, 它们可以通过IdentityService进⾏管理如果没有显式指定设置的是⽤户还是群组,引擎会默认当做群组处理下⾯的设置与使⽤group(accountancy)⼀样:<formalExpression>accountancy</formalExpression>Activiti对任务分配的扩展当分配不复杂时,⽤户和组的设置⾮常⿇烦.为避免复杂性,可以使⽤⽤户任务的⾃定义扩展assignee属性: 直接把⽤户任务分配给指定⽤户(和使⽤humanPerformer 效果完全⼀样)<userTask id="theTask" name="my task" activiti:assignee="kermit" />candidateUsers属性: 为任务设置候选⼈(和使⽤potentialOwner效果完全⼀样,不需要像使⽤potentialOwner通过user(kermit)声明,这个属性只能⽤于⼈员)<userTask id="theTask" name="my task" activiti:candidateUsers="kermit, gonzo" />candidateGroups属性: 为任务设置候选组(和使⽤potentialOwner效果完全⼀样,不需要像使⽤potentialOwner通过group(management)声明,这个属性只能⽤于群组)<userTask id="theTask" name="my task" activiti:candidateGroups="management, accountancy" />candidateUsers和candidateGroups可以同时设置在同⼀个⽤户任务中Activiti中虽然有账号管理组件和IdentityService ,账号组件不会检测设置的⽤户是否存在. Activiti允许与其他已存的账户管理⽅案集成使⽤创建事件的任务监听器来实现⾃定义的分配逻辑:<userTask id="task1" name="My task" ><extensionElements><activiti:taskListener event="create" class="org.activiti.MyAssignmentHandler" /></extensionElements></userTask>DelegateTask会传递给TaskListener的实现,通过它可以设置执⾏⼈,候选⼈和候选组public class MyAssignmentHandler implements TaskListener {public void notify(DelegateTask delegateTask) {// Execute custom identity lookups here// and then for example call following methods:delegateTask.setAssignee("kermit");delegateTask.addCandidateUser("fozzie");delegateTask.addCandidateGroup("management");...}}使⽤spring时,使⽤表达式把任务监听器设置为spring代理的bean,让这个监听器监听任务的创建事件⽰例:执⾏者会通过调⽤ldapService这个spring bean的findManagerOfEmployee⽅法获得.流程变量emp会作为参数传递给bean<userTask id="task" name="My Task" activiti:assignee="${ldapService.findManagerForEmployee(emp)}"/>可以⽤来设置候选⼈和候选组:<userTask id="task" name="My Task" activiti:candidateUsers="${ldapService.findAllSales()}"/>⽅法返回类型只能为String(候选⼈) 或Collection < String >(候选组):public class FakeLdapService {public String findManagerForEmployee(String employee) {return "Kermit The Frog";}public List<String> findAllSales() {return Arrays.asList("kermit", "gonzo", "fozzie");}}脚本任务描述脚本任务是⼀个⾃动节点当流程到达脚本任务,会执⾏对应的脚本图形标记脚本任务显⽰为标准BPMN 2.0任务(圆⾓矩形),左上⾓有⼀个脚本⼩图标XML内容脚本任务定义需要指定script和scriptFormat<scriptTask id="theScriptTask" name="Execute script" scriptFormat="groovy"><script>sum = 0for ( i in inputArray ) {sum += i}</script></scriptTask>scriptFormat的值必须兼容JSR-223(java平台的脚本语⾔).默认Javascript会包含在JDK中,不需要额外的依赖.如果要使⽤其他的脚本引擎,必须要是JSR-223引擎兼容的.还需要把对应的jar添加到classpath下, 并使⽤合适的名称:activiti单元测试经常使⽤groovygroovy脚本引擎放在groovy-all.jar中,在2.0版本之前,脚本引擎是groovy jar的⼀部分.使⽤需要添加依赖:<dependency><groupId>org.codehaus.groovy</groupId><artifactId>groovy-all</artifactId><version>2.x.x<version></dependency>脚本变量到达脚本任务的流程可以访问的所有流程变量,都可以在脚本中使⽤<script>sum = 0for ( i in inputArray ) {sum += i}</script>也可以在脚本中设置流程变量,直接调⽤execution.setVariable("variableName", variableValue) 默认,不会⾃动保存变量(activiti 5.12之前) 可以在脚本中⾃动保存任何变量,只要把scriptTask的autoStoreVariables属性设置为true 最佳实践是不要使⽤,⽽是显式调⽤execution.setVariable()<scriptTask id="script" scriptFormat="JavaScript" activiti:autoStoreVariables="false">参数默认为false: 如果没有为脚本任务定义设置参数,所有声明的变量将只存在于脚本执⾏的阶段在脚本中设置变量: 这些命名已经被占⽤,不能⽤作变量名- out, out:print, lang:import, context, elcontext.<script>def scriptVar = "test123"execution.setVariable("myVar", scriptVar)</script>脚本结果脚本任务的返回值可以通过制定流程变量的名称,分配给已存在或者⼀个新流程变量,需要使⽤脚本任务定义的'activiti:resultVariable'属性任何已存在的流程变量都会被脚本执⾏的结果覆盖如果没有指定返回的变量名,脚本的返回值会被忽略<scriptTask id="theScriptTask" name="Execute script" scriptFormat="juel" activiti:resultVariable="myVar"><script>#{echo}</script></scriptTask>脚本的结果-表达式 #{echo} 的值会在脚本完成后,设置到myVar变量中Java服务任务描述Java服务任务⽤来调⽤外部Java类图形标记Java服务任务显⽰为圆⾓矩形,左上⾓有⼀个齿轮⼩图标XML内容声明Java调⽤逻辑有四种⽅式:实现JavaDelegate或者ActivityBehavior执⾏解析代理对象的表达式调⽤⼀个⽅法表达式调⽤⼀个值表达式执⾏⼀个在流程执⾏中调⽤的类,需要在activiti:class属性中设置全类名:<serviceTask id="javaService"name="My Java Service Task"activiti:class="org.activiti.MyJavaDelegate" />使⽤表达式调⽤⼀个对象,对象必须遵循⼀些规则,并使⽤activiti:delegateExpression属性进⾏创建:<serviceTask id="serviceTask" activiti:delegateExpression="${delegateExpressionBean}" />delegateExpressionBean是⼀个实现了JavaDelegate接⼝的bean,定义在实例的spring容器中要执⾏指定的UEL⽅法表达式, 需要使⽤activiti:expression:<serviceTask id="javaService"name="My Java Service Task"activiti:expression="#{printer.printMessage()}" />⽅法printMessage()会调⽤名为printer对象的⽅法为表达式中的⽅法传递参数:<serviceTask id="javaService"name="My Java Service Task"activiti:expression="#{printer.printMessage(execution, myVar)}" />调⽤名为printer对象上的⽅法printMessage.第⼀个参数是DelegateExecution, 在表达式环境中默认名称为execution. 第⼆个参数传递的是当前流程的名为myVar的变量要执⾏指定的UEL⽅法表达式, 需要使⽤activiti:expression:<serviceTask id="javaService"name="My Java Service Task"activiti:expression="#{split.ready}" />ready属性的getter⽅法:getReady() 会作⽤于名为split的bean上.这个对象会被解析为流程对象和spring环境中的对象实现要在流程执⾏中实现⼀个调⽤的类,这个类需要实现org.activiti.engine.delegate.JavaDelegate接⼝,并在execute⽅法中提供对应的业务逻辑.当流程执⾏到特定阶段,会指定⽅法中定义好的业务逻辑,并按照默认BPMN 2.0中的⽅式离开节点⽰例: 创建⼀个java类的例⼦,对流程变量中字符串转换为⼤写这个类需要实现org.activiti.engine.delegate.JavaDelegate接⼝,要求实现execute(DelegateExecution) ⽅法,包含的业务逻辑会被引擎调⽤流程实例信息:流程变量和其他信息,可以通过DelegateExecution接⼝访问和操作public class ToUppercase implements JavaDelegate {public void execute(DelegateExecution execution) throws Exception {String var = (String) execution.getVariable("input");var = var.toUpperCase();execution.setVariable("input", var);}}serviceTask定义的class只会创建⼀个java类的实例所有流程实例都会共享相同的类实例,并调⽤execute(DelegateExecution) 类不能使⽤任何成员变量,必须是线程安全的,必须能模拟在不同线程中执⾏.影响着属性注⼊的处理⽅式流程定义中引⽤的类(activiti:class)不会在部署时实例化只有当流程第⼀次执⾏到使⽤类的时候,类的实例才会被创建如果找不到类,会抛出⼀个ActivitiException这个原因是部署环境(更确切是的classpath)和真实环境往往是不同的:当使⽤ant或业务归档上传到Activiti Explorer来发布流程,classpath没有包含引⽤的类内部实现类也可以提供实现org.activiti.engine.impl.pvm.delegate.ActivityBehavior接⼝的类实现可以访问更强⼤的ActivityExecution,它可以影响流程的流向注意: 这应该尽量避免.只有在⾼级情况下并且确切知道要做什么的情况下,再使⽤ActivityBehavior接⼝属性注⼊为代理类的属性注⼊数据. ⽀持如下类型的注⼊: 固定的字符串表达式如果有效的话,数值会通过代理类的setter⽅法注⼊,遵循java bean的命名规范(⽐如fistName属性对应setFirstName(Xxx)⽅法)如果属性没有对应的setter⽅法,数值会直接注⼊到私有属性中⼀些环境的SecurityManager不允许修改私有属性,要把想注⼊的属性暴露出对应的setter⽅法来⽆论流程定义中的数据是什么类型,注⼊⽬标的属性类型都应该是 org.activiti.engine.delegate.Expression⽰例: 把⼀个常量注⼊到属性中属性注⼊可以使⽤class属性在声明实际的属性注⼊之前,需要定义⼀个extensionElements的XML元素<serviceTask id="javaService"name="Java service invocation"activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected"><extensionElements><activiti:field name="text" stringValue="Hello World" /></extensionElements></serviceTask>ToUpperCaseFieldInjected类有⼀个text属性,类型是org.activiti.engine.delegate.Expression. 调⽤text.getValue(execution) 时,会返回定义的字符串Hello World可以使⽤长⽂字(⽐如,内嵌的email),使⽤activiti:string⼦元素:<serviceTask id="javaService"name="Java service invocation"activiti:class="org.activiti.examples.bpmn.servicetask.ToUpperCaseFieldInjected"><extensionElements><activiti:field name="text"><activiti:string>Hello World</activiti:string></activiti:field></extensionElements></serviceTask>可以使⽤表达式,实现在运⾏期动态解析注⼊的值这些表达式可以使⽤流程变量或spring定义的bean.服务任务中的java类实例会在所有流程实例中共享:为了动态注⼊属性的值,可以在org.activiti.engine.delegate.Expression中使⽤值和⽅法表达式会使⽤传递给execute⽅法的DelegateExecution参数进⾏解析<serviceTask id="javaService" name="Java service invocation"activiti:class="org.activiti.examples.bpmn.servicetask.ReverseStringsFieldInjected"><extensionElements><activiti:field name="text1"><activiti:expression>${genderBean.getGenderString(gender)}</activiti:expression></activiti:field><activiti:field name="text2"><activiti:expression>Hello ${gender == 'male' ? 'Mr.' : 'Mrs.'} ${name}</activiti:expression></activiti:field></ extensionElements></ serviceTask>⽰例: 注⼊表达式,并使⽤在当前传⼊的DelegateExecution解析:public class ReverseStringsFieldInjected implements JavaDelegate {private Expression text1;private Expression text2;public void execute(DelegateExecution execution) {String value1 = (String) text1.getValue(execution);execution.setVariable("var1", new StringBuffer(value1).reverse().toString());String value2 = (String) text2.getValue(execution);execution.setVariable("var2", new StringBuffer(value2).reverse().toString());}}可以把表达式设置成⼀个属性,⽽不是⼦元素:因为java类实例会被重⽤,注⼊只会发⽣⼀次,当服务任务调⽤第⼀次的时候发⽣注⼊当代码中的属性改变了,值也不会重新注⼊,把它们看作是不变的,不⽤修改它们服务任务结果服务流程返回的结果(使⽤表达式的服务任务)可以分配给已经存在的或新的流程变量通过指定服务任务定义的activiti:resultVariable属性来实现指定的流程变量会被服务流程的返回结果覆盖如果没有指定返回变量名,就会忽略返回结果<serviceTask id="aMethodExpressionServiceTask"activiti:expression="#{myService.doSomething()}"activiti:resultVariable="myVar" />服务流程的返回值(在myService上调⽤doSomething() ⽅法的返回值,myService可能是流程变量,也可能是spring的bean),在服务执⾏完成之后,会设置到名为myVar的流程变量⾥处理异常执⾏⾃定义逻辑时,常常需要捕获对应的业务异常,在流程内部进⾏处理抛出BPMN Errors: 在服务任务或脚本任务的代码⾥抛出BPMN error: 要从JavaDelegate,脚本,表达式和代理表达式中抛出名为BpmnError的特殊ActivitiExeption 引擎会捕获这个异常,把它转发到对应的错误处理中:边界错误事件或错误事件⼦流程public class ThrowBpmnErrorDelegate implements JavaDelegate {public void execute(DelegateExecution execution) throws Exception {try {executeBusinessLogic();} catch (BusinessException e) {throw new BpmnError("BusinessExceptionOccured");}}}构造参数是错误代码,会被⽤来决定哪个错误处理器会来响应这个错误这个机制只⽤于业务失败,应该被流程定义中设置的边界错误事件或错误事件⼦流程处理. 技术上的错误应该使⽤其他异常类型,通常不会在流程⾥处理异常顺序流: 内部实现类在⼀些异常发⽣时,让流程进⼊其他路径<serviceTask id="javaService"name="Java service invocation"activiti:class="org.activiti.ThrowsExceptionBehavior"></serviceTask><sequenceFlow id="no-exception" sourceRef="javaService" targetRef="theEnd" /><sequenceFlow id="exception" sourceRef="javaService" targetRef="fixException" />这⾥的服务任务有两个外出顺序流:分别叫exception和no-exception. 异常出现时会使⽤顺序流的ID来决定流向public class ThrowsExceptionBehavior implements ActivityBehavior {public void execute(ActivityExecution execution) throws Exception {String var = (String) execution.getVariable("var");PvmTransition transition = null;try {executeLogic(var);transition = execution.getActivity().findOutgoingTransition("no-exception");} catch (Exception e) {transition = execution.getActivity().findOutgoingTransition("exception");}execution.take(transition);}}JavaDelegate使⽤Activiti服务需要在Java服务任务中使⽤Activiti服务的场景: ⽐如,通过RuntimeService启动流程实例,⽽callActivity不满⾜需求org.activiti.engine.delegate.DelegateExecution允许通过 org.activiti.engine.EngineServices接⼝直接获得这些服务:public class StartProcessInstanceTestDelegate implements JavaDelegate {public void execute(DelegateExecution execution) throws Exception {RuntimeService runtimeService = execution.getEngineServices().getRuntimeService();runtimeService.startProcessInstanceByKey("myProcess");}}所有activiti服务的API都可以通过这个接⼝获得使⽤这些API调⽤出现的所有数据改变,都是在当前事务中在例如spring和CDI这样的依赖注⼊环境也会起作⽤,⽆论是否启⽤了JTA数据源⽰例: 下⾯的代码功能与上⾯的代码⼀致,这是RuntimeService是通过依赖注⼊获得,⽽不是通过org.activiti.engine.EngineServices接⼝@Component("startProcessInstanceDelegate")public class StartProcessInstanceTestDelegateWithInjection {@Autowiredprivate RuntimeService runtimeService;public void startProcess() {runtimeService.startProcessInstanceByKey("oneTaskProcess");}}因为服务调⽤是在当前事务⾥,数据的产⽣或改变,在服务任务执⾏完之前,还没有提交到数据库.所以API对于数据库数据的操作,意味着未提交的操作在服务任务的API调⽤中都是不可见的WebService任务描述WebService任务可以⽤来同步调⽤⼀个外部的WebService图形标记WebService任务与Java服务任务显⽰效果⼀样(圆⾓矩形,左上⾓有⼀个齿轮⼩图标)XML内容要使⽤WebService需要导⼊操作和类型,可以使⽤import标签来指定WebService的WSDL<import importType="/wsdl/"location="http://localhost:63081/counter?wsdl"namespace="/" />声明告诉activiti导⼊WSDL定义,但没有创建itemDefinition和message假设想调⽤⼀个名为prettyPrint的⽅法,必须创建为请求和响应信息对应的message和itemDefinition <message id="prettyPrintCountRequestMessage" itemRef="tns:prettyPrintCountRequestItem" /><message id="prettyPrintCountResponseMessage" itemRef="tns:prettyPrintCountResponseItem" /><itemDefinition id="prettyPrintCountRequestItem" structureRef="counter:prettyPrintCount" /><itemDefinition id="prettyPrintCountResponseItem" structureRef="counter:prettyPrintCountResponse" />在申请服务任务之前,必须定义实际引⽤WebService的BPMN接⼝和操作基本上,定义接⼝和必要的操作.对每个操作都会重⽤上⾯定义的信息作为输⼊和输出⽰例: 定义了counter接⼝和prettyPrintCountOperation操作:<interface name="Counter Interface" implementationRef="counter:Counter"><operation id="prettyPrintCountOperation" name="prettyPrintCount Operation"implementationRef="counter:prettyPrintCount"><inMessageRef>tns:prettyPrintCountRequestMessage</inMessageRef><outMessageRef>tns:prettyPrintCountResponseMessage</outMessageRef></operation></interface>然后定义WebService任务,使⽤WebService实现,并引⽤WebService操作<serviceTask id="webService"name="Web service invocation"implementation="##WebService"operationRef="tns:prettyPrintCountOperation">WebService任务IO规范每个WebService任务可以定义任务的输⼊输出IO规范<ioSpecification><dataInput itemSubjectRef="tns:prettyPrintCountRequestItem" id="dataInputOfServiceTask" /><dataOutput itemSubjectRef="tns:prettyPrintCountResponseItem" id="dataOutputOfServiceTask" /><inputSet><dataInputRefs>dataInputOfServiceTask</dataInputRefs></inputSet><outputSet><dataOutputRefs>dataOutputOfServiceTask</dataOutputRefs></outputSet></ioSpecification>WebService任务数据输⼊关联指定数据输⼊关联有两种⽅式:使⽤表达式使⽤简化⽅式使⽤表达式指定数据输⼊关联: 需要定义来源和⽬的item,并指定每个item属性之间的对应关系:<dataInputAssociation><sourceRef>dataInputOfProcess</sourceRef><targetRef>dataInputOfServiceTask</targetRef><assignment><from>${dataInputOfProcess.prefix}</from><to>${dataInputOfServiceTask.prefix}</to></assignment><assignment><from>${dataInputOfProcess.suffix}</from><to>${dataInputOfServiceTask.suffix}</to></assignment></dataInputAssociation>分配item的前缀和后缀使⽤简化⽅式指定数据输⼊关联: sourceRef元素是activiti的变量名,targetRef元素是item定义的⼀个属性:<dataInputAssociation><sourceRef>PrefixVariable</sourceRef><targetRef>prefix</targetRef></dataInputAssociation><dataInputAssociation><sourceRef>SuffixVariable</sourceRef><targetRef>suffix</targetRef></dataInputAssociation>PrefixVariable变量的值分配给prefix属性,把SuffixVariable变量的值分配给suffix属性WebService任务数据输出关联指定数据输出关联有两种⽅式:使⽤表达式使⽤简化⽅式使⽤表达式指定数据输出关联: 需要定义⽬的变量和来源表达式<dataOutputAssociation><targetRef>dataOutputOfProcess</targetRef><transformation>${dataOutputOfServiceTask.prettyPrint}</transformation></dataOutputAssociation>⽅法和数据输⼊关联完全⼀样使⽤简化⽅式指定数据输出关联: sourceRef元素是item定义的⼀个属性,targetRef元素是activiti的变量名<dataOutputAssociation><sourceRef>prettyPrint</sourceRef><targetRef>OutputVariable</targetRef></dataOutputAssociation>⽅法和数据输⼊关联完全⼀样业务规则任务描述业务规则任务⽤来同步执⾏⼀个或多个规则Activiti使⽤drools规则引擎执⾏业务规则: 包含业务规则的.drl⽂件必须和流程定义⼀起发布流程定义⾥包含了执⾏这些规则的业务规则任务流程使⽤的所有.drl⽂件都必须打包在流程BAR⽂件⾥如果想要⾃定义规则任务的实现: 想⽤不同⽅式使⽤drools,或者使⽤完全不同的规则引擎.你可以使⽤BusinessRuleTask上的class或表达式属性图形标记业务规则任务是⼀个圆⾓矩形,左上⾓使⽤⼀个表格⼩图标进⾏显⽰XML内容要执⾏部署流程定义的BAR⽂件中的⼀个或多个业务规则,需要定义输⼊和输出变量:对于输⼊变量定义,可以使⽤逗号分隔的⼀些流程变量输出变量定义只包含⼀个变量名,会把执⾏业务规则后返回的对象保存到对应的流程变量中注意: 结果变量会包含⼀个对象列表,如果没有指定输出变量名称,默认会使⽤ org.activiti.engine.rules.OUTPUT<process id="simpleBusinessRuleProcess"><startEvent id="theStart" /><sequenceFlow sourceRef="theStart" targetRef="businessRuleTask" /><businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"activiti:resultVariable="rulesOutput" /><sequenceFlow sourceRef="businessRuleTask" targetRef="theEnd" /><endEvent id="theEnd" /></process>业务规则任务也可以配置成只执⾏部署的.drl⽂件中的⼀些规则.这时要设置逗号分隔的规则名,只会执⾏rule1和rule2:<businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"activiti:rules="rule1, rule2" />定义哪些规则不⽤执⾏:除了rule1和rule2以外,所有部署到流程定义同⼀个BAR⽂件中的规则都会执⾏:<businessRuleTask id="businessRuleTask" activiti:ruleVariablesInput="${order}"activiti:rules="rule1, rule2" exclude="true" />可以⽤⼀个选项修改BusinessRuleTask的实现:<businessRuleTask id="businessRuleTask" activiti:class="${MyRuleServiceDelegate}" />BusinessRuleTask的功能和ServiceTask⼀样,但是使⽤BusinessRuleTask的图标来表⽰在这⾥要执⾏业务规则邮件任务Activiti强化了业务流程,⽀持⾃动邮件任务: 可以发送邮件给⼀个或多个参与者,包括⽀持cc,bcc,HTML内容等等邮件任务不是BPMN 2.0规范定义的官⽅任务,Activiti中邮件任务是⽤专门的服务任务实现的邮件服务器配置Activiti引擎要通过⽀持SMTP功能的外部邮件服务器发送邮件为了实际发送邮件,引擎穾知道如何访问邮件服务器.下⾯的配置可以设置到activiti.cfg.xml配置⽂件中:属性是否必须描述mailServerHost否邮件服务器的主机名(⽐如:).默认为localhostmailServerPort 是如果没有使⽤默认端⼝邮件服务器上的SMTP传输端⼝.默认为25mailServerDefaultFrom否如果⽤户没有指定发送邮件的邮件地址,默认设置的发送者的邮件地址。
2021全网最全Activiti7教程02(Activiti7入门使用-欢迎收藏)
2021全⽹最全Activiti7教程02(Activiti7⼊门使⽤-欢迎收藏)全⽹最详细Activiti系列⽂章,强烈建议收藏加关注哦!Activiti的⼊门应⽤1Activiti的基本使⽤1.1 创建Maven项⽬ 创建⼀个普通的Maven项⽬,并添加相关的依赖<properties><slf4j.version>1.6.6</slf4j.version><log4j.version>1.2.12</log4j.version><activiti.version>7.0.0.Beta1</activiti.version></properties><dependencies><dependency><groupId>org.activiti</groupId><artifactId>activiti-engine</artifactId><version>${activiti.version}</version></dependency><dependency><groupId>org.activiti</groupId><artifactId>activiti-spring</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 模型处理 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-model</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 转换 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-converter</artifactId><version>${activiti.version}</version></dependency><!-- bpmn json数据转换 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-json-converter</artifactId><version>${activiti.version}</version></dependency><!-- bpmn 布局 --><dependency><groupId>org.activiti</groupId><artifactId>activiti-bpmn-layout</artifactId><version>${activiti.version}</version><exclusions><exclusion><groupId>com.github.jgraph</groupId><artifactId>jgraphx</artifactId></exclusion></exclusions></dependency><!-- activiti 云⽀持 --><dependency><groupId>org.activiti.cloud</groupId><artifactId>activiti-cloud-services-api</artifactId><version>${activiti.version}</version></dependency><!-- mysql驱动 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.40</version></dependency><!-- mybatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.4.5</version></dependency><!-- 链接池 --><dependency><groupId>commons-dbcp</groupId><artifactId>commons-dbcp</artifactId><version>1.4</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- log start --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>${slf4j.version}</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>${slf4j.version}</version></dependency></dependencies>1.2 log4j 添加⼀个⽇志⽂件log4j.properties# Set root category priority to INFO and its only appender to CONSOLE.#log4j.rootCategory=INFO, CONSOLE debug info warn error fatallog4j.rootCategory=debug, CONSOLE, LOGFILE# Set the enterprise logger category to FATAL and its only appender to CONSOLE..apache.axis.enterprise=FATAL, CONSOLE# CONSOLE is set to be a ConsoleAppender using a PatternLayout.log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderyout=org.apache.log4j.PatternLayoutyout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n# LOGFILE is set to be a File appender using a PatternLayout.log4j.appender.LOGFILE=org.apache.log4j.FileAppenderlog4j.appender.LOGFILE.File=d:\log\act\activiti.loglog4j.appender.LOGFILE.Append=trueyout=org.apache.log4j.PatternLayoutyout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n1.3 添加Activiti配置⽂件 我们在本案例中使⽤的数据库是mysql8.0. Activiti的默认的使⽤⽅式是要求我们在resources下创建activiti.cfg.xml⽂件,默认的⽅式的名称是不能修改的。
Activiti工作流详解完整教程
Activiti教程详解完整教程1.A ctiviti介绍Activiti是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理,工作流,服务协作等领域的一个开源,灵活的,易扩展的可执行流程语言框架。
Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss JBPM的项目架构师,它的特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。
1.1工作流引擎ProcessEngine对象,这是Activiti工作的核心。
负责生成流程运行时的各种实例及数据,监控和管理流程的运行。
1.2BPMN业务流程建模与标注(Business Process Model and Notation,BPMN),描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)2.准备环境2.1Activiti软件环境1)JDK1.6或者更高版本2)支持的数据库有:h2,mysql,oracle,mysql,db2等3)支持Activiti运行的jar包,可以通过maven依赖引入4)开发环境为Eclipse3.7或者以上版本,myeclipse为8.6版本2.2安装流程设计器(eclipse插件)1)打开Help →Install New Software →Add输入Name: Activiti DesignerLocation: /designer/update/输入完成后,单击OK按钮等待下载完成后安装。
安装完成后在菜单选项中会出现Activiti的目录选项2.3 设置eclipse activit插件的画流程图选项打开菜单Windows --> Preferences --> Activiti -->Save 下流程图片的生成方式勾选上Create process definition image when saving the diagram操作,勾选上这个操作后在画流程图后保存eclipse会自动生成对应的流程图片。
Activiti7精讲教程-Java通用型工作流开发实战
Activiti7精讲教程-Java通用型工作流开发实战
完整版11章,附源码
从0开始开发一个通用、好用、高效的UML工作流系统;项目代码手把手带着敲,没有无中生有的复制粘贴,每一行代码都有出处和依据;以主流前后端分离模式,手把手带你铸就黑马级全栈项目。
课程三大核心:① 以“代码驱动式”教学模式,精讲最新版工作流引擎Activiti7核心组件;② 传授你业务建模或者软件建模的“工程化思维”;③ 基于SpringBoot+Activiti+SpringSecurity 等技术栈,“手把手”带你设计与实战企业级的黑马项目:《通用型可视化UML 工作流系统》。
优雅的实现Activiti动态调整流程(自由跳转、前进、后退、分裂、前加签、后加签等),含。。。
优雅的实现Activiti动态调整流程(⾃由跳转、前进、后退、分裂、前加签、后加签等),含。
最近对Activiti做了⼀些深⼊的研究,对Activiti的流程机制有了些理解,对动态调整流程也有了⼀些实践⽅法。
现在好好总结⼀下,⼀来是对这段时间⾃⼰⾟苦探索的⼀个记录,⼆来也是为后来者指指路~~~如下内容准备采⽤QA的⽅式写,很多问题都是当初⾃⼰极疑惑的问题,希望能为⼤家解惑!Q:可以动态调整流程吗?A:可以!可以动态更改流程指向,或者创建新的节点,等等。
Q: 更改流程还需要注意什么?A: 必须要实现持久化!否则⼀旦应⽤重启,你的流程就犯糊涂了!譬如,你创建了⼀个新节点,但由于没有持久化,重启之后流程引擎找不到那个新节点了。
Q: 如何做到优雅?A: 除了持久化之外,还记住尽量不要因为临时调整直接更改现有活动(没准这个活动后⾯还要照常使⽤呢!),这种情况可以考虑克隆。
第三,不要直接操作数据库,或者SqlSession,记住⾃⼰写Command!参见我前⾯的。
如下代码⽰出执⾏某个activity后续流程的Cmd:public class CreateAndTakeTransitionCmd implements Command<ng.Void>{private ActivityImpl _activity;private String _executionId;public CreateAndTakeTransitionCmd(String executionId, ActivityImpl activity){_executionId = executionId;_activity = activity;}@Overridepublic Void execute(CommandContext commandContext){Logger.getLogger(TaskFlowControlService.class).debug(String.format("executing activity: %s", _activity.getId()));ExecutionEntity execution = commandContext.getExecutionEntityManager().findExecutionById(_executionId);execution.setActivity(_activity);execution.performOperation(AtomicOperation.TRANSITION_CREATE_SCOPE);return null;}}Q: 如何新建⼀个活动?A: 新建活动可以调⽤processDefinition.createActivity(newActivityId),我们往往可以以某个活动对象为模板来克隆⼀个新的活动,克隆的⽅法是分别拷贝各个字段的值:protected ActivityImpl cloneActivity(ProcessDefinitionEntity processDefinition, ActivityImpl prototypeActivity,String newActivityId, String... fieldNames){ActivityImpl clone = processDefinition.createActivity(newActivityId);CloneUtils.copyFields(prototypeActivity, clone, fieldNames);return clone;}拷贝字段的代码如下:import ng.reflect.FieldUtils;import org.apache.log4j.Logger;import org.junit.Assert;public abstract class CloneUtils{public static void copyFields(Object source, Object target, String... fieldNames){Assert.assertNotNull(source);Assert.assertNotNull(target);Assert.assertSame(source.getClass(), target.getClass());for (String fieldName : fieldNames){try{Field field = FieldUtils.getField(source.getClass(), fieldName, true);field.setAccessible(true);field.set(target, field.get(source));}catch (Exception e){Logger.getLogger(CloneUtils.class).warn(e.getMessage());}}}}⼀个⽰例的⽤法是:ActivityImpl clone = cloneActivity(processDefinition, prototypeActivity, cloneActivityId, "executionListeners","properties");这个语句的意思是克隆prototypeActivity对象的executionListeners和properties字段。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
A c t i v i t i工作流入门详解完整教程Prepared on 24 November 2020Activiti入门教程详解完整教程1.Activiti介绍Activiti是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理,工作流,服务协作等领域的一个开源,灵活的,易扩展的可执行流程语言框架。
Activiti基于Apache许可的开源BPM平台,创始人TomBaeyens是JBossJBPM 的项目架构师,它的特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。
1.1工作流引擎ProcessEngine对象,这是Activiti工作的核心。
负责生成流程运行时的各种实例及数据,监控和管理流程的运行。
1.2BPMN业务流程建模与标注(BusinessProcessModelandNotation,BPMN),描述流程的基本符号,包括这些图元如何组合成一个业务流程图(BusinessProcessDiagram) 2.准备环境2.1Activiti软件环境1)或者更高版本2)支持的数据库有:h2,mysql,oracle,mysql,db2等3)支持Activiti运行的jar包,可以通过maven依赖引入4)开发环境为或者以上版本,myeclipse为版本安装流程设计器(eclipse插件)1)打开HelpInstallNewSoftwareAdd输入Name:ActivitiDesignerdesigner/update/输入完成后,单击OK按钮等待下载完成后安装。
安装完成后在菜单选项中会出现Activiti的目录选项设置eclipseactivit插件的画流程图选项打开菜单Windows-->Preferences-->Activiti-->Save下流程图片的生成方式勾选上Createprocessdefinitionimagewhensavingthediagram操作,勾选上这个操作后在画流程图后保存eclipse会自动生成对应的流程图片。
准备开发环境Activiti依赖在eclipse左边工作栏右键New选择创建MavenProject项目,创建一个名为ActivitiTest的项目点击Finish完成。
右键项目选择Properties,选择ProjectFacets勾选上图中的选项,点击Apply,再点击OK然后将项目转换成web项目,右键项目选择Properties,在ProjectFacets中做如下勾选,然后点击Appy应用和OK确定然后右键项目Properties,选择DeploymentAssembly,将test相关目录Remove掉之保留main下面需要发布的内容,如下图然后点击Appply和OK然后在文件中添加以下依赖<dependencies><dependency><groupId></groupId><artifactId>Activiti-engine</artifactId><version></dependency><dependency><groupId></groupId><artifactId>Activiti-spring</artifactId><version></dependency><dependency><groupId></groupId><artifactId>groovy-all</artifactId><version></dependency><dependency><groupId></groupId><artifactId>slf4j-api</artifactId><version></dependency><dependency><groupId></groupId><artifactId>slf4j-jdk14</artifactId><version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version><scope>test</scope> </dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version></version></dependency></dependencies>然后在命令行下mvncompile编译当前项目,将需要的包下载到本地仓库1)src/main/resource目录下创建文件,内容如下<xml version=""encoding="UTF-8"><beans xmlns=xmlns:xsi=xmlns:context=xmlns:tx=xmlns:jee=xmlns:aop=xsi:schemaLocation=><bean id="processEngineConfiguration"class="><property name="jdbcDriver"value=/><property name="jdbcUrl"value=/><property name="jdbcUsername"value="root"/><property name="jdbcPassword"value="root"/><property name="databaseSchemaUpdate"value="true"/> </bean></beans>jdbcUrl为你电脑数据库的urljdbcUsername为数据库用户名jdbcPassword为数据库密码2)在main/java目录下创建任意目录和类编写创建Activiti数据表方法publicclass CreateTable{/*****创建流程表**/@Testpublicvoid createTable(){ProcessEngine processEngine=("").buildProcessEngine();"------processEngine:"+processEngine);}}然后运行该测试方法,如果运行成功,在数据库中应该会产生25张Activiti 的相关数据表表说明下面是概括了几个常用的数据表流程部署相关表act_re_deployement部署对象表act_rep_procdef流程定义表act_ge_bytearray资源文件表act_ge_prperty主键生成策略表(对于部署对象表的主键ID)流程实例相关表act_ru_execution正在执行的执行对象表(包含执行对象ID和流程实例ID,如果有多个线程可能流程实例ID不一样)act_hi_procinst流程实例历史表act_hi_actinst存放历史所有完成的任务Task任务相关表act_ru_task代办任务表(只对应节点是UserTask的)act_hi_taskinst代办任务历史表(只对应节点是UserTask的)act_hi_actinst所有节点活动历史表(对应流程的所有节点的活动历史,从开始节点一直到结束节点中间的所有节点的活动都会被记录)流程变量表act_ru_variable正在执行的流程变量表act_hi_variable流程变量历史表3.核心API说明:1)在Activiti中最核心的类,其他的类都是由他而来。
2)产生方式ProcessEngine processEngine=();3)可以产生RepositoryServiceRepositoryService repositoryService=();4)可以产生RuntimeServiceRuntimeService runtimeService=();5)可以产生TaskServiceTaskService taskService=();各个Service的作用Activiti的仓库服务类。
所谓的仓库指流程定义文档的两个文件:bpmn文件和流程图片该service可以用来删除部署的流程定义。
是Activiti的流程执行服务类,可以从这个服务类中获取很多关于流程执行的相关的信息。
是Activiti的任务服务类。
可以从这个类中获取任务的相关信息,如当前正在执行的个人待办和用户组待办任务。
是Activiti的查询历史信息的类,在一个流程执行完成后,这个对象为我们提供查询历史信息,可以跟踪流程实例对应所有待办节点的运行情况。
流程定义类,可以从这里获得资源文件等。
代表流程定义的执行实例,当一个部署的流程图启动后,该流程只有一条流程实例数据,但是它的流程任务可以有多个,每个任务对应流程图中相应的流程节点。
4.入门HelloWorld程序创建流程图方法点击ActivitiTest项目,在src/main/java目录下创建一个diagrams目录用来存放流程图在当前项目右键选择ActivitiDiagram流程图输入流程图名称HelloWorld,然后点击OK,在控制面板的右边栏有相关的画图图标操作其中一个流程必须包含一个开始节点和一个结束节点,结束节点可以有多个。
然后使用StartEvent,UserTask,EndEvent画出下面的流程图,然后用Connection 中的SequenceFlow连线连接起来。