Android开发之activiti节点跳转

activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业务非常的复杂,比如一个简单的采购流程:流程如下:

供应商上新商品的时候,提交商务审核,商务审核通过提交运营审核,审核失败退回供应商。

运营审核成功提交合同签订。交运营审核审核失败退回商务审核或者直接退回供应商。

合同签订审核通过结束,合同签订审核不通过返回运营审核或者退回商务审核,或者退回供应商。

上面的流程就出现了一个问题,什么问题呢?

我们来观察一下退回线的问题。

1.商务审核退回供应商上新。

2.运营审核可能退回商务审核,运营审核可能退回供应商上新。

3.合同签订可能退回运营审核,合同签订可能退回商务审核,合同签订可能退回供应商上新。

4....

假如以后我们的流程在添加新的部门审核,是不是我们的退回线更加的多了。其实就是n!的问题,难道我们没添加一个节点,就要画很多的退回线吗?这显然是一个糟糕的设计。oh my god.

存在的问题就是,我们要是想让我们的流程更加的通用,我们可能在设计的时候,需要添加很多的退回线控制,防止业务变化,流程跟起来变化,这就是应对了变化,同时在增加了冗余设计。

那有没有一种更好的方式,能解决上面的问题呢?很显然这就是我们本章要解决的问题。

1.1.1. activiti节点跳转实现

实现之前,我们考虑几个问题。

1.当前流程在哪一个节点。

2.流程需要跳转的目标节点。

3.跳转到目标节点之后,需要添加变量吗?有可能需要把,总不能无缘无故的跳转到了目标节点。痕迹肯定要记录。

4.跳转到目标节点,那当前节点配置的任务监听需要触发吗?(可参考 activiti监听器使用).当前节点跳转到目标节点的时候,如果当前节点配置了任务监听业务,调转到目标节点之前,这些当前的任务节点的是否触发任务监听业务必须能支持灵活配置。

上面的思考点,也是我们接下来需要重点讲解的内容。那下面就开始我们的设计吧。

1.1.1.1. 流程图

下面我们先定义一个流程如下图所示:

1.1.1.2. xml

下面我们先定义一个xml定义如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="daling">
 <process id="daling" name="name_daling" isExecutable="true" activiti:candidateStarterUsers="a,b,c,d">
  <userTask id="usertask2" name="usertask2" activiti:assignee="c"></userTask>
  <userTask id="usertask3" name="usertask3"></userTask>
  <sequenceFlow id="flow4" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
  <userTask id="usertask4" name="usertask4"></userTask>
  <sequenceFlow id="flow5" sourceRef="usertask3" targetRef="usertask4"></sequenceFlow>
  <userTask id="usertask5" name="usertask5"></userTask>
  <sequenceFlow id="flow6" sourceRef="usertask4" targetRef="usertask5"></sequenceFlow>
  <endEvent id="endevent1" name="End"></endEvent>
  <sequenceFlow id="flow7" sourceRef="usertask5" targetRef="endevent1"></sequenceFlow>
  <startEvent id="startevent1" name="Start"></startEvent>
  <sequenceFlow id="flow8" sourceRef="startevent1" targetRef="usertask2"></sequenceFlow>
 </process>
 <bpmndi:BPMNDiagram id="BPMNDiagram_daling">
  <bpmndi:BPMNPlane bpmnElement="daling" id="BPMNPlane_daling">
   <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
    <omgdc:Bounds height="55.0" width="105.0" x="300.0" y="90.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
    <omgdc:Bounds height="55.0" width="105.0" x="450.0" y="90.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNShape bpmnElement="usertask4" id="BPMNShape_usertask4">
    <omgdc:Bounds height="55.0" width="105.0" x="600.0" y="90.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNShape bpmnElement="usertask5" id="BPMNShape_usertask5">
    <omgdc:Bounds height="55.0" width="105.0" x="750.0" y="90.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
    <omgdc:Bounds height="35.0" width="35.0" x="900.0" y="100.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
    <omgdc:Bounds height="35.0" width="35.0" x="140.0" y="90.0"></omgdc:Bounds>
   </bpmndi:BPMNShape>
   <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
    <omgdi:waypoint x="405.0" y="117.0"></omgdi:waypoint>
    <omgdi:waypoint x="450.0" y="117.0"></omgdi:waypoint>
   </bpmndi:BPMNEdge>
   <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
    <omgdi:waypoint x="555.0" y="117.0"></omgdi:waypoint>
    <omgdi:waypoint x="600.0" y="117.0"></omgdi:waypoint>
   </bpmndi:BPMNEdge>
   <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
    <omgdi:waypoint x="705.0" y="117.0"></omgdi:waypoint>
    <omgdi:waypoint x="750.0" y="117.0"></omgdi:waypoint>
   </bpmndi:BPMNEdge>
   <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
    <omgdi:waypoint x="855.0" y="117.0"></omgdi:waypoint>
    <omgdi:waypoint x="900.0" y="117.0"></omgdi:waypoint>
   </bpmndi:BPMNEdge>
   <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
    <omgdi:waypoint x="175.0" y="107.0"></omgdi:waypoint>
    <omgdi:waypoint x="300.0" y="117.0"></omgdi:waypoint>
   </bpmndi:BPMNEdge>
  </bpmndi:BPMNPlane>
 </bpmndi:BPMNDiagram>
