Activiti工作流入门

Activiti概述

工作流概念

工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”。是对工作流程及其各操作步骤之间业务规则的抽象、概括描述。
通俗的说,流程(过程)就是多个人在一起合作完成某件事情的步骤,把步骤编程计算机能理解的形式,就是工作流。
工作流是研究一个群体如何在计算机的帮助下实现协同工作的,其主要解决的问题是:为了实现某个业务目标,利用计算机在多个参与者(Actor)之间按某种预定规则自动传递文档、信息或者任务(Task)。

【不使用工作流技术:】
从头开始开发这个订购流程的业务逻辑,我们需要:
- 每个活动点都需要开发交互页面和后台处理程序
- 每个活动的流转都需要硬性判断下一步活动节点及其操作人
- 每次操作都需要维护业务数据和流程的相关数据

使用好处:
- 使用专门的流程数据系统,维护所有涉及流程流转的数据。
- 提供“流程设计”工具,帮助用户定义订货流程的模型,而且一般都提供了可视化的界面。
- 所有的流程都依靠流程引擎来处理,避免了需求更改与硬编码之间矛盾的产生。
- 工作流引擎还提供了众多的API,可以很方便的将工作流的管理和业务操作完美结合。

工作流技术的优势

  • 降低开发风险
    通过使用诸如活动、流转、状态、行为这样的术语,使得业务分析师和开发人员使用同一种语言交谈成为可能。优秀的流程设计建模工具,甚至能使开发人员不必将用户需求转化成详细设计文档。
  • 流程实现的集中统一
    应对业务流程经常变化的情况,使用工作流技术的最大好处是使业务流程的实现代码,不再散落在各式各样的业务系统中。
  • 加速开发
    开发者不用再关注流程的参与者、活动节点的衔接、流转控制……因为这些工作很多被工作流框架接管了。因而开发者开发起来更快、代码出错更少、系统更加容易维护。
  • 提升对迭代开发的支持
    如果系统中业务流程部分被硬编码,就不容易更改,需求分析师就会花费很大的精力在开发前的业务分析中,并且希望一次成功。但可悲的是,在任何软件项目开发中,这都很少能实现。工作流管理系统使得业务流程很容易部署和重新编排,业务流程相关的应用开发可以以一种“迭代/渐进”的方式推进,也就是说工作流技术在某种程度上支持“需求分析不必一次完全成功”。

工作流的技术特点

工作流只管理流程,是不能完成业务操作的。换句话说,工作流是相对独立的、通用的,与业务管理无直接关系。
比如费用报销流程,工作流管理的是报销的流程(谁申请,谁审批),费用报销的业务(使用费用的原因,使用费用的时间,,)
工作流虽然与业务无直接关系,但是,在开发的时候,需要考虑和业务整合。

常见的工作流框架

Activiti、JBPM、OSWorkflow、ActiveBPEL、YAWL等。

Activiti的起源

Activiti是一套业务流程管理(BPM)框架,它覆盖了业务流管理、工作流、服务协助等领域,它是一个开源的(Apache许可2.0)、灵活的、易扩展的可执行流程语言框架。
Activiti是Alfresco软件在2010年5月17日宣布启动的一个开源项目,其创始人和首席架构师由业务流程管理BPM的专家 Tom Baeyens担任。Tom Baeyens是JBoss jBPM的项目架构师。
提示:Jbpm4版本之后,该作者才做的Activiti,所以,Activiti很像jbpm4,理念又有点像hibernate。但是,jbpm5与4版本的差距比较大。

它是一项新的基于Apache许可的开源BPM平台,从基础开始构建,提供支持新的BPMN 2.0标准。(直观的认识就是XML)
Activiti提供了流程设计器,开发人员可以直接通过流程设计器直接画出业务流程图。
Activiti的持久层使用的Mybatis。(api将dao封装了,无需会mybatis)

Activiti环境搭建

One minute version(官方Demo演示)

第一步:用管理员进去定制流程。
第二步:部署和启动流程。
第三步:使用流程。

使用工作流系统需要三步:
1.画流程图(流程文档xml定义)—管理员
2.部署到工作流的系统中—管理员
3.启动流程,开始执行任务,直到任务结束。–用户

新建Maven项目

Maven坐标(工作流引擎activiti-engine,日志实现slf4j-log4j12,数据库驱动oracle,测试junit):

    <properties>
        <activiti.version>5.19.0.2</activiti.version>
        <slf4j.version>1.7.5</slf4j.version>
        <oracle.version>10.2.0.4.0</oracle.version>
        <c3p0.version>0.9.1.2</c3p0.version>
        <junit.version>4.11</junit.version>
    </properties>
  <dependencies>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>
    <dependency>
        <groupId>com.oracle</groupId>
        <artifactId>ojdbc14</artifactId>
        <version>${oracle.version}</version>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>${junit.version}</version>
        <scope>test</scope>
    </dependency>
  </dependencies>

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

