zoukankan      html  css  js  c++  java
  • 手把手教你如何玩转Activiti工作流

    手把手教你如何玩转Activiti工作流

    版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Cs_hnu_scw/article/details/79059965

    一:Activiti的介绍

    场景:学校    

    主角:阿毛  ,   班主任   ,教务处处长

    问题:有一天,阿毛到学校,感觉到身体不舒服,然后想跟班主任请假,然后班主任告诉阿毛说,你想请假,那么就必须要请假条,这个上面必须要我同意,然后再拿到教务处去盖章,然后交给我,这样才可以进行请假。。阿毛,想着,怎么请个假都这么麻烦,这么多层次处理问题,能不能简便一点。。。。好烦好烦~!!~~

    分析:从上面的小例子,我们可以很明显的得到一个结论,就是:

    请假流程:阿毛------》提交申请-----》班主任审批-----》教务处审批-----》请假成功

    也就是说,这种问题就是一种流式的控制管理,当然,这是最简单的,因为里面没有包含着回馈,相当于只是一个方向。其实,到这里,Activiti的定义就已经出来了。。。。。

    Activiti定义:

    Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务流程图。

    二:牛刀小试---------搭建第一个Activiti项目流程

    环境:IDEA(或者Eclipse,本人这里是用IDEA进行的)

    步骤:

    (1)第一步:IDEA安装Activiti插件

    首先,创建一个普通的Java工程即可,然后按照下面流程进行:

    1:点击菜单中的File(最左上角),选择settings

    2:3

    3:然后点击右边的安装,等待一下就可以啦。

    (2)创建Activiti流图

    (3)创建一个流程图(这里就用一个学生请假实例来进行)

    1:首先选择一个startEvent,也就是流程的开始,并且点击一个额外的界面地方,然后输入该处理流程的名称和ID,这里就输入为shenqing

    2:在选择一个UserTask按钮,表示一个处理任务,同理命名为“请假申请”

    3:在选择一个UserTask按钮,表示一个处理任务,同理命名为“班主任”

    4:在选择一个UserTask按钮,表示一个处理任务,同理命名为“教务处”

    5:选择一个EndEvent按钮,表示流程的结束;

    6:将各个按钮进行连线。(将鼠标放到每个按钮的“正中心”,然后拖着到想要链接的另外一个按钮即可,出现线条)

    7:最终的效果。描述:就是学生提交请假申请——》班主任审核——》教务处审核

    (4)将第三步中创建的shenqing.bpmn文件生成一个png格式的内容。对于这个的话,在IDEA与Eclipse有一点不一样,因为,在Eclipse中,当保存了之后,就会生成一个对应的png的图片,而在IDEA中需要手动进行生成。

    1:首先将shenqing.bpmn的后缀改为xml

    2:当点击xml文件,我们会看到里面之前的文字都是乱码了,那么如何进行解决?

    小点1:找到自己IDEA的安装目录下的bin文件

    小点2:找到如图所示的内容

    小点3:分别打开这两个文件,然后添加一行内容(追加到最后即可):

    小点4:保存内容,然后重启IDEA,就会发现不会乱码了

    3:右击xml文件,然后选择:

    4:然后继续:

    保存到对应的工程下面即可。就会看到有个shenqing.png的内容出现

    5:将之前修改为xml的文件的后缀改回原来的bpmn.

    (5)创建一个acitiviti.cfg.xml文件,放在src目录下即可。这个主要是用于存放后面acitivi部署流程中,创建的相关联的一些表。

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4.  
    5. <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
    6. <property name="jdbcDriver" value="com.mysql.jdbc.Driver"></property>
    7. <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activititest?useUnicode=true&characterEncoding=utf8"></property>
    8. <property name="jdbcUsername" value="xxxxxx"></property>
    9. <property name="jdbcPassword" value="xxxxxxxx"></property>
    10. <!--
    11. 创建表的策略
    12. -->
    13. <property name="databaseSchemaUpdate" value="true"></property>
    14. </bean>
    15. </beans>

    (6)导入Activiti的包--------当然也可以直接通过Maven进行依赖包的管理

    (7)创建一个数据库生成的测试。(注意:要保证本地有对应名字的数据库)

    1. package com.hnu.scw.activiti;
    2. import org.activiti.engine.ProcessEngine;
    3. import org.activiti.engine.ProcessEngineConfiguration;
    4. import org.junit.Test;
    5. /**
    6. * @author scw
    7. * @create 2018-01-15 11:06
    8. * @desc 从数据源和流程图中,生成一个数据库表(这个就是Activiti流程控制的关键的数据表)
    9. **/
    10. public class ActivitiTable {
    11. /**
    12. * 创建Activiti流的相关的数据库表
    13. */
    14. @Test
    15. public void creatTable(){
    16. ProcessEngine processEngine = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
    17. .buildProcessEngine();
    18. }
    19. }

    如果,运行测试方法成功之后,再进入数据库,我们会看到产生了如下多张数据表(23张):

    后面我会再详细讲解这每个表的作用,也是activiti的关键所在。

    (8)进行流程部署的重点开发(按照下面的流程进行)------------重点的重点

    1. package com.hnu.scw.activiti;
    2. import org.activiti.engine.ProcessEngine;
    3. import org.activiti.engine.ProcessEngines;
    4. import org.activiti.engine.task.Task;
    5. import org.junit.Test;
    6. import java.util.List;
    7. /**
    8. * @author scw
    9. * @create 2018-01-15 11:04
    10. * @desc 用于进行演示Activiti的首例程序,即描述如何在代码中实现学生进行请假申请,班主任审核,教务处审核
    11. **/
    12. public class ActivitiTest {
    13.  
    14. /**
    15. * 1、部署流程
    16. * 2、启动流程实例
    17. * 3、请假人发出请假申请
    18. * 4、班主任查看任务
    19. * 5、班主任审批
    20. * 6、最终的教务处Boss审批
    21. */
    22. /**
    23. * 1:部署一个Activiti流程
    24. * 运行成功后,查看之前的数据库表,就会发现多了很多内容
    25. */
    26. @Test
    27. public void creatActivitiTask(){
    28. //加载的那两个内容就是我们之前已经弄好的基础内容哦。
    29. //得到了流程引擎
    30. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    31. processEngine.getRepositoryService()
    32. .createDeployment()
    33. .addClasspathResource("shenqing.bpmn")
    34. .addClasspathResource("shenqing.png")
    35. .deploy();
    36. }
    37. /**
    38. * 2:启动流程实例
    39. */
    40. @Test
    41. public void testStartProcessInstance(){
    42. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    43. processEngine.getRuntimeService()
    44. .startProcessInstanceById("shenqing:1:4"); //这个是查看数据库中act_re_procdef表
    45. }
    46. /**
    47. * 完成请假申请
    48. */
    49. @Test
    50. public void testQingjia(){
    51. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    52. processEngine.getTaskService()
    53. .complete("104"); //查看act_ru_task表
    54. }
    55.  
    56. /**
    57. * 小明学习的班主任小毛查询当前正在执行任务
    58. */
    59. @Test
    60. public void testQueryTask(){
    61. //下面代码中的小毛,就是我们之前设计那个流程图中添加的班主任内容
    62. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    63. List<Task> tasks = processEngine.getTaskService()
    64. .createTaskQuery()
    65. .taskAssignee("小毛")
    66. .list();
    67. for (Task task : tasks) {
    68. System.out.println(task.getName());
    69. }
    70. }
    71.  
    72. /**
    73. * 班主任小毛完成任务
    74. */
    75. @Test
    76. public void testFinishTask_manager(){
    77. ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
    78. engine.getTaskService()
    79. .complete("202"); //查看act_ru_task数据表
    80. }
    81.  
    82. /**
    83. * 教务处的大毛完成的任务
    84. */
    85. @Test
    86. public void testFinishTask_Boss(){
    87. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    88. processEngine.getTaskService()
    89. .complete("302"); //查看act_ru_task数据表
    90. }
    91. }

    注意:通过上面的代码,一个个@Test,过来,主要是查看act_get_bytearray,act_ru_task和act_re_procdef三张表,当每进行不同的代码的时候,记得关注一下数据库的变化哦。。。你就会发现其中的奥秘的,

    (9)小试牛刀的审批流程,基本完成。。。。。。。项目结构如下所示:

    三:Activiti流程部署的方法

    描述:对于流程处理, 第一步就是要进行流程的部署操作,在”小试牛刀“上面的代码中,主要是采取读取bpmn和png的资源文件的方法,那么除了这种方法之外,还有其他的方法吗?

    备注:首先,说一下,在接下来的操作的时候,主要看下面的三张表的改变:

    1. 涉及到的表
    2. * act_ge_bytearray:
    3. * 1、英文解释
    4. * act:activiti
    5. * ge:general
    6. * bytearray:二进制
    7. * 2、字段
    8. * name_:文件的路径加上名称
    9. * bytes_:存放内容
    10. * deployment_id_:部署ID
    11. * 3、说明:
    12. * 如果要查询文件(bpmn和png),需要知道deploymentId
    13. * act_re_deployment
    14. * 1、解析
    15. * re:repository
    16. * deployment:部署 用户描述一次部署
    17. * 2、字段
    18. * ID_:部署ID 主键
    19. * act_re_procdef
    20. * 1、解释
    21. * procdef: process definition 流程定义
    22. * 2、字段
    23. * id_:pdid:pdkey:pdversion:随机数
    24. * name:名称
    25. * key:名称
    26. * version:版本号
    27. * 如果名称不变,每次部署,版本号加1
    28. * 如果名称改变,则版本号从1开始计算
    29. * deployment_id_:部署ID
     涉及到的表
    	 *      act_ge_bytearray:
    	 *        1、英文解释
    	 *           act:activiti
    	 *           ge:general
    	 *           bytearray:二进制
    	 *        2、字段
    	 *           name_:文件的路径加上名称
    	 *           bytes_:存放内容
    	 *           deployment_id_:部署ID
    	 *        3、说明:
    	 *             如果要查询文件(bpmn和png),需要知道deploymentId
    	 *      act_re_deployment
    	 *        1、解析
    	 *           re:repository
    	 *           deployment:部署  用户描述一次部署
    	 *        2、字段
    	 *            ID_:部署ID  主键
    	 *      act_re_procdef
    	 *        1、解释
    	 *            procdef: process definition  流程定义
    	 *        2、字段
    	 *            id_:pdid:pdkey:pdversion:随机数
    	 *            name:名称
    	 *            key:名称
    	 *            version:版本号
    	 *                如果名称不变,每次部署,版本号加1
    	 *                如果名称改变,则版本号从1开始计算
    	 *            deployment_id_:部署ID

    方法一:

    1. /**
    2. * 通过bpmn和png资源进行部署
    3. */
    4. @Test
    5. public void testDeployFromClasspath(){
    6. //得到流程引擎
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. processEngine.getRepositoryService()
    9. .createDeployment()
    10. .addClasspathResource("shenqing.bpmn")
    11. .addClasspathResource("shenqing.png")
    12. .deploy();
    13. }

    方法二:

    1. /**
    2. * 通过 inputstream完成部署
    3. */
    4. @Test
    5. public void testDeployFromInputStream(){
    6. InputStream bpmnStream = this.getClass().getClassLoader().getResourceAsStream("shenqing.bpmn");
    7. //得到流程引擎
    8. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    9. processEngine.getRepositoryService()
    10. .createDeployment()
    11. .addInputStream("shenqing.bpmn", bpmnStream)
    12. .deploy();
    13. }

    方法三:

    1. /**
    2. * 通过zipinputstream完成部署
    3. * 注意:这个的话,需要将bpmn和png文件进行压缩成zip文件,然后放在项目src目录下即可(当然其他目录也可以)
    4. */
    5. @Test
    6. public void testDeployFromZipinputStream(){
    7. InputStream in = this.getClass().getClassLoader().getResourceAsStream("shenqing.zip");
    8. ZipInputStream zipInputStream = new ZipInputStream(in);
    9. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    10. processEngine.getRepositoryService()
    11. .createDeployment()
    12. .addZipInputStream(zipInputStream)
    13. .deploy();
    14. }

    删除已经部署的Activiti的代码:

    1. /**
    2. * 删除已经部署的Activiti流程
    3. */
    4. @Test
    5. public void testDelete(){
    6. //得到流程引擎
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. //第一个参数是部署的流程的ID,第二个true表示是进行级联删除
    9. processEngine.getRepositoryService()
    10. .deleteDeployment("601",true);
    11. }

    四:关于流程部署相关的其他API的示例

    (1)

    1. /**
    2. * 根据名称查询流程部署
    3. */
    4. @Test
    5. public void testQueryDeploymentByName(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. List<Deployment> deployments = processEngine.getRepositoryService()
    8. .createDeploymentQuery()
    9. .orderByDeploymenTime()//按照部署时间排序
    10. .desc()//按照降序排序
    11. .deploymentName("请假流程")
    12. .list();
    13. for (Deployment deployment : deployments) {
    14. System.out.println(deployment.getId());
    15. }
    16. }

    数据库情况:

    执行后输出:

    801

    (2)

    1. /**
    2. * 查询所有的部署流程
    3. */
    4. @Test
    5. public void queryAllDeplyoment(){
    6. //得到流程引擎
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. List<Deployment> lists = processEngine.getRepositoryService()
    9. .createDeploymentQuery()
    10. .orderByDeploymenTime()//按照部署时间排序
    11. .desc()//按照降序排序
    12. .list();
    13. for (Deployment deployment:lists) {
    14. System.out.println(deployment.getId() +" 部署名称" + deployment.getName());
    15. }
    16. }

    数据库情况:

    程序执行后输出:

    801    部署名称请假流程

    (3)

    1. /**
    2. * 查询所有的流程定义
    3. */
    4. @Test
    5. public void testQueryAllPD(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. List<ProcessDefinition> pdList = processEngine.getRepositoryService()
    8. .createProcessDefinitionQuery()
    9. .orderByProcessDefinitionVersion()
    10. .desc()
    11. .list();
    12. for (ProcessDefinition pd : pdList) {
    13. System.out.println(pd.getName());
    14. }
    15. }

    数据库情况:

    程序执行后输出:

    shenqing

    (4)

    1. /**
    2. * 查看流程图
    3. * 根据deploymentId和name(在act_ge_bytearray数据表中)
    4. */
    5. @Test
    6. public void testShowImage() throws Exception{
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. InputStream inputStream = processEngine.getRepositoryService()
    9. /**
    10. * deploymentID
    11. * 文件的名称和路径
    12. */
    13. .getResourceAsStream("801","shenqing.png");
    14. OutputStream outputStream3 = new FileOutputStream("e:/processimg.png");
    15. int b = -1 ;
    16. while ((b=inputStream.read())!=-1){
    17. outputStream3.write(b);
    18. }
    19. inputStream.close();
    20. outputStream3.close();
    21. }

    数据库情况:

    (5)

    1. /**
    2. * 根据pdid查看图片(在act_re_procdef数据表中)
    3. * @throws Exception
    4. */
    5. @Test
    6. public void testShowImage2() throws Exception{
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. InputStream inputStream = processEngine.getRepositoryService()
    9. .getProcessDiagram("shenqing:1:804");
    10. OutputStream outputStream = new FileOutputStream("e:/processimg.png");
    11. int b = -1 ;
    12. while ((b=inputStream.read())!=-1){
    13. outputStream.write(b);
    14. }
    15. inputStream.close();
    16. outputStream.close();
    17. }

    数据库情况:

    (6)

    1. /**
    2. * 查看bpmn文件(在act_re_procdef数据表中)
    3. */
    4. @Test
    5. public void testShowBpmn() throws Exception{
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. InputStream inputStream = processEngine.getRepositoryService()
    8. .getProcessModel("shenqing:1:804");
    9. OutputStream outputStream = new FileOutputStream("e:/processimg.bpmn");
    10. int b = -1 ;
    11. while ((b=inputStream.read())!=-1){
    12. outputStream.write(b);
    13. }
    14. inputStream.close();
    15. outputStream.close();
    16. }

    数据库情况:

    五:关于流程实例的相关API

    涉及到的表:

     *    act_hi_actinst
     *     1、说明
     *         act:activiti
     *         hi:history
     *         actinst:activity instance
     *            流程图上出现的每一个元素都称为activity
     *            流程图上正在执行的元素或者已经执行完成的元素称为activity instance
     *      2、字段
     *         proc_def_id:pdid
     *         proc_inst_id:流程实例ID
     *         execution_id_:执行ID
     *         act_id_:activity
     *         act_name
     *         act_type
     *    act_hi_procinst
     *      1、说明
     *         procinst:process instance  历史的流程实例
     *            正在执行的流程实例也在这张表中
     *         如果end_time_为null,说明正在执行,如果有值,说明该流程实例已经结束了
     *    act_hi_taskinst
     *      1、说明
     *          taskinst:task instance  历史任务
     *             正在执行的任务也在这张表中
     *             如果end_time_为null,说明该任务正在执行
     *             如果end_time不为null,说明该任务已经执行完毕了
     *    act_ru_execution
     *      1、说明
     *         ru:runtime
     *         代表正在执行的流程实例表
     *         如果当期正在执行的流程实例结束以后,该行在这张表中就被删除掉了,所以该表也是一个临时表
     *      2、字段
     *         proc_inst_id_:piid  流程实例ID,如果不存在并发的情况下,piid和executionID是一样的
     *         act_id:当前正在执行的流程实例(如果不考虑并发的情况)的正在执行的activity有一个,所以act_id就是当前正在执行的流程实例的正在执行的
     *           节点
     *    act_ru_task
     *      1、说明
     *         代表正在执行的任务表
     *         该表是一个临时表,如果当前任务被完成以后,任务在这张表中就被删除掉了
     *      2、字段
     *          id_:  主键    任务ID
     *          execution_id_:执行ID  
     *              根据该ID查询出来的任务肯定是一个
     *          proc_inst_id:piid
     *              根据该id查询出来的任务
     *                 如果没有并发,则是一个
     *                 如果有并发,则是多个
     *          name_:任务的名称
     *          assignee_:任务的执行人

    (1)启动流程实例

    方法一:

    1. /**
    2. * 启动流程实例,通过PID
    3. */
    4. @Test
    5. public void testStartProcessInstanceByPID(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. ProcessInstance processInstance = processEngine.getRuntimeService()
    8. .startProcessInstanceById("shenqing:1:804"); //这个就是从部署的时候生成的一个内容,如下数据库所示
    9. System.out.println(processInstance.getId());
    10. }

    方法二:

    1. /**
    2. * 根据pdkey启动流程实例,默认启动最高版本的
    3. */
    4. @Test
    5. public void testStartPIByPDKEY(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. processEngine.getRuntimeService()
    8. .startProcessInstanceByKey("shenqing"); //这个字段对应上面那个数据库中的Key字段
    9. }

    对应的数据库内容:

    执行后:(就多出了一条流程)

    (2)完成任务

    1. /**
    2. * 完成任务
    3. */
    4. @Test
    5. public void testFinishTask(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. processEngine.getTaskService()
    8. .complete("1102");
    9. }

    对应的表:

    执行后的情况:(注意表不同了,原来那个表的字段ID的条目信息,就没了)

    (3)

    1. /**
    2. * 查询任务
    3. * 根据任务的执行人查询正在执行任务(通过act_ru_task数据表)
    4. */
    5. @Test
    6. public void testQueryTaskByAssignee(){
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. /**
    9. * 当前班主任小毛人这个人当前正在执行的所有的任务
    10. */
    11. List<Task> tasks = processEngine.getTaskService()
    12. .createTaskQuery()
    13. .orderByTaskCreateTime()
    14. .desc()
    15. .taskAssignee("小毛")
    16. .list();
    17. for (Task task : tasks) {
    18. System.out.println(task.getName());
    19. System.out.println(task.getAssignee());
    20. }
    21. }

    数据库情况:

    程序执行后,输出:

    班主任
    小毛

    (4)

    1. /**
    2. * 查询所有的正在执行的任务
    3. */
    4. @Test
    5. public void testQueryTask(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. List<Task> tasks = processEngine.getTaskService()
    8. .createTaskQuery()
    9. .list();
    10. for (Task task : tasks) {
    11. System.out.println(task.getName());
    12. }
    13. }

    数据库情况:

    程序执行后,输出内容:

    请假申请
    班主任
    请假申请

    (5)

    1. /**
    2. * 根据piid查询任务
    3. */
    4. @Test
    5. public void testQueryTaskByPIID(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. List<Task> tasks = processEngine.getTaskService()
    8. .createTaskQuery().executionId("1001")
    9. .list();
    10. for (Task task : tasks) {//因为没有并发,所以就有一个
    11. System.out.println(task.getName());
    12. }
    13. }

    数据库情况:

    程序执行后输出:

    班主任

    (6)

    1. /**
    2. * 根据piid得到当前正在执行的流程实例的正在活动的节点
    3. */
    4. @Test
    5. public void testActivity(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. /**
    8. * 根据piid得到流程实例
    9. */
    10. ProcessInstance pi = processEngine.getRuntimeService()
    11. .createProcessInstanceQuery()
    12. .processInstanceId("1001")
    13. .singleResult();
    14. String activityId = pi.getActivityId();//当前流程实例正在执行的activityId
    15. System.out.println(activityId);
    16. }

    数据库情况:

    程序执行后输出:

    班主任

    (7)查询历史执行的任务(这个包括当前在执行的和已经执行过的任务,可以通过Delete_Reason这个字段进行区别)

    1. /**
    2. * 查看已经完成的任务和当前在执行的任务
    3. */
    4. @Test
    5. public void findHistoryTask(){
    6. ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
    7. //如果只想获取到已经执行完成的,那么就要加入completed这个过滤条件
    8. List<HistoricTaskInstance> historicTaskInstances1 = defaultProcessEngine.getHistoryService()
    9. .createHistoricTaskInstanceQuery()
    10. .taskDeleteReason("completed")
    11. .list();
    12. //如果只想获取到已经执行完成的,那么就要加入completed这个过滤条件
    13. List<HistoricTaskInstance> historicTaskInstances2 = defaultProcessEngine.getHistoryService()
    14. .createHistoricTaskInstanceQuery()
    15. .list();
    16. System.out.println("执行完成的任务:" + historicTaskInstances1.size());
    17. System.out.println("所有的总任务数(执行完和当前未执行完):" +historicTaskInstances2.size());
    18. }

    执行结果:

    执行完成的任务:1
    所有的总任务数(执行完和当前未执行完):3

    六:关于ProcessDefinitionEntity(流程定义实体)的相关内容

    上面的这个图就是对于一个流程的相关内容,这部分要特别注意,是非常重要的一个内容。

    1. package com.hnu.scw.activiti.activityimpl;
    2. import java.util.List;
    3. import org.activiti.engine.ProcessEngine;
    4. import org.activiti.engine.ProcessEngines;
    5. import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    6. import org.activiti.engine.impl.pvm.PvmTransition;
    7. import org.activiti.engine.impl.pvm.process.ActivityImpl;
    8. import org.activiti.engine.runtime.ProcessInstance;
    9. import org.junit.Test;
    10.  
    11. public class ProcessDefinitionEntityTest {
    12. /**
    13. * 根据pdid得到processDefinitionEntity
    14. */
    15. @Test
    16. public void testProcessDefinitionEntity(){
    17. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    18. /**
    19. * 根据pdid得到ProcessDefinitionEntry
    20. */
    21. ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService()
    22. .getProcessDefinition("qingjia1:1:804");
    23.  
    24. }
    25.  
    26. /**
    27. * 根据pdid得到processDefinitionEntity中的activityimpl
    28. */
    29. @Test
    30. public void testGetActivityImpl(){
    31. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    32. /**
    33. * 根据pdid得到ProcessDefinitionEntry
    34. */
    35. ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService()
    36. .getProcessDefinition("qingjia1:1:804");
    37. /**
    38. * ActivityImpl是一个对象
    39. * 一个activityImpl代表processDefinitionEntity中的一个节点
    40. */
    41. List<ActivityImpl> activityImpls = processDefinitionEntity.getActivities();
    42. for (ActivityImpl activityImpl : activityImpls) {
    43. System.out.println(activityImpl.getId());
    44. System.out.print("hegiht:"+activityImpl.getHeight());
    45. System.out.print(""+activityImpl.getWidth());
    46. System.out.print(" x:"+activityImpl.getX());
    47. System.out.println(" y:"+activityImpl.getY());
    48. }
    49. }
    50.  
    51. /**
    52. * 得到ProcessDefinitionEntity中的所有的ActivityImpl的所有的PvmTransition
    53. */
    54. @Test
    55. public void testSequenceFlow(){
    56. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    57. /**
    58. * 根据pdid得到ProcessDefinitionEntry
    59. */
    60. ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService()
    61. .getProcessDefinition("qingjia1:1:804");
    62.  
    63. /**
    64. * ActivityImpl是一个对象
    65. * 一个activityImpl代表processDefinitionEntity中的一个节点
    66. */
    67. List<ActivityImpl> activityImpls = processDefinitionEntity.getActivities();
    68. for (ActivityImpl activityImpl : activityImpls) {
    69. /**
    70. * 得到一个activityimpl的所有的outgoing
    71. */
    72. List<PvmTransition> pvmTransitions = activityImpl.getOutgoingTransitions();
    73. for (PvmTransition pvmTransition : pvmTransitions) {
    74. System.out.println("sequenceFlowId:"+pvmTransition.getId());
    75. }
    76. }
    77. }
    78.  
    79. /**
    80. * 得到当前正在执行的流程实例的activityimpl-->PvmTransition
    81. */
    82. @Test
    83. public void testQueryActivityImpl_Ing(){
    84. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    85. ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity)processEngine.getRepositoryService()
    86. .getProcessDefinition("qingjia:1:504");
    87. //根据piid获取到activityId
    88. ProcessInstance pi = processEngine.getRuntimeService()
    89. .createProcessInstanceQuery()
    90. .processInstanceId("1001")
    91. .singleResult();
    92. //根据流程实例得到当前正在执行的流程实例的正在执行的节点
    93. ActivityImpl activityImpl = processDefinitionEntity.findActivity(pi.getActivityId());
    94. System.out.print("流程实例ID:"+pi.getId());
    95. System.out.print(" 当前正在执行的节点:"+activityImpl.getId());
    96. System.out.print(" hegiht:"+activityImpl.getHeight());
    97. System.out.print(" "+activityImpl.getWidth());
    98. System.out.print(" x:"+activityImpl.getX());
    99. System.out.println(" y:"+activityImpl.getY());
    100. }
    101. }

    七:通过当前系统登陆用户,获取到的相关Activiti内容

    备注:上面这个流程图,一定要根据上面的知识点来进行推到学习,一定要弄清楚每个内容对应的属性和对象指的是什么,因为这个在实际的开发项目中,是非常有用,并且是经常进行使用的内容。

    上面图所对应的代码如下:

    1. package com.hnu.scw.activiti.utils;
    2. import java.util.ArrayList;
    3. import java.util.List;
    4. import org.activiti.engine.ProcessEngine;
    5. import org.activiti.engine.ProcessEngines;
    6. import org.activiti.engine.repository.ProcessDefinition;
    7. import org.activiti.engine.runtime.ProcessInstance;
    8. import org.activiti.engine.task.Task;
    9. public class ActivitiUtils {
    10. /**
    11. * 当前用户-->当前用户正在执行的任务--->当前正在执行的任务的piid-->该任务所在的流程实例
    12. * @param assignee
    13. * @return
    14. */
    15. public static List<ProcessInstance> getPIByUser(String assignee){
    16. List<ProcessInstance> pis = new ArrayList<ProcessInstance>();
    17. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    18. /**
    19. * 该用户正在执行的任务
    20. */
    21. List<Task> tasks = processEngine.getTaskService()
    22. .createTaskQuery()
    23. .taskAssignee(assignee)
    24. .list();
    25. for (Task task : tasks) {
    26. /**
    27. * 根据task-->piid-->pi
    28. */
    29. String piid = task.getProcessInstanceId();
    30. ProcessInstance pi = processEngine.getRuntimeService()
    31. .createProcessInstanceQuery()
    32. .processInstanceId(piid)
    33. .singleResult();
    34. pis.add(pi);
    35. }
    36. return pis;
    37. }
    38.  
    39. /**
    40. * 根据当前的登录人能够推导出所在的流程定义
    41. */
    42. public static void getProcessInstance(String assignee){
    43. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    44. List<Task> tasks = processEngine.getTaskService()
    45. .createTaskQuery()
    46. .taskAssignee(assignee)
    47. .list();
    48. for (Task task : tasks) {
    49. String pdid = task.getProcessDefinitionId();
    50. ProcessDefinition processDefinition = processEngine.getRepositoryService()
    51. .createProcessDefinitionQuery()
    52. .processDefinitionId(pdid)
    53. .singleResult();
    54. }
    55. }
    56. }

    八:详细解析Task任务(非常重要)

    任务的概念:需要有人进行审批或者申请的为任务

    任务的执行人的情况类型:

     情况一:当没有进入该节点之前,就可以确定任务的执行人
      实例:比如进行“请假申请”的流程时候,最开始执行的就是提交”请假申请“,那么就需要知道,谁提交的“请假”,很明显,在一个系统中,谁登陆到系统里面,谁就有提交“请假任务”的提交人,那么执行人就可以确定就是登录人。
    情况二:有可能一个任务节点的执行人是固定的。

           实例:比如,在“公司财务报账”的流程中,最后一个审批的人,一定是财务部的最大的BOSS,所以,这样该流程的最后一个节点执行人,是不是就已经确定是为“财务部最大BOSS”了。

    情况三:一个节点任务,之前是不存在执行人(未知),只有当符合身份的人,登陆系统,进入该系统,才能确定执行人。

    实例:比如,如果当前的流程实例正在执行“自荐信审批”,这个时候,自荐信审批没有任务执行人,因为审批人是可以很多个,无法确定到底是谁,只有当咨询员登录系统以后才能给该任务赋值执行人,即存在只要是咨询员登陆,那么就可以看到所有的“自荐信”。

     情况四:一个任务节点有n多人能够执行该任务,但是只要有一个人执行完毕就完成该任务了:组任务

    实例:比如,“进入地铁站通道”的流程,我们一般地铁都是有N个安全检查的入口,有很多个人在进行检查,那么我们要想通过检查,那么任意一个检察员只要通过即可。

    详细分析:

    针对情况一:

    步骤:

    (1)首先构建流程图:(注意区别上面的第一次画的内容)

    (2)将bpmn的内容,生成一个png的图片(这个操作方法,上面都已经很详细了,不多说)

    (3)代码实现步骤:

    1:

    1. /**
    2. * 部署流程
    3. */
    4. @Test
    5. public void startDeployTest(){
    6. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    7. processEngine.getRepositoryService()
    8. .createDeployment()
    9. .name("请假流程:情况一")
    10. .addClasspathResource("com/hnu/scw/task/shenqing.bpmn")
    11. .deploy();
    12. }

    数据库情况:

    2:

    1. /**
    2. * 启动流程实例
    3. * 可以设置一个流程变量
    4. */
    5. @Test
    6. public void testStartPI(){
    7. /**
    8. * 流程变量
    9. * 给<userTask id="请假申请" name="请假申请" activiti:assignee="#{student}"></userTask>
    10. * 的student赋值
    11. */
    12. Map<String, Object> variables = new HashMap<String, Object>();
    13. variables.put("student", "小明");
    14. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    15. processEngine.getRuntimeService()
    16. .startProcessInstanceById("shenqing1:1:1304",variables);
    17. }

    数据库情况:

    分析:如果,我们安装下面的代码执行,那么就出出现如下的错误

    1. /**
    2. * 启动流程实例
    3. * 可以设置一个流程变量
    4. */
    5. @Test
    6. public void testStartPI(){
    7. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    8. processEngine.getRuntimeService()
    9. .startProcessInstanceById("shenqing1:1:1304");
    10. }

    原因:是否还记得,我们在画流程图的时候,对该请假申请的节点,分配了一个#{student},这个变量,这个其实含义就是说,当我们进行该节点的处理的时候,就需要分配一个执行人,如果没有分配,就会发生上面的错误。然后再回头想一下,是不是就是我们的第一种情况呢?因为,在进行请假的流程的执行开始的时候,其实申请人是已经可以确定了,就是登陆的用户。

    3:后面的代码如下:

    1. /**
    2. * 在完成请假申请的任务的时候,给班主任审批的节点赋值任务的执行人
    3. */
    4. @Test
    5. public void testFinishTask_Teacher(){
    6. Map<String, Object> variables = new HashMap<String, Object>();
    7. variables.put("teacher", "我是小明的班主任");
    8. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    9. processEngine.getTaskService()
    10. .complete("1405", variables); //完成任务的同时设置流程变量
    11. }
    12.  
    13. /**
    14. * 在完成班主任审批的情况下,给教务处节点赋值
    15. */
    16. @Test
    17. public void testFinishTask_Manager(){
    18. Map<String, Object> variables = new HashMap<String, Object>();
    19. variables.put("manager", "我是小明的教务处处长");
    20. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    21. processEngine.getTaskService()
    22. .complete("1603", variables); //完成任务的同时设置流程变量
    23. }
    24.  
    25. /**
    26. * 结束流程实例
    27. */
    28. @Test
    29. public void testFinishTask(){
    30. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    31. processEngine.getTaskService()
    32. .complete("1703");
    33. }

    总结:针对情况一,那么我们必须要进入该节点执行前,就要分配一个执行人。

    情况二:这个情况的话,这里不多介绍,因为之前的知识点中,都是在画流程图的时候就已经分配这个执行人了。可以回头去看看。
    情况三:

    步骤:(1)画流程图,这里不多介绍,就说一下需要修改的地方。

    (2)编写的TaskListener监听类

    1. package com.hnu.scw.tasklistener;
    2. import org.activiti.engine.delegate.DelegateTask;
    3. import org.activiti.engine.delegate.TaskListener;
    4. /**
    5. * @author Administrator
    6. * @create 2018-01-16 11:10
    7. * @desc tack任务的监听,主要是为了动态分配执行人
    8. **/
    9. public class MyTaskListener implements TaskListener {
    10. @Override
    11. public void notify(DelegateTask delegateTask) {
    12. /**
    13. * 任务的执行人可以动态的赋值
    14. * 1、流程变量
    15. * 可以通过提取流程变量的方式给任务赋值执行人
    16. * 2、可以操作数据库
    17. * 方法一:(必须在web环境) WebApplicationContext ac = WebApplicationContextUtils
    18. * .getWebApplicationContext(ServletActionContext.getServletContext());
    19. xxxxService xxxxService = (xxxxService) ac.getBean("xxxxService");
    20. 方法二:通过JDBC来进行数据库操作
    21. */
    22. //动态分配(这里是从上一节点中的tack变量的map中获取,只有流程没有结束,所有的变量都是可以获取)
    23. /*String value = (String)delegateTask.getVariable("aaa");
    24. delegateTask.setAssignee(value);*/
    25. //静态分配(用于确定该执行人就只有一种情况,是一种固定的)
    26. delegateTask.setAssignee("我是班主任");
    27. }
    28. }

    通过这样的方式的话,当有“请假申请”进行提交之后,“班主任”的这个节点,就会自动进行分配执行人。

    情况四:

    流程图如下:

    具体的测试代码:(注意看写的注释内容,就明白了对应的数据库的什么表)

    1. package com.hnu.scw.test;
    2. import org.activiti.engine.ProcessEngine;
    3. import org.activiti.engine.ProcessEngines;
    4. import org.activiti.engine.task.IdentityLink;
    5. import org.activiti.engine.task.Task;
    6. import org.junit.Test;
    7. import java.util.List;
    8.  
    9. /**
    10. * @author scw
    11. * @create 2018-01-23 15:45
    12. * @desc 关于对于组任务的测试内容
    13. **/
    14. public class GroupTaskTest {
    15. /**
    16. * 主要是对于某些任务流程中,有N个人,但是只需要其中的某一个通过,
    17. * 则该任务就通过了,所以针对这样的业务需求,就有如下的内容
    18. */
    19. @Test
    20. public void deployTashTest(){
    21. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    22. processEngine.getRepositoryService()
    23. .createDeployment()
    24. .addClasspathResource("com/hnu/scw/test/task3.bpmn")
    25. .addClasspathResource("com/hnu/scw/test/task3.png")
    26. .name("组任务的测试")
    27. .deploy();
    28. }
    29. /**
    30. * 当启动完流程实例以后,进入了"电脑维修"节点,该节点是一个组任务
    31. * 这个时候,组任务的候选人就会被插入到两张表中
    32. * act_ru_identitylink 存放的是当前正在执行的组任务的候选人
    33. * act_hi_identitylink
    34. */
    35. @Test
    36. public void processTaskStartTest(){
    37. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    38. processEngine.getRuntimeService()
    39. .startProcessInstanceByKey("task3");
    40. }
    41. /**
    42. * 对于act_hi_identitylink表,根据任务ID,即TASK_ID字段查询候选人
    43. */
    44. @Test
    45. public void testQueryCandidateByTaskId(){
    46. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    47. List<IdentityLink> identityLinks = processEngine.getTaskService()
    48. .getIdentityLinksForTask("2104");
    49. for (IdentityLink identityLink : identityLinks) {
    50. System.out.println(identityLink.getUserId());
    51. }
    52. }
    53.  
    54. /**
    55. * 对于act_hi_identitylink表,根据候选人,即USER_ID_查看组任务
    56. */
    57. @Test
    58. public void testQueryTaskByCandidate(){
    59. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    60. List<Task> tasks = processEngine.getTaskService()
    61. .createTaskQuery()
    62. .taskCandidateUser("工程师1")
    63. .list();
    64. for (Task task : tasks) {
    65. System.out.println(task.getName());
    66. }
    67. }
    68. /**
    69. * 候选人中的其中一个人认领任务
    70. */
    71. @Test
    72. public void testClaimTask(){
    73. ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    74. processEngine.getTaskService()
    75. /**
    76. * 第一个参数为taskId
    77. * 第二个参数为认领人
    78. */
    79. .claim("2104", "工程师2");
    80. }
    81.  
    82. }

    九:实际项目中的关于Activiti的工具类方法封装

    1. package com.hnu.scw.activiti.utils;
    2. import org.activiti.engine.ProcessEngine;
    3. import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
    4. import org.activiti.engine.impl.pvm.PvmActivity;
    5. import org.activiti.engine.impl.pvm.PvmTransition;
    6. import org.activiti.engine.impl.pvm.process.ActivityImpl;
    7. import org.activiti.engine.repository.Deployment;
    8. import org.activiti.engine.repository.ProcessDefinition;
    9. import org.activiti.engine.runtime.ProcessInstance;
    10. import org.activiti.engine.task.Task;
    11. import org.springframework.beans.factory.annotation.Autowired;
    12. import org.springframework.stereotype.Component;
    13.  
    14. import javax.annotation.Resource;
    15. import java.io.File;
    16. import java.io.FileInputStream;
    17. import java.io.IOException;
    18. import java.io.InputStream;
    19. import java.util.HashMap;
    20. import java.util.List;
    21. import java.util.Map;
    22. import java.util.zip.ZipInputStream;
    23.  
    24. /**
    25. * @author scw
    26. * @create 2018-01-24 9:51
    27. * @desc 针对流程管理的工具类
    28. **/
    29. @Component("activitiUtils")
    30. public class ActivitiUtils {
    31. @Resource(name = "processEngine")
    32. private ProcessEngine processEngine;
    33.  
    34. /**
    35. * 部署流程
    36. * @param file 流程的zip文件
    37. * @param processName 流程的名字
    38. * @throws IOException
    39. */
    40. public void deployeProcess(File file , String processName)throws IOException{
    41. InputStream inputStream = new FileInputStream(file);
    42. ZipInputStream zipInputStream = new ZipInputStream(inputStream);
    43. this.processEngine.getRepositoryService()
    44. .createDeployment()
    45. .name(processName)
    46. .addZipInputStream(zipInputStream)
    47. .deploy();
    48. }
    49.  
    50. /**
    51. * 通过字节流来进行部署流程
    52. * @param io
    53. * @param processName
    54. */
    55. public void deplyoProcessByInputSterm(InputStream io , String processName){
    56. ZipInputStream zipInputStream = new ZipInputStream(io);
    57. this.processEngine.getRepositoryService()
    58. .createDeployment()
    59. .name(processName)
    60. .addZipInputStream(zipInputStream)
    61. .deploy();
    62. }
    63.  
    64.  
    65. /**
    66. * 查询所有的部署流程
    67. * @return
    68. */
    69. public List<Deployment> getAllDeplyoment(){
    70. return this.processEngine.getRepositoryService()
    71. .createDeploymentQuery()
    72. .orderByDeploymenTime()
    73. .desc()
    74. .list();
    75. }
    76. /**
    77. * 查询所有的部署定义信息
    78. * @return
    79. */
    80. public List<ProcessDefinition> getAllProcessInstance(){
    81. return this.processEngine.getRepositoryService()
    82. .createProcessDefinitionQuery()
    83. .orderByProcessDefinitionVersion()
    84. .desc()
    85. .list();
    86. }
    87.  
    88. /**
    89. * 根据部署ID,来删除部署
    90. * @param deplyomenId
    91. */
    92. public void deleteDeplyomentByPID(String deplyomenId){
    93. this.processEngine.getRepositoryService()
    94. .deleteDeployment(deplyomenId , true);
    95. }
    96.  
    97. /**
    98. * 查询某个部署流程的流程图
    99. * @param pid
    100. * @return
    101. */
    102. public InputStream lookProcessPicture(String pid){
    103. return this.processEngine.getRepositoryService()
    104. .getProcessDiagram(pid);
    105. }
    106.  
    107. /**
    108. * 开启请假的流程实例
    109. * @param billId
    110. * @param userId
    111. */
    112. public void startProceesInstance(Long billId , String userId){
    113. Map<String , Object> variables = new HashMap<>();
    114. variables.put("userID" , userId);
    115. this.processEngine.getRuntimeService()
    116. .startProcessInstanceByKey("shenqingtest" , ""+billId , variables); //第一个参数,就是流程中自己定义的名字,这个一定要匹配,否则是找不到的。
    117. }
    118.  
    119. /**
    120. * 查询当前登陆人的所有任务
    121. * @param userId
    122. * @return
    123. */
    124. public List<Task> queryCurretUserTaskByAssignerr(String userId){
    125. return this.processEngine.getTaskService()
    126. .createTaskQuery()
    127. .taskAssignee(userId)
    128. .orderByTaskCreateTime()
    129. .desc()
    130. .list();
    131. }
    132.  
    133. /**
    134. * 根据TaskId,获取到当前的执行节点实例对象
    135. * @param taskId
    136. * @return
    137. */
    138. public ActivityImpl getActivityImplByTaskId(String taskId){
    139. //首先得到任务
    140. Task task = this.getTaskByTaskId(taskId);
    141. //其次,得到流程实例
    142. ProcessInstance processInstance = this.getProcessInstanceByTask(task);
    143. //再次,根据流程实例来获取到流程定义
    144. ProcessDefinitionEntity processDefinitionEntity = this.getProcessDefinitionEntityByTask(task);
    145. //再根据,流程定义,通过流程实例中来获取到activiti的ID,从而得到acitviImp
    146. ActivityImpl activity = processDefinitionEntity.findActivity(processInstance.getActivityId());
    147. return activity;
    148. }
    149.  
    150. /**
    151. * 根据taskId,判断对应的流程实例是否结束
    152. * 如果结束了,那么得到的流程实例就是返回一个null
    153. * 否则就是返回对应的流程实例对象
    154. * 当然也可以选择返回boolean类型的
    155. * @param taskId 任务ID
    156. * @return
    157. */
    158. public ProcessInstance isFinishProcessInstancs(String taskId){
    159. //1,先根据taskid,得到任务
    160. Task task = getTaskByTaskId(taskId);
    161. //2:完成当前任务
    162. finishCurrentTaskByTaskId(taskId);
    163. //3:得到当前任务对应得的流程实例对象
    164. ProcessInstance processInstance = getProcessInstanceByTask(task);
    165. return processInstance;
    166. }
    167.  
    168. /**
    169. * 获取当前执行节点的所有出口
    170. * @param activity
    171. * @return
    172. */
    173. public List<PvmTransition> getCurrentActivitiImplPvm(ActivityImpl activity){
    174. List<PvmTransition> outgoingTransitions = activity.getOutgoingTransitions();
    175. return outgoingTransitions;
    176. }
    177.  
    178. /**
    179. * 根据taskId获取到task
    180. * @param taskId
    181. * @return
    182. */
    183. public Task getTaskByTaskId(String taskId) {
    184. //得到当前的任务
    185. Task task = this.processEngine.getTaskService()
    186. .createTaskQuery()
    187. .taskId(taskId)
    188. .singleResult();
    189. return task;
    190. }
    191.  
    192. /**
    193. * 根据Task中的流程实例的ID,来获取对应的流程实例
    194. * @param task 流程中的任务
    195. * @return
    196. */
    197. public ProcessInstance getProcessInstanceByTask(Task task) {
    198. //得到当前任务的流程
    199. ProcessInstance processInstance = this.processEngine.getRuntimeService()
    200. .createProcessInstanceQuery()
    201. .processInstanceId(task.getProcessInstanceId())
    202. .singleResult();
    203. return processInstance;
    204. }
    205.  
    206. /**
    207. * 根据Task来获取对应的流程定义信息
    208. * @param task
    209. * @return
    210. */
    211. public ProcessDefinitionEntity getProcessDefinitionEntityByTask(Task task){
    212. ProcessDefinitionEntity processDefinitionEntity = (ProcessDefinitionEntity) this.processEngine.getRepositoryService()
    213. .getProcessDefinition(task.getProcessDefinitionId());
    214. return processDefinitionEntity;
    215. }
    216.  
    217. /**
    218. * 根据taskId获取到businesskey,这个值是管理activiti表和自己流程业务表的关键之处
    219. * @param taskId 任务的ID
    220. * @return
    221. */
    222. public String getBusinessKeyByTaskId(String taskId){
    223. Task task = this.getTaskByTaskId(taskId);
    224. ProcessInstance processInstance = this.getProcessInstanceByTask(task);
    225. //返回值
    226. return processInstance.getBusinessKey();
    227. }
    228.  
    229. /**
    230. * 根据taskId,完成任务
    231. * @param taskId
    232. */
    233. public void finishCurrentTaskByTaskId(String taskId){
    234. this.processEngine.getTaskService().complete(taskId);
    235. }
    236.  
    237. /**
    238. * 完成任务的同时,进行下一个节点的审批人员的信息的传递
    239. * @param taskId
    240. * @param object
    241. */
    242. public void finishCurrentTaskByTaskId(String taskId , Object object){
    243. Map<String , Object> map = new HashMap<>();
    244. map.put("assigeUser" , object);
    245. this.processEngine.getTaskService().complete(taskId , map);
    246. }
    247. }

     OK,这上面就是关于对于控制流的一些介绍了。对于这个,我们在很多的流程管理项目中都是有很好的借鉴意义的。当然,对于Actitivi这个框架,提供的只是部分的API接口,而且当我们刚开始接触的时候,对于里面内部存在的表的关系还会很模糊,但是,只要慢慢的熟悉了,这个就能够很好的理解了。另外的话,还说一个知识点。

    附加知识点:

    问题:Activiti里面本身自带有很多的数据表,它里面都是存在着关联关系,那么如何将其本身的表与我们的实际业务中的表进行关联呢?

    解惑:其实,这个对于Activiti早已经想到这个问题,就是通过act_ru_exectution这个表中的business_key这个字段来进行关联。

    实例分析:比如,针对上面的请假流程,那么,我们肯定在自己的业务中,就需要一张请假的信息表,比如,里面就包含,请假原因,请假人,请假时间等等基本请假信息。然后,我们其他的业务,也会根据这张表的内容,进行不断的扩充,比如,还需要记录对每条请假信息,每个审批节点中每个人的具体描述信息,那么这样就出现了一张“请假审批详细表”,很明显,这两张表就是通过“请假表中的主键ID”来进行关联的,那么就作为“请假详情表”中的外键。。。那么,同理,我们也是一样的,我们就通过对于act_ru_exectution这个数据表的business_key字段来关联着我们的业务主键即可。所以,这样就把我们自身的业务和Activiti进行了关联。如下图:

    附加知识点2:Activiti工作流的自带数据表的含义

    (1)资源库流程规则表
    1)act_re_deployment 部署信息表
    2)act_re_model  流程设计模型部署表
    3)act_re_procdef  流程定义数据表
    (2):运行时数据库表
    1)act_ru_execution 运行时流程执行实例表
    2)act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
    3)act_ru_task 运行时任务节点表
    4)act_ru_variable 运行时流程变量数据表
    (3):历史数据库表
    1)act_hi_actinst 历史节点表
    2)act_hi_attachment 历史附件表
    3)act_hi_comment 历史意见表
    4)act_hi_identitylink 历史流程人员表
    5)act_hi_detail 历史详情表,提供历史变量的查询
    6)act_hi_procinst 历史流程实例表
    7)act_hi_taskinst 历史任务实例表
    8)act_hi_varinst 历史变量表
    (4):组织机构表
    1)act_id_group 用户组信息表
    2)act_id_info 用户扩展信息表
    3)act_id_membership 用户与用户组对应信息表
    4)act_id_user 用户信息表
    这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足 
    (5):通用数据表
    1)act_ge_bytearray 二进制数据表
    2)act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录,

    附加知识点3:完整的一个Activiti工作流的项目代码。

    环境:IDEA+ SpringMvc+Spring+Hibernate  +Mysql

    获取方式:留言即可。我会随时浏览信息的。。。。

    github地址:git@github.com:qq496616246/ActivitiCode.git

    或者https://github.com/qq496616246/ActivitiCode.git

  • 相关阅读:
    解决duplicate symbols for architecture x86_64错误
    IOS-UITextField键盘不隐藏问题
    IOS-细节错误
    IOS开发-图片上传
    IOS-指定返回Modal的控制器presentViewController
    支付-支付宝集成
    真机测试-Please enter a different string错误解决
    Xcode插件安装 错选了Skip Bundle解决办法
    SQLServer 命令批量删除数据库中指定表(游标循环删除)
    SQL中使用update inner join和delete inner join
  • 原文地址:https://www.cnblogs.com/libin6505/p/10102638.html
Copyright © 2011-2022 走看看