</definitions>

1.1.1.3. 代码实现

package com.daling.ch1.jd;
import java.util.Iterator;
import java.util.Map;
import org.activiti.engine.impl.context.Context;
import org.activiti.engine.impl.interceptor.Command;
import org.activiti.engine.impl.interceptor.CommandContext;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityManager;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
/**
 *
 * JD节点的跳转
 * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
 */
public class JDJumpTaskCmd implements Command<Void> {
protected String executionId;
protected ActivityImpl desActivity;
protected Map<String, Object> paramvar;
protected ActivityImpl currentActivity;
/**
 * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
 */
public Void execute(CommandContext commandContext) {
ExecutionEntityManager executionEntityManager = Context
.getCommandContext().getExecutionEntityManager();
// 获取当前流程的executionId,因为在并发的情况下executionId是唯一的。
ExecutionEntity executionEntity = executionEntityManager
.findExecutionById(executionId);
executionEntity.setVariables(paramvar);
executionEntity.setEventSource(this.currentActivity);
executionEntity.setActivity(this.currentActivity);
// 根据executionId 获取Task
Iterator<TaskEntity> localIterator = Context.getCommandContext()
.getTaskEntityManager()
.findTasksByExecutionId(this.executionId).iterator();
while (localIterator.hasNext()) {
TaskEntity taskEntity = (TaskEntity) localIterator.next();
// 触发任务监听
taskEntity.fireEvent("complete");
// 删除任务的原因
Context.getCommandContext().getTaskEntityManager()
.deleteTask(taskEntity, "completed", false);
}
executionEntity.executeActivity(this.desActivity);
return null;
}
/**
 * 构造参数 可以根据自己的业务需要添加更多的字段
 * 分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
 * @param executionId
 * @param desActivity
 * @param paramvar
 * @param currentActivity
 */
public JDJumpTaskCmd(String executionId, ActivityImpl desActivity,
Map<String, Object> paramvar, ActivityImpl currentActivity) {
this.executionId = executionId;
this.desActivity = desActivity;
this.paramvar = paramvar;
this.currentActivity = currentActivity;
}
} 

1.1.1.4. 使用

我们先让流程运转到usertask3节点的时候开始测试跳转。

怎么使用上面的JDJumpTaskCmd类呢,直接new JDJumpTaskCmd()调用,肯定不行了,因为activiti引擎程序没有获取,肯定报错,正确的的使用方式如下:

1.1.1.4.1. 第一种方式

我们先来观察一下数据库ACT_RU_TASK表任务的记录信息,方便我们的操作,数据库记录如下图所示:

可以看到当前的节点在usertask3,我们现在把usertask3跳转到usertask5节点,看是否能成功,因为usertask3到usertask5没有连线,如果成功了,就说明我们这个方法正确。

执行下面的代码,根据自己的数据库信息修改相对应的值即可。

Map<String, Object> vars = new HashMap<String, Object>();
String[] v = { "shareniu1", "shareniu2", "shareniu3", "shareniu4" };
vars.put("assigneeList", Arrays.asList(v));
//分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
RepositoryService repositoryService = demo.getRepositoryService();
ReadOnlyProcessDefinition processDefinitionEntity = (ReadOnlyProcessDefinition) repositoryService
.getProcessDefinition("daling:29:137504");
// 目标节点
ActivityImpl destinationActivity = (ActivityImpl) processDefinitionEntity
.findActivity("usertask5");
String executionId = "137509";
// 当前节点
  ActivityImpl currentActivity = (ActivityImpl)processDefinitionEntity
   .findActivity("usertask3");
demo.getManagementService().executeCommand(
new JDJumpTaskCmd(executionId, destinationActivity, vars,
currentActivity)); 

执行上面的代码之后,我们看一下数据库中的记录。

节点确实跳转到了usertask5。ok了这个方法确实可以没问题,下面说一下第二种方式执行executeCommand命令。

1.1.1.4.2. 第二种方式