初始化Activiti数据库

新建一个测试类:

        /**
         * Activiti测试类
         */
        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(locations="classpath:applicationContext.xml")
        public class ActivitiTest {

            //创建表:通过创建工厂(流程引擎:用来生成其他的服务api来具体操作)
            @Test
            public void testCreateTable(){
                //1.得到引擎的配置对象:单服务器使用
                ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createStandaloneProcessEngineConfiguration();

                //2.在引擎配置对象上设置相应的数据库连接参数
                processEngineConfiguration.setJdbcDriver("oracle.jdbc.driver.OracleDriver");
                processEngineConfiguration.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
                processEngineConfiguration.setJdbcUsername("bos");
                processEngineConfiguration.setJdbcPassword("bos");

                //设置自动建表
                //三种参数值:
                //false:只是检查表结构,但不创建也不更新。适合已经有表的时候用
                //create-drop:启动的时候检查和创建表,引擎关闭的是的删除
                //true:检查表结构,如果表存在,则创建,如果表结构不一致,则更新。---常用
                processEngineConfiguration.setDatabaseSchemaUpdate(processEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);

                //获取工作流引擎对象(单例)
                ProcessEngine processEngine = processEngineConfiguration.buildProcessEngine();
                System.out.println("====="+processEngine);


            }
        }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

Activiti的核心

  • ACT_RE_*: ‘RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
  • ACT_RU_*: ‘RU’表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
  • ACT_ID_*: ‘ID’表示identity。 这些表包含身份信息,比如用户,组等等。
  • ACT_HI_*: ‘HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
  • ACT_GE_*: ‘GE’表示general。通用数据, 用于不同场景下,如存放资源文件。
  • ACT_EVT_LOG:事件日志

ProcessEngine:流程引擎接口,是最核心的API类,其他的API类都由他而来。它是其他API产生的基础!ProcessEngine对象,这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。

  • RepositoryService 流程定义管理 操作 ACT_RE_* 数据表
  • RuntimeService 流程实例管理 操作 ACT_RU_* 数据表
  • TaskService 任务管理 操作 ACT_RU_TASK 数据表
  • IdentitiService 认证管理 操作 ACT_ID_* 数据表
  • HistoryService 历史记录管理 操作 ACT_HI_* 数据表
  • ManagementService 定时任务管理,创建job,ACT_RU_JOB 数据表
  • FormService 表单管理,生成动态任务表单页面,某个字段存的数据

maven坐标

    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-engine</artifactId>
        <version>${activiti.version}</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>${slf4j.version}</version>
    </dependency>

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

ApplicationContext.xml:

    <!-- 流程引擎配置对象 -->
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <!-- 注入数据源 -->
        <property name="dataSource" ref="dataSource"/>
        <!-- 自动建表 -->
        <property name="databaseSchemaUpdate" value="true"/>
    </bean>
    <!-- 流程引擎对象 -->
    <bean id="processEngine" factory-bean="processEngineConfiguration" factory-method="buildProcessEngine"/>

   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

流程文档定义—画流程图

流程id(非常重要-将来程序里面叫key—流程定义的唯一标识),必须英文.
添加办理人:

Bpmn文件解读:

流程定义管理

核心API

关于工作流的api,有个规律:要获取某对象,都是createXxx;
如果是CreateXxx,获取的就是xxx对象,该对象主要用来增删改对应的表。
如果是CreateXxxQuery,获取的是xxxQuery对象,该对象主要用来查询的。

加载流程文档的时候,可以单独加载文档bpmn,工作流会自动生成一张图片存在数据库。
但也可以两个都加载,那么工作流就不会自动生成图片,而使用你上传的图片。

        @RunWith(SpringJUnit4ClassRunner.class)
        @ContextConfiguration(
                locations="classpath:applicationContext.xml")
        public class ActivitiTest {
            //注入仓库Service
            @Autowired
            private RepositoryService repositoryService;

            //发布流程:只发布流程图,自动生成图片
            @Test
            public void deployment1(){
                Deployment deployment = repositoryService.createDeployment()//获取发布对象
                .addClasspathResource("diagrams/Leave.bpmn")//添加流程文件
                .name("请假流程1")//发布的名字
                .deploy();//发布
                System.out.println("发布的编号:"+deployment.getId());
                System.out.println("发布的名称:"+deployment.getName());
                System.out.println("发布的时间:"+deployment.getDeploymentTime());
            }
            //发布流程:发布流程图和图片--第一种方法
            @Test
            public void deployment21(){
                Deployment deployment = repositoryService.createDeployment()//获取发布对象
                        .addClasspathResource("diagrams/Leave.bpmn")//添加流程文件
                        .addClasspathResource("diagrams/Leave.png")//添加流程图片
                        .name("请假流程21")//发布的名字
                        .deploy();//发布
                System.out.println("发布的编号:"+deployment.getId());
                System.out.println("发布的名称:"+deployment.getName());
                System.out.println("发布的时间:"+deployment.getDeploymentTime());
            }
            //发布流程:发布流程图和图片--第二种方法
            @Test
            public void deployment22() throws FileNotFoundException{
                Deployment deployment = repositoryService.createDeployment()//获取发布对象
                        .addZipInputStream(new ZipInputStream(this.getClass().getClassLoader().getResourceAsStream("diagrams/Leave.zip")))
                        .name("请假流程22")//发布的名字
                        .deploy();//发布
                System.out.println("发布的编号:"+deployment.getId());
                System.out.println("发布的名称:"+deployment.getName());
                System.out.println("发布的时间:"+deployment.getDeploymentTime());
            }
        }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

