`

Activiti工作流实践

阅读更多

配置

首先,配置processEngineConfiguration:

 

    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="jobExecutorActivate" value="false"/>
        <!--<property name="history" value="full"/>-->
        <property name="processDefinitionCacheLimit" value="10"/>

        <!-- UUID作为主键生成策略
        <property name="idGenerator" ref="uuidGenerator" />
        -->

        <!-- 生成流程图的字体 -->
        <property name="activityFontName" value="${diagram.activityFontName}"/>
        <property name="labelFontName" value="${diagram.labelFontName}"/>

        <!-- 缓存支持
        <property name="processDefinitionCache">
            <bean class="me.kafeitu.demo.activiti.util.cache.DistributedCache" />
        </property>-->

        <!-- 自动部署 -->
        <property name="deploymentResources">
            <list>
                <value>classpath*:/deployments/*</value>
            </list>
        </property>

        <!-- 自定义表单字段类型 -->
        <property name="customFormTypes">
            <list>
                <bean class="me.kafeitu.demo.activiti.activiti.form.UsersFormType"/>
            </list>
        </property>

        <!-- JPA -->
        <property name="jpaEntityManagerFactory" ref="entityManagerFactory" />
        <property name="jpaHandleTransaction" value="false" />
        <property name="jpaCloseEntityManager" value="false" />

        <!-- 全局事件 -->
        <property name="typedEventListeners">
            <map>
                <entry key="VARIABLE_CREATED" >
                    <list>
                        <ref bean="variableCreateListener"/>
                    </list>
                </entry>
            </map>
        </property>
    </bean>


然后,根据这个配置来生成流程引擎:

 

 

    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

最后,通过流程引擎获取关于仓库、运行、表单、身份认证、任务、历史等相关操作服务:

 

 

    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
    <bean id="formService" factory-bean="processEngine" factory-method="getFormService"/>
    <bean id="identityService" factory-bean="processEngine" factory-method="getIdentityService"/>
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
    <bean id="managementService" factory-bean="processEngine" factory-method="getManagementService"/>

 

 

流程定义

添加

最多的部署方式为上传流程定义文件来部署,RepositoryService中提供了多种部署方式,其中包括从输入流、classpath资源文件等方式:

 

         String fileName = file.getOriginalFilename();

        try {
            InputStream fileInputStream = file.getInputStream();
            Deployment deployment = null;

            String extension = FilenameUtils.getExtension(fileName);
            if (extension.equals("zip") || extension.equals("bar")) {
                ZipInputStream zip = new ZipInputStream(fileInputStream);
                deployment = repositoryService.createDeployment().addZipInputStream(zip).deploy();
            } else {
                deployment = repositoryService.createDeployment().addInputStream(fileName, fileInputStream).deploy();
            }

 

 

查询

Activityti提供链式api来进行查询操作,支持分页查询。一个对一个流程定义部署多次,会产生一个流程定义的多个版本而不是多个流程定义。可以看成流程定义和部署之间存在一对多的关联关系。

 

        List<Object[]> objects = new ArrayList<Object[]>();
        Page<Object[]> page = new Page<Object[]>(PageUtil.PAGE_SIZE);
        int[] pageParams = PageUtil.init(page, request);
        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().orderByDeploymentId().desc();
        List<ProcessDefinition> processDefinitionList = processDefinitionQuery.listPage(pageParams[0], pageParams[1]);
        for (ProcessDefinition processDefinition : processDefinitionList) {
            String deploymentId = processDefinition.getDeploymentId();
            //Deployment deployment = repositoryService.createDeploymentQuery().deploymentId(deploymentId).singleResult();
            //objects.add(new Object[]{processDefinition, deployment});
            for(Deployment dep : repositoryService.createDeploymentQuery().deploymentId(deploymentId).list()){
            	objects.add(new Object[]{processDefinition, dep});
            	System.out.println(deploymentId);
            }
        }

 


删除

 

repositoryService.deleteDeployment(deploymentId, true);

第二个参数为true时表示级联删除流程实例、历史记录和任务。也可以通过deleteDeploymentCascade(deploymentId)来级联删除。

 

 

启动流程

可以使用RuntimeService来启动一个流程实例,启动流程实例的方式有很多种,主要涉及到

processDefinitionId:流行定义id

processDefinitionKey:流程定义关键字

businessKey:业务关键字

variables(Map):流程变量

tenantId:

message:

你可以根据不同的情况尝试组合使用上面的信息来启动一个流程实例。

 

    /**
     * 启动流程
     * @param entity
     */
    public ProcessInstance startWorkflow(Leave entity, Map<String, Object> variables) {
        leaveManager.saveLeave(entity);
        String businessKey = entity.getId().toString();
        ProcessInstance processInstance = null;
        try {
            identityService.setAuthenticatedUserId(entity.getUserId());
            processInstance = runtimeService.startProcessInstanceByKey("leave", businessKey, variables);
            String processInstanceId = processInstance.getId();
            entity.setProcessInstanceId(processInstanceId);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }
        return processInstance;
    }

事实上,一个流程启动之后,流程当中并不关心实际的业务内容,而是人为地将这些业务变量放到了流程实例的”存储空间“当中,比如这里的businessKey和variables。真正当流程实例跑起来的时候,它也不关心具体的业务内容,这种关心被挪到了流程定义当中,而流程定义是用户来做的,从而将流程的运行和具体业务解耦出来。

 

待我处理

TaskService提供了这样的查询API来查询与我相关的任务。TaskQuery中有多种方式来确定任务的所有者:

和其他丰富的限制条件,这些任务查询出来之后,还需要与具体的业务对象关联,这样,在更上一层的处理上面对的只是业务对象,而不是工作流中的Task。

 

    public List<Leave> findTodoTasks(String userId, Page<Leave> page, int[] pageParams) {
        List<Leave> results = new ArrayList<Leave>();
        List<Task> tasks = new ArrayList<Task>();

        // 根据当前人的ID查询
        TaskQuery todoQuery = taskService.createTaskQuery().processDefinitionKey("leave").taskAssignee(userId).active().orderByTaskId().desc()
                .orderByTaskCreateTime().desc();
        List<Task> todoList = todoQuery.listPage(pageParams[0], pageParams[1]);

        // 根据当前人未签收的任务
        TaskQuery claimQuery = taskService.createTaskQuery().processDefinitionKey("leave").taskCandidateUser(userId).active().orderByTaskId().desc()
                .orderByTaskCreateTime().desc();
        List<Task> unsignedTasks = claimQuery.listPage(pageParams[0], pageParams[1]);

        // 合并
        tasks.addAll(todoList);
        tasks.addAll(unsignedTasks);

        // 根据流程的业务ID查询实体并关联
        for (Task task : tasks) {
            String processInstanceId = task.getProcessInstanceId();
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).active().singleResult();
            String businessKey = processInstance.getBusinessKey();
            if (businessKey == null) {
                continue;
            }
            Leave leave = leaveManager.getLeave(new Long(businessKey));
            leave.setTask(task);
            leave.setProcessInstance(processInstance);
            leave.setProcessDefinition(getProcessDefinition(processInstance.getProcessDefinitionId()));
            results.add(leave);
        }
        page.setTotalCount(todoQuery.count() + claimQuery.count());
        page.setResult(results);
        return results;
    }



 

任务签收

 

  void claim(String taskId, String userId);


任务处理

 

 

taskService.complete(taskId, variables);

 

动态表单

在之前的请假流程当中,可能因为我们对请假有比较特殊的,所以请假的核心对象Leave是由我们自己管理的,我们自己搞了个库来存放请假过程中的相关表单数据。但是更为通用和灵活的工作流,表单的内容应该是动态定义出来的,而不是事先由程序写好的。只有这样才能体现工作流引擎的最终目的。有了动态表单,每个节点上,有哪些字段、字段类型是什么、默认值、是否可见、是否可修改、是否必填等信息就可以动态定义了。

流程定义XML:

 

<process id="leave-dynamic-from" name="请假流程-动态表单">
<documentation>请假流程演示-动态表单</documentation>
<startEvent id="startevent1" name="Start" activiti:initiator="applyUserId">
<extensionElements>
<activiti:formProperty id="startDate" name="请假开始日期" type="date" datePattern="yyyy-MM-dd" required="true" readable="true" writable="true"/>
<activiti:formProperty id="endDate" name="请假结束日期" type="date" datePattern="yyyy-MM-dd" required="true" readable="true" writable="true"/>
<activiti:formProperty id="reason" name="请假原因" type="string" required="true" readable="true" writable="true"/>
</extensionElements>
</startEvent>
<userTask id="deptLeaderAudit" name="部门领导审批" activiti:candidateGroups="deptLeader">
<extensionElements>
<activiti:formProperty id="startDate" name="请假开始日期" type="date" value="${startDate}" datePattern="yyyy-MM-dd" readable="true" writable="false"/>
<activiti:formProperty id="endDate" name="请假结束日期" type="date" value="${endDAte}" datePattern="yyyy-MM-dd" readable="true" writable="false"/>
<activiti:formProperty id="reason" name="请假原因" type="string" value="${reason}" readable="true" writable="false"/>
<activiti:formProperty id="deptLeaderPass" name="审批意见" type="enum" required="true" writable="true">
<activiti:value id="true" name="同意"/>
<activiti:value id="false" name="不同意"/>
</activiti:formProperty>
</extensionElements>
</userTask>
[......]

疑问:这些动态表单字段的定义信息保存在哪儿的?

 

表单渲染

 

FormService中提供了按照processDefinitionId或者taskId来获取对应表单数据的方法:

获取到表单数据之后,还能对其中每一项,根据其不同的数据类型进行处理,比如下面的代码中,对枚举类型的数据进行了整理,统一存放到了一个Map中,以供页面使用:

 

        Map<String, Object> result = new HashMap<String, Object>();
        StartFormDataImpl startFormData = (StartFormDataImpl) formService.getStartFormData(processDefinitionId);
        startFormData.setProcessDefinition(null);
        List<FormProperty> formProperties = startFormData.getFormProperties();
        for (FormProperty formProperty : formProperties) {
            Map<String, String> values = (Map<String, String>) formProperty.getType().getInformation("values");
            if (values != null) {
                result.put("enum_" + formProperty.getId(), values);
            }
        }
        result.put("form", startFormData);


前台页面对于这样的数据及其类型(单行文本、多行文本域、下拉选择、日期、数字等等)动态生成一个表单。

 

 

表单数据搜集与存储

这个也没没有社么特别的了,根据上一节中渲染出来的表单,填写数据,然后提交数据到后台即可了。关键是表单数据如何与流程引擎关联起来?很简单,因为我们之间渲染动态表单的时候其中所有字段的name都是按照表单定义来的,所以只要通过request.getParameterMap(),将这个参数键值对送给FormService就可以了,根本不用做其他多余的处理,代码如下:

 

        Map<String, String> formProperties = new HashMap<String, String>();
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Entry<String, String[]>> entrySet = parameterMap.entrySet();
        for (Entry<String, String[]> entry : entrySet) {
            String key = entry.getKey();
            if (StringUtils.defaultString(key).startsWith("fp_")) {
                formProperties.put(key.split("_")[1], entry.getValue()[0]);
            }
        }
        User user = UserUtil.getUserFromSession(request.getSession());
        ProcessInstance processInstance = null;
        try {
            identityService.setAuthenticatedUserId(user.getId());
            processInstance = formService.submitStartFormData(processDefinitionId, formProperties);
        } finally {
            identityService.setAuthenticatedUserId(null);
        }

上面的代码对于parameterMap还是稍微做了一点处理,这是因为前台页面中对于动态表单字段的的name都统一增加了fp_,这里要过滤只带有fp_的name值。从而起到一个过滤杂质,避免将其他没用的数据传递给FormService。

 

这些数据最终被存放到哪里了呢?答案是数据库表ACT_RU_VARIABLE,没错,就是流程标量表中,和相对于动态表单的静态表单而言,动态表单唯一不同的是,动态表单把业务相关的数据也当成流程变量存放起来了,而静态表单是使用自己的表来存放业务数据。

分享到:
评论

相关推荐

    Activiti工作流使用手册操作文档

    总结来说,Activiti工作流是一个功能强大且灵活的流程管理工具,通过深入学习和实践本操作手册,Java开发者能够熟练掌握其使用,从而提升业务流程的自动化水平和效率。工作流使用.doc文档将提供更详细的步骤和示例,...

    activiti工作流项目

    【标题】"activiti工作流项目"是一个基于Java技术栈...通过这个项目,开发者不仅可以深入理解Activiti工作流引擎的使用,还能巩固Spring全家桶的综合运用能力,以及提升在Web环境下实现业务流程管理系统的实践经验。

    activiti工作流案例

    这个压缩包文件包含的“activiti工作流案例”是帮助初学者快速理解和实践Activiti工作流的一个实用资源。 在了解这个案例之前,我们先来认识一下Activiti的基本概念。Activiti由Alfresco Software公司开发,并在...

    Activiti工作流示例Activiti Demo(带完整源码)非常实用

    这个"Activiti工作流示例Activiti Demo"提供了完整的源代码,帮助开发者深入理解并实际操作Activiti,从而更好地在自己的项目中应用。 在描述中提到的"Canvas动画"是指Activiti提供的可视化建模工具,它允许开发者...

    activiti工作流测试

    Activiti工作流测试是针对Activiti这一开源工作流引擎进行的一种实践操作,旨在帮助开发者理解和掌握如何在实际项目中运用Activiti。Activiti是一个轻量级、高效且灵活的业务流程管理(BPM)系统,它能够处理业务...

    Activiti工作流整合Web流程设计器整合

    Activiti工作流引擎是一款强大的开源工作流解决方案,它基于模型驱动的架构,旨在为企业提供灵活、可扩展的业务流程自动化能力。在这个“Activiti工作流整合Web流程设计器整合”主题中,我们将深入探讨如何将...

    Activiti 工作流取回的示例

    总结来说,这个"Activiti 工作流取回的示例"涵盖了Activiti工作流引擎的关键操作,尤其是关于任务的取回和撤销。通过对这些示例的分析和实践,开发者能够增强对Activiti的理解,提升在企业级应用中实现高效工作流程...

    Activiti6.0工作流引擎springboot项目代码

    通过以上分析,我们可以看出这个项目旨在教授如何利用Activiti 6.0工作流引擎和Spring Boot进行业务流程自动化开发,同时可能涵盖了SpringCloud的使用,为开发者提供了丰富的实践素材。对于希望在企业级应用中引入...

    eclipse的activiti工作流插件

    **Eclipse Activiti 工作流插件** Activiti 是一个开源的工作流和业务自动化引擎,它基于模型驱动的设计理念,提供了一套强大的工具来帮助开发者实现复杂的业务流程。Eclipse 的 Activiti 插件是这个引擎的一个集成...

    activiti工作流流程跟踪图(图片(两种方式))

    Activiti是一款开源的工作流引擎,它为业务流程自动化提供了强大的支持。在开发和运维过程中,流程跟踪图是非常重要的工具,可以帮助我们理解流程的执行状态,定位问题,优化流程设计。本实例聚焦于如何生成和查看...

    Activiti工作流.doc

    activiti工作流笔记文档,参考资料和实践文档。工作流引擎

    activiti工作流demo

    Activiti工作流是一个开源的工作流程管理系统,用于设计、部署和执行业务流程。它基于Java,兼容BPMN 2.0标准,使得企业能够轻松构建动态的、灵活的业务流程。这个"activiti工作流demo"是针对初学者或者开发者的一个...

    Spring结合Activiti工作流

    Spring结合Activiti工作流是企业级应用开发中的一个重要实践,它允许开发者在应用程序中实现复杂的业务流程自动化。本文将深入探讨这一主题,介绍如何利用Spring框架集成Activiti工作流引擎,以及如何通过源码示例...

    Activiti工作流实战.rar

    在《Activiti工作流实战》这本书中,作者将通过具体的案例和实践,引导读者逐步了解和掌握以下几个方面: 1. **Activiti基本概念**:涵盖流程定义、参与者、任务、事件等基本概念,以及它们在流程图中的表示方式。 ...

    ACTIVITI工作流绘图

    ACTIVITI工作流绘图是一个关于流程自动化和工作流管理系统的话题,主要涉及的是Activiti这一开源工作流引擎。在本文中,我们将深入探讨Activiti的核心功能、如何使用它进行工作流设计,以及如何通过图形化工具进行...

    Activiti 学习笔记14:工作流定义的角色组

    在本篇Activiti学习笔记中,我们将深入探讨工作流定义中...理解并熟练运用角色组,是提升Activiti工作流设计和管理能力的关键。通过不断的学习和实践,我们可以更好地利用Activiti构建高效、符合业务需求的工作流系统。

    Activiti工作流demo

    本"Activiti工作流demo"旨在帮助开发者快速理解并应用Activiti,通过实践来学习其核心概念和功能。 1. **Activiti简介** Activiti是一款轻量级的业务流程管理(BPM)系统,它不仅支持复杂的业务流程,还具有高度...

    疯狂activiti工作流讲义

    13. **案例研究**:"疯狂activiti工作流讲义"很可能包含实际案例,让读者通过实践来理解和应用 Activiti,提升学习效果。 这些知识点覆盖了 Activiti 工作流框架的基础到高级应用,是理解并使用 Activiti 进行业务...

    activiti工作流学习总结

    【标题】:“activiti工作流学习总结” 在深入探讨activiti工作流系统之前,我们先理解什么是工作流。工作流是一系列相互关联的任务,这些任务按照一定的规则和顺序执行,以实现某个业务过程。Activiti是一款开源的...

    activiti工作流详细讲解和实例

    Activiti工作流是一款开源的工作流程管理系统,主要用于设计、部署和执行业务流程。它基于Java平台,采用模型驱动的架构(MDA),支持BPMN 2.0标准,提供了丰富的API和工具,使得开发者能够轻松地创建和管理复杂的...

Global site tag (gtag.js) - Google Analytics