Map<String, Object> vars = new HashMap<String, Object>();
String[] v = { "shareniu1", "shareniu2", "shareniu3", "shareniu4" };
vars.put("assigneeList", Arrays.asList(v));
//分享牛原创(尊重原创 转载对的时候第一行请注明,转载出处来自分享牛http://blog.csdn.net/qq_30739519)
  CommandExecutor commandExecutor = taskServiceImpl
   .getCommandExecutor();
  commandExecutor.execute(new JDJumpTaskCmd(executionId,
   destinationActivity, vars, currentActivity)); 

上面的两种方式都可以执行自定义的Command子类。读者选择自己喜欢使用的方式即可。

1.1.2. 小结

1.任意节点的跳转,前提是节点必须在模板定义中。

2.任意节点的跳转暂时不能跨流程跳转。

3.任意节点的跳转不需要连线即可、

4.任意节点的跳转可以实现回退、转办、转阅、越级上报、一步到底等等功能,关于这些更多的实战,我们将在最后的工作流实战项目中一步步封装。使用。

以上所述是小编给大家介绍的activiti节点跳转的相关知识,希望对大家有所帮助!

(0)

相关推荐

  • Android 实现闪屏页和右上角的倒计时跳转实例代码

    以前编程的时候,遇到倒计时的功能时,经常自己去写,但其实Android已经帮封装好了一个倒计时类CountDownTimer,其实是将后台线程的创建和Handler队列封装成为了一个方便的类调用. 闪屏页用到了handler和CountDownTimer类,还需配置一下Activity的主题,这里是:android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 全屏主题的意思. 给大家展示下效果图: 代码如下所示: package

  • Android如何跳转到应用商店的APP详情页面

    需求:从App内部点击按钮或链接,跳转到应用商店的某个APP的详情页面. 让用户 下载 或 评论. 实现: /** * 启动到应用商店app详情界面 * * @param appPkg 目标App的包名 * @param marketPkg 应用商店包名 ,如果为""则由系统弹出应用商店列表供用户选择,否则调转到目标市场的应用详情界面,某些应用商店可能会失败 */ public void launchAppDetail(String appPkg, String marketPkg)

  • iOS和Android用同一个二维码实现跳转下载链接的方法

    前言 最近一个项目需要iOS和安卓使用一个二维码,让扫描的机器自己识别操作系统实现跳转到相应的下载链接.比如iPhone用微信进行扫描就让他跳转appStore的下载页面,安卓机器使用微信扫描就直接跳浏览器下载.但是这二维码还有一个需求就是,用户已经下载了这个app,当用户打开app进入到注册页面时,再次扫描这个二维码时,自动填写邀请码进行注册.那么该如何实现,细节就不说了,直接上代码. 使用js实现,其实代码非常简单. 使用时直接拷贝代码,改掉相应的链接就好. PS:该链接在微信环境打开时还是

  • 详解Android App卸载后跳转到指定的反馈页面的方法

    很多人也许会问:360被卸载之后会跳转到指定的反馈页面,是怎么弄的? 其实这个问题的核心就在于:应用被卸载了,如果能够做到后续的代码逻辑继续执行 我们再来仔细分析一下场景和流程 一个应用被用户卸载肯定是有理由的,而开发者却未必能得知这一重要的理由,毕竟用户很少会主动反馈建议,多半就是用得不爽就卸,如果能在被卸载后获取到用户的一些反馈,那对开发者进一步改进应用是非常有利的.目前据我所知,国内的Android应用中实现这一功能的只有360手机卫士.360平板卫士,那么如何实现这一功能的? 我们可以把

  • Android viewpager在最后一页滑动之后跳转到主页面的实例代码

    先给大家说下实现思路 主要有是两个监听: 一是addOnPageChangeListener();二是setOnTouchListener(): addOnPageChangeListener()主要是为了获取position(滑动到了第几页) setOnTouchListener()主要是判断在最后一页中是否向左滑动了,然后进入主页 在没给大家分享代码之前,先给大家展示下效果图: 主要功能代码 addOnPageChangeListener(); viewPager.addOnPageChan

  • Android TextView中文本点击文字跳转 (代码简单)

    在web页面中,有a标签的超链接实现跳转,同样在Android当中,用TextView控件来显示文字,实现它的事件来跳转. 用过微博Android手机端的朋友的都知道微博正文有时有一些高亮显示的文本,如话题.提到的人等等,当点击这些文本时会跳到另外一个页面(即另一个activity),下面就要来模仿微博的这个功能 点击#hello# 点击@人 一.新建一个名为WeiboContentTest的工程 二.在布局文件中添加一个textview 三.在mainactivity中创建该textview

  • Android开发之activiti节点跳转

    activiti使用的时候,通常需要跟业务紧密的结合在一起,有些业务非常的复杂,比如一个简单的采购流程:流程如下: 供应商上新商品的时候,提交商务审核,商务审核通过提交运营审核,审核失败退回供应商. 运营审核成功提交合同签订.交运营审核审核失败退回商务审核或者直接退回供应商. 合同签订审核通过结束,合同签订审核不通过返回运营审核或者退回商务审核,或者退回供应商. 上面的流程就出现了一个问题,什么问题呢? 我们来观察一下退回线的问题. 1.商务审核退回供应商上新. 2.运营审核可能退回商务审核,运

  • Android开发之5.0activity跳转时共享元素的使用方法

    在两个activity中的xml文件中编写下面的ImageView,主要的就是transitionName属性必须使用相同的属性. <ImageView android:id="@+id/item_image" android:layout_width="100dp" android:layout_height="140dp" android:layout_margin="10dp" android:transition

  • Android开发之ListView实现Item局部刷新

    对于android中的ListView刷新机制,大多数的程序员都是很熟悉的,修改或者添加adapter中的数据源之后,然后调用notifyDataSetChanged()刷新ListView.在这种模式下,我们会在getView中,根据不同的数据源,让控件显示不同的内容.这种模式是最常见的刷新模式,当我们来回滑动ListView的时候,调用adapter的getView方法,然后listview对adapter返回的View进行绘制.这种模式下,View的显示内容或状态都记录在adapter里面

  • Android开发之Notification通知用法详解

    本文实例讲述了Android开发之Notification通知用法.分享给大家供大家参考,具体如下: 根据activity的生命周期,在activity不显示时,会执行onStop函数(比如按下home键),所以你在onStop函数(按退出键除外)里面把notification放在通知栏里,再此显示时,把notification从通知栏里去掉.或者,只要程序在运行就一直显示通知栏图标. 下面对Notification类中的一些常量,字段,方法简单介绍一下: 常量: DEFAULT_ALL 使用所

  • Android 开发之dataBinding与ListView及事件

    2015年Google IO大会分布了DataBinding库,能够更快捷便利的实现MVVM结构模式.但是,通过对DataBinding的学习,其中踩过得坑,今天要在这里记录一下.对于DataBinding一些比较基础的使用,在这里就不在记录了,毕竟现在Google一下,出来很多的教程,而且,android developer官网中,也已经对其基本使用方法做了详细介绍,有英语基础的童鞋,还是去看比较官方的文章.如果英文基础不太好的,https://realm.io/cn/news/data-bi

  • Android开发之TextView使用intent传递信息,实现注册界面功能示例

    本文实例讲述了Android开发之TextView使用intent传递信息,实现注册界面功能.分享给大家供大家参考,具体如下: 使用intent在活动间传递值 首先是 MainActuvity 活动(注册界面 写完个人信息点击注册 ) 跳转到 In 活动 (通过 intent 获得 MainActivity 中的信息 ) 效果图如下: MainActivity 实现: Java代码: public class Home extends AppCompatActivity { //用于存放个人注册

  • Android开发之FloatingActionButton悬浮按钮基本使用、字体、颜色用法示例

    本文实例讲述了Android开发之FloatingActionButton悬浮按钮基本使用.字体.颜色用法.分享给大家供大家参考,具体如下: 这里主要讲: FloatingActionsMenu自定义样式以及title调整 FloatingActionButton的基本方法 看一下效果图: 这里使用的是:com.getbase.floatingactionbutton.FloatingActionsMenu 先说下它的配置:在app/build.gradle 添加以下代码依赖: 圆形悬浮按钮 i

  • Android开发之Gradle 进阶Tasks深入了解

    目录 前言 定义Task register与create的区别 查找Task 配置Task 将参数传递给Task构造函数 Task添加依赖 Task排序 Task添加说明 跳过Task 使用onlyIf 使用 StopExecutionException 禁用与启用Task Task超时 Task支持增量编译 Task的输入输出 自定义task类型 声明输入输出的好处 推断task依赖关系 输入和输出验证 并行task 增量编译原理解析 一些高端操作 将@OutputDirectory链接到@I

  • Android开发之Button事件实现与监听方法总结

    本文实例总结了Android开发之Button事件实现与监听方法.分享给大家供大家参考,具体如下: 先来介绍Button事件实现的两种方法 main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="

  • Android开发之button事件监听简单实例

    本文实例讲述了Android开发之button事件监听用法.分享给大家供大家参考.具体如下: 事件监听的listener,有以下几种方式: 1.声明一个普通的class,实现OnClickListener接口,然后在button的setOnClickListener中new该类的一个对象. 2.使用匿名内部类,直接 btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { S

随机推荐