ApplicationContext.xml:

    <!-- 流程控制的相关service -->
    <!-- 仓库对象 -->
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"></bean>

   
   
  • 1
  • 2
  • 3
  • 4

工作流服务端自动生成的图片的乱码问题解决方案:
解决方案1:
在流程引擎配置对象上面设置字体属性:

 <!-- 发布流程生成图片是正常显示中文 -->
        <property name="activityFontName" value="宋体"/>
        <property name="labelFontName" value="宋体"/>

   
   
  • 1
  • 2
  • 3
  • 4

解决方案2:
流程图的图片在设计器中生成好,上传到服务器,不让服务器自动生成图片。

部署信息查询
        //查询部署表对象数据
        @Test
        public void queryDeployment(){
            List<Deployment> list = repositoryService.createDeploymentQuery()
            //条件查询
                    .deploymentName("请假的流程部署")
                    .deploymentId("1")//根据id
                    .singleResult()//查询出一条结果
                    .orderByDeploymenTime()//排序
                    .listPage(firstResult, maxResults)//分页
                    .count()//统计
                    .list();
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
流程定义信息查询
        @Test
        //查询流程定义的表的数据
        public void queryProceeDefinition(){
            List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
    //      .processDefinitionKey(processDefinitionKey)//根据key来查询
            .list();
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
流程图查看
    //查询流程图
    @Test
    public void findProcessDefinitionDiagram() throws IOException{
        InputStream in = repositoryService.getProcessDiagram("LeaveProcess:1:4");
        OutputStream out = new FileOutputStream("z:/Leave.png");
        FileUtil.copyStream(in, out);
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
流程定义的删除-流程销毁
        //删除流程定义(通过部署id)
        @Test
        public void deleteProcessDefinition(){
            repositoryService.deleteDeployment("1", true);
        }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

级联和不级联。
场景:如果流程已经开启了,如果不使用级联,则会抛出异常!(原因:定义表有外键关联它),此时只能用级联。

流程实例管理

流程实例的启动

  • 根据流程定义的id来启动:可以启动指定的流程定义。
  • 根据流程定义的key来启动:自动选择版本号最高(最新)的流程定义来启动
  • 根据消息的名字来启动
    //启动流程实例
    @Test
    public void startProcessInstance(){
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("LeaveProcess");
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

applicationContext.xml配置:

<!-- 运行时Service -->
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>

   
   
  • 1
  • 2
  • 3

流程实例的查询

    //查询流程实例
    @Test
    public void queryProcessInstance(){
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery()
        .list();
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

流程当前节点的坐标

    //查询活动节点坐标
    @Test
    public void queryActiveNodeZuobiao(){

        List<String> activeActivityIds = runtimeService.getActiveActivityIds("10001");
        for (String activeActivityId : activeActivityIds) {
            GraphicInfo graphicInfo1 = repositoryService.getBpmnModel("LeaveProcess:4:7504")
            .getGraphicInfo(activeActivityId);//某活动节点的坐标
        }
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

流程实例的删除(强行终止)

        //流程实例的删除
        @Test
        public void deleteProcessInstance(){
            runtimeService.deleteProcessInstance("LeaveProcess:4:7504", "不想请假了");
        }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 删除流程定义:可以级联删除流程定义以及流程实例相关表数据。–管理员
  • 删除流程实例:只删除流程实例相关(运行时)表的数据,对流程定义没有影响。-流程启动者

任务管理

个人任务查询(待办任务查询)

    //个人任务查询
    @Test
    public void queryPersionTask(){
        List<Task> list = taskService.createTaskQuery()
                .taskAssignee("张三")
                .list();
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

个人任务办理

    //个人任务办理
    @Test
    public void completePersonTask(){
        taskService.complete("12504");
    }
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

任务办理完成

当end节点之前的节点办理完成后,会自动完成end节点。当前流程实例都结束了。

        <link rel="stylesheet" href="https://csdnimg.cn/release/phoenix/template/css/markdown_views-ea0013b516.css">
            </div>

转载自:https://blog.csdn.net/shuaicihai/article/details/60878001

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值