activiti6.0笔记记录,以下全部activiti均基于github。6.x版本
一.activiti 基础入门快速上手
1.0 快速上手
官方示例,演示流程的初始化/启动/加载/执行/历史等.
https://www.activiti.org/quick-start
引入activiti-engine即可.
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>$actVer</version>
</dependency>
代码中初始化ProcessEngine后会自动创建基础流程数据表
后续也会有其他的通过xml配置,接入spring等其他初始化的方法,理论上一样,初始化的时候都会建表.
...
[main] DEBUG org.activiti.engine.impl.db.DbSqlSession - SQL: create table ACT_PROCDEF_INFO (
ID_ varchar(64) not null,
PROC_DEF_ID_ varchar(64) not null,
REV_ integer,
INFO_JSON_ID_ varchar(64),
primary key (ID_)
)
...
engin初始化
核心及engin获取,通过Configuration初始化engin.
ProcessEngineConfiguration cfg = new StandaloneProcessEngineConfiguration()
.setJdbcUrl("jdbc:h2:mem:activiti;DB_CLOSE_DELAY=1000")
.setJdbcUsername("sa")
.setJdbcPassword("")
.setJdbcDriver("org.h2.Driver")
.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
ProcessEngine processEngine = cfg.buildProcessEngine();
流程中其他关键对象均通过ProcessEngin获取.
比如:流程的部署,流程的执行处理,流程历史的查询等.
流程部署
通过RepositoryService 部署 bpmn20.xml格式的流程定义说明
RepositoryService repositoryService = processEngine.getRepositoryService();
//加载流程定义bpmn20.xml 文件来部署流程 (在数据库中生成对应的流程定义)
Deployment deployment = repositoryService.createDeployment()
.addClasspathResource("test.bpmn20.xml").deploy();
//查询
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deployment.getId()).singleResult();
bpmn20.xml格式大体类似如下格式,定义了流程中各个节点条件等属性,流程引擎通过
repositoryService解析加载流程. 每个流程有一个唯一 process id 如下为 test.
该流程表现为如下
流程的启动
通过processEngine获取RuntimeService控制流程的执行.
RuntimeService runtimeService = processEngine.getRuntimeService();
//test 为需要启动的流程定义中process id
//启动实际上为根据流程定义生成一份新的 运行流程运行示例,对应数据库中实际运行的流程数据
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey("test");
流程中的表单参数
流程每一步中可以自定义很多表单参数,比如请假时间/原因/。
引擎提供了对应的Api来查询.
//每一个处理审批步骤都是一个task
TaskService taskService = processEngine.getTaskService();
//-----------------------------------
//获取manager组的待处理任务 (流程启动后,需要manager组审批)
List<Task> tasks = taskService.createTaskQuery()
.taskCandidateGroup("managers").list();
...
//或者
//根据当前人的ID查询
TaskQuery taskQuery = taskService.createTaskQuery().taskCandidateOrAssigned(userId);
List<Task> tasks = taskQuery.list();
//---------------------------------------
//处理表单数据的api
FormService formService = processEngine.getFormService();
Task task = tasks.get(i);
Map<String, Object> variables = new HashMap<String, Object>();
FormData formData = formService.getTaskFormData(task.getId());
for (FormProperty formProperty : formData.getFormProperties()) {
//表单属性-各种字段
...
//根据表单数据字段填入具体数据,请假原因等..
//构造具体表单数据,作为后续流程执行的参数,传入下一步
variables.put(formProperty.getId(), val_reason_str);
}
流程的执行
流程的执行通过processEngine获取的TaskService来控制.
taskService 传入参数 来处理task,
TaskService taskService = processEngine.getTaskService();
//填入参数,完成当前流程节点,进入流程下一步
taskService.complete(task.getId(), variables);
流程执行历史记录
流程的执行历史通过processEngine获取的HistoryService来处理.
HistoryService historyService = processEngine.getHistoryService();
HistoricActivityInstance endActivity = null;
List<HistoricActivityInstance> activities =
historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstance.getId()).finished()
.orderByHistoricActivityInstanceEndTime().asc()
.list();
for (HistoricActivityInstance activity : activities) {
if (activity.getActivityType() == "startEvent") {
...
}
else
...
}
二.activiti-app (activiti-ui)-在线编辑组件
一个新东西,大家从体验来讲,最关心的大概就是能否看到东西,界面就是了。
官方提供了一个在线编辑流程图的web模块。这既是activiti-app (activiti-ui,老版本叫做modeler.html 都是一个东西)
官方说明如下:
https://www.activiti.org/userguide/#activiti.setup
war包的来源
具体这个 activity-app.war包的来源
直接从官网下载
https://github.com/Activiti/Activiti/releases/download/activiti-6.0.0/activiti-6.0.0.zip
或者自己从github下载的6.x代码中activiti-ui模块编译.
本地编译
mvn clean package -DskipTests
要是遇到错误看差哪个模块就到哪个模块目录编译
如下,编译
mvn clean install -DskipTests ,分别处理可能遇到的所有错误,
最后在activiti-ui目录 mvn clean package -DskipTests 生成需要的war包.
此war与官网下载的一样.
部署启动
部署至tomcat,启动默认使用H2数据库,
对解压的\activiti-app\WEB-INF\classes\META-INF\activiti-app\activiti-app.properties 文件中
修改数据库配置后,重启。会在配置的mysql中生成对应的表结构
datasource.driver=com.mysql.jdbc.Driver
datasource.url=jdbc:mysql://127.0.0.1:3306/activiti6ui?characterEncoding=UTF-8
datasource.username=root
datasource.password=123456
#hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.dialect=org.hibernate.dialect.MySQLDialect
启动后会自动建表.
启动完成后访问 http://127.0.0.1:8080/activiti-app/
用户密码 admin/test
其中第一个为编辑流程.
界面如下:
三. 流程相关数据库说明
数据库表结构说明
上述activiti-app部署后自动生成的表数据如下:
这些表中
分别有act_re_/act_ru_/act_id_/act_hi_/act_ge_开头的表,分别可通过后续的各种服务组件来操作.
其中
A. 'act_re_**'表示repository,
这个前缀的表包含了流程定义说明和流程静态资源 (图片,规则,等等)。
B.'act_ru_*'表示runtime。
这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。
task.流程的每一步,待处理任务.
任务处理人.
C.'act_id_'表示identity。
这些表包含身份信息,比如用户,组等等。
Activiti Engine提供了简单的用户及组管理,
用户组:
用户:
正常系统中的用户组比这个复杂很多,需要在自动的用户管理中增删查改的时候,同步处理这几张表的数据同步用户.
Activiti有一个IdentityService接口,通过这个接口可以操控Activiti的act_id_*表的数据,一般的做法是用业务系统的权限管理模块维护用户数据,当进行CRUD操作的时候在原有业务逻辑后面添加同步到Activiti的代码
D.'act_hi_'表示history
这些表包含历史数据,比如历史流程实例, 变量,任务等等。
E.'act_ge_*'表示通用数据,
用于不同场景下,如存放资源文件或者系统配置数据。
其中act_ge_bytearray 存放流程的xml定义文件及生成的流程图片数据 二进制数据. 对应act_re_procdef中的resource字段.
act_ge_property为引擎的系统配置表,定义的一些系统变量
F. 其他表说明
此数据库是通过activiti-ui自动生成的,剩下的表中除 act_evt_log为日志表外,其他均与在线编辑流程相关.
其中 act_de_modal存储了流程的ui设计定义.
四.流程API说明
其他各种服务都是通过processEngine获取的。包括7大服务组件.
processEngine通过 ProcessEnginConfiguration的build来生产,而ProcessEnginConfiguration的产生有很多方法,
比如像本文开始示例中直接通过代码生成,
或者通过文件类配置,此处可以集成spring.
processEngine全项目中唯一一个实例,全项目共用.
ProcessEngine
是一个线程安全的类,在多个线程之间共享。在Web应用程序中,这意味着可以在容器启动时创建一次流程引擎,并在容器停机时关闭引擎
7大服务组件
七大服务组件
官方说明:https://www.activiti.org/userguide/#chapterApi
RepositoryService
提供流程的管理,发布操作
流程部署及流程定义信息的查询,
流程包含的资源文件,比如部署xml文件,引擎自动生成的流程图片的查询等
RuntimeService
查询的是流程实际启动后的实例信息,实际运行的数据,执行管理,
包括启动、推进、删除流程实例等操作
TaskService
为流程的任务管理,流程每一步的处理都可以看作一个task
功能包括查询分配给用户或组的任务
创建新的与流程实例无关的独立任务。
IdentityService
系统中用户及用户组的管理及查询服务.
流程引擎可以将任务分配给任何人或者组,流程引擎是不会检查用户是否存在的。
FormService
一个可选服务,任务表单管理
我们可以使用这个来管理每一个步骤中的表单数据
这里的表单服务功能有限,
定义表单的方式在每个Task标签中定义extensionElements和activiti:formProperty即可,到达这个节点的时候可以通过API读取表单元素。
Activiti官方的入门例子使用的就是在流程定义中设置每一个节点显示什么样的表单哪些字段需要显示、哪些字段只读、哪些字段必填。
但是这种方式仅仅适用于比较简单的流程,对于稍微复杂或者页面需要业务逻辑的判断的情况就不适用了。
对于数据的保存都是在引擎的表中,不利于和其他表的关联、对整个系统的规划也不利!
一般我们可以自定义页面来实现复制表单
HistoryService
历史管理(执行完的数据的管理)
可以查询流程的执行历史实例,历史参数,人员等.
ManagerService
检索有关数据库表和表元数据的信息,一般情况下用不到.
五.流程的查询,参数传递及表达式
查询API
可以如下,通过一个服务的createXXXQuery()来创建查询,后续所有的条件都And链接.
List<Task> tasks = taskService.createTaskQuery() .taskAssignee("kermit") .processVariableValueEquals("orderId", "0815") .orderByDueDate().asc() .list();
runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).active().singleResult();
repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).singleResult()
也可以通过自定sql语句查询
List<Task> tasks = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T WHERE T.NAME_ = #{taskName}")
.parameter("taskName", "gonzoTask")
.list();
long count = taskService.createNativeTaskQuery()
.sql("SELECT count(*) FROM " + managementService.getTableName(Task.class) + " T1, "
+ managementService.getTableName(VariableInstanceEntity.class) + " V1 WHERE V1.TASK_ID_ = T1.ID_")
.count();
流程中参数的传入
参数都是通过一个Map对象传递.
变量都存储在ACT_RU_VARIABLE数据库表
启动流程时的传入参数
Map<String, Object> variables = new HashMap<String, Object>();
variables.put("person", "张三");
ProcessInstance pi = runtimeService.startProcessInstanceByKey("test", variables);
完成当前任务时添加参数
Map<String, Object> variables = var.getVariableMap();
taskService.complete(taskId, variables);
也可以在流程执行期间添加变量。
通过RuntimeService动态改变流程中的变量
//RunTimeService.
void setVariable(String executionId, String variableName, Object value);
流程参数的获取
在开始处理一个任务的时候,可以通过taskervice及taskid获取之前提交的参数.
Map<String, Object> variables = taskService.getVariables(taskId);
流程中的表达式
Activiti使用UEL进行表达式解析,UEL代表统一表达语言,是EE6规范的一部分(有关详细信息,请参阅EE6规范)
值表达式:解析为值。默认情况下,可以使用所有过程变量。此外,
所有spring-beans(如果使用Spring)都可用于表达式:
${myVar}
${myBean.myProperty}
方法表达式:调用带或不带参数的方法。在调用不带参数的方法时,请务必在方法名称后面添加空括号(因为这会将表达式与值表达式区分开来)。传递的参数可以是文字值或自己解析的表达式。例子:
${printer.print()}
${myBean.addNewOrder('orderName')}
${myBean.doSomething(myVar, execution)}
本文中请假审批通过与否的判断条件为 ${agree=='true'}
此参数需要在任务处理完成时带入.
<sequenceFlow id="sid-25084A53-A41D-4E9B-AD65-BDE782C39F18" name="通过" sourceRef="sid-E7EACBCC-F142-43EA-A6B7-150C6B200C4B">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${agree=='true'}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-5E55ADB7-4BFF-40BA-B0B4-0F976CE80CBE" name="不通过" sourceRef="sid-E7EACBCC-F142-43EA-A6B7-150C6B200C4B" targetRef="sid-FADF1853-63C2-4673-997E-791FF4690455">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${agree!='true'}]]></conditionExpression>
</sequenceFlow>
variables.put("agree", "true");
taskService.complete(taskId, variables);
引擎会根据设计的流程图进入下一步骤.
五. 流程表单处理
a.流程表单类型
这个应该是最后开发的主要使用方式了.
普通自定义表单,业务(表单)数据自己的表中独立管理,所有界面自定义实现.
使用
startProcessInstanceByKey businessKey的结合 ,启动时与流程关联.
业务表增加pro instanceid
通过
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).active().singleResult();
//业务数据,比如自定义的流程表单数据的记录id,与开始流程前传入的参数一致
String businessKey = processInstance.getBusinessKey();
b流程动态表单
通过FormService 来获取流程定义时的表单数据,及生成表单界面.简单的可以试试,复杂的估计不太好用.
//处理表单数据的api
FormService formService = processEngine.getFormService();
Task task = tasks.get(i);
Map<String, Object> variables = new HashMap<String, Object>();
FormData formData = formService.getTaskFormData(task.getId());
for (FormProperty formProperty : formData.getFormProperties()) {
//表单属性-各种字段
...
//根据表单数据字段填入具体数据,请假原因等..
//构造具体表单数据,作为后续流程执行的参数,传入下一步
variables.put(formProperty.getId(), val_reason_str);
}
c流程外部表单
同时在定义流程的时候,在提供了一种外部表单key的方式
外部表单数据保存在流程发布的相同目录,
本文基于CC BY-NC-ND 4.0 许可协议发布,作者:野生的喵喵。 固定链接: 【activiti-入门及基础总结(activiti 6.x)】 转载请注明
相关文章: