 流程设计器教程
---
# 1.开始事件和结束事件
---
对应着流程的开始和结束。
> 应该保证每个分支都可以从开始走到结束

## 开始事件
开始事件用来指明流程在哪里开始。开始事件的类型（流程在接收事件时启动， 还是在指定时间启动，等等），定义了流程如何启动。



> 一般使用第一个空的开始事件就可以了,需要手动启动流程

*属性*
![](/assets/act_vacationReq_bg_v.png)

* 初始化器

  当流程启动时，把当前登录的用户保存到哪个变量名中，可以在表达式里直接引用该变量
* 表单属性

  当执行到开始事件时，所有的流程变量都是可用的，但是可能需要一些用于表单展示的自定义变量，此时可以在表单属性中定义,将会保存到流程的`共享变量`区域
  
  ![](/assets/act_vacationReq_form.png)
  如图是`请假流程`的开始事件的表单属性，在这里定义的变量，在`工作流测试页面`会自动渲染成表单
  支持以下的几种表单属性类型：

 * string (org.activiti.engine.impl.form.StringFormType)
 * long (org.activiti.engine.impl.form.LongFormType)
 * enum (org.activiti.engine.impl.form.EnumFormType)
 * date (org.activiti.engine.impl.form.DateFormType)
 * boolean (org.activiti.engine.impl.form.BooleanFormType)

  > 括号里是作为流程变量存储的对应JAVA类
  表达式和变量
  
  如果设置了`变量`，需要通过变量名来引用变量，表达式同理
  > 默认则是把id作为变量名使用
 
  * 必须   如果勾选了，提交表单时没有提供该属性则抛出异常
  * 可读   不勾选则不会进行自动渲染显示，但是还是可以提交
  * 可写   不够勾选，还提交该属性，也会抛出异常
  
  
## 结束事件
  结束事件表示（子）流程（分支）的结束。 结束事件都是触发事件。 这是说当流程达到结束事件，会触发一个结果。 结果的类型是通过事件的内部黑色图标表示的。
  > 一般使用一个空的结束事件就行了，意味着到达事件时不会指定抛出的结果。 这样，引擎会直接结束当前执行的分支，不会做其他事情。
  
### 自动结束流程（HAP 扩展特性）

当一个任务被拒绝时，绝大多数情况下，这个流程应该直接结束。   
但在工作流中，`审批拒绝`和`审批同意` 仅仅是给变量赋的参数值不同而已，如果希望流程结束，应该加一个 `选择网关`，判断审批结果是否为 `拒绝` ，然后引导流程走向`结束事件`。

显然，这很繁琐，尤其是当流程中`人工任务`节点比较多时。   

HAP 做了一个优化：   
> 如果一个`人工任务` 的下一个节点仍然是 `任务（Task 类型）`，那么 HAP 将会自动插入一个`选择网关`和`终止事件` 来自动做结束流程的操作

这个优化在流程的图上是看不出来的，用户完全无感知。


  
# 2.任务
---

常用的是人工任务，和服务任务

## 人工任务(UserTask)
![](/assets/act_vacationReq_userTask.png)

### 任务派遣
**指定审批人、组**

点击`任务派遣` 弹出对话框

<img width='600' src='/assets/usertask-assignment.png'/>

其中：
* 指派对象    
只能有一个人，可以点击`选择`按钮来从系统中选择员工
* 候选用户   
可以添加多个，每个指定一个`员工工号`
* 候选组   
可以添加多个，每个指定一个`岗位代码`



**动态审批人、组**

与 上面类似，不过动态的审批人和组不是选择的，而是通过表达式计算得来。   

`表达式`有两种情况
   * 引用变量   
   比如`${initiator}`， 其中`initiator` 就是一个变量
   * 调用 service 方法   
   比如`${orgStructure.getDirector(initiator)}`，其中 `orgStructure` 是一个自定的用于工作流的 `bean`，参数则可以使用任意的变量、常量等
   
   > `execution` 是一个固有的、特殊的变量，指代 `org.activiti.engine.delegate.DelegateExecution`，非常有用

关于自定义在工作流中用的 `bean`：   
HAP 提供一个 接口 `com.hand.hap.activiti.custom.IActivitiBean`。   
实现这个接口并被定义注册为 bean，其中的任何 `public` 方法都可以在工作流表达式中直接调用。   
默认 bean 的 名字就是引用名，也可以覆盖接口的默认实现，指定名称。

### 表单的标识Key

   用于在待办明细页面中，动态渲染页面，设置为表单html页面的路径
   
### 表单属性 

   跟开始事件的表单属性一样

**审批动作**
Hap 的工作流在审批的时候默认有两个标准的动作：
* 同意（APPROVED）
* 拒绝（REJECTED）

当审批者点击按钮以后，审批动作 id 会被保存到流程的`共享变量`区域。
key 为 `approveResult`，这个变量可以直接在表达式中使用。

```
${approveResult=='REJECTED'}
```


流程设计时，可以控制这两个按钮显示的文本；也可以控制只显示其中的一个。


允许自定义额外的审批动作，自动动作的 id 同样会保存在 `approveResult` 变量中，通常需要流程显示处理（比如选择网关）。

<img width='920' src='/assets/custom-approve-action.png'/>

### 会签设置
  会签通过设置`多实例`属性来实现，有串行和并行两种模式。
  > 三条竖线表示实例会并行执行。 三条横线表示顺序执行。
  
  <img width='920' src='/assets/activiti_parallel.png'/>

  `集合` 应该返回一个字符串数组，表示用户集合
  > 并行执行 会立刻为所有集合成员创建任务实例
  > 串行执行 会依次创建任务实例，完成一个才会创建下一个
  
  `元素变量` 遍历用户集合的单个对象变量名称
  > 任务派遣 设置${元素变量}即可
  
  `完成条件`  
  > activiti 标准会签,默认有 3 个参数, 可以作为结束条件考量依据.
分别是
 * nrOfInstances(实例个数，根据集集合表达式中获取的对象个数确定)
 * nrOfCompletedInstances(已经完成的实例个数，比如已经同意或者拒绝的)
 * nrOfActiveInstances(还未完成的实例个数)
>
hap 自定义了两个: 
 * nrOfApproved(同意的实例个数)
 * nrOfRejected(拒绝的实例个数)
 
## 服务任务（ServiceTask）
用来调用外部java类

有三种方式

### 类名
在`类名`属性设置类的完整限定名
比如`com.hand.hap.activiti.demo.DemoServiceTask`
直
>  需要实现JavaDelegate接口
   类只会初始化一次， 类似 servlet 的模式。
   
### 代理表达式
执行解析代理对象的表达式，直接通过表达式确定代理对象
比如`$(demoServiceTaskDelegate)`
> 参考com.hand.hap.activiti.demo.components.DemoServiceTaskDelegate 实现JavaDelegate接口和IActivitiBean
注意是用$符号，这是delegateExpression，与普通的表达式有区别

### 表达式
可以调用指定方法
`#{demoServiceTaskDelegate.method1(execution,task2Output)}`

# 3.网关
网关用来控制流程的流向

网关显示成菱形图形，内部有有一个小图标。 图标表示网关的类型

### 单一网关
  内部图标是一个“X”
  当流程执行到这个网关，所有外出顺序流都会被处理一遍。 通过设置`跳转条件`控制流程走向。
> 比如 ${approveResult == 'REJECTED'}，表示拒绝后的流程走向。

  可以设置`默认跳转`，当其他所以顺序流的跳转条件都返回false时触发。
> 注意如果多个顺序流的条件结果为true，单一网关只会选择一个执行。

### 并行网关
  内部是一个“+”图标
  并行网关的功能是基于进入和外出的顺序流的：          

* 分支： 并行后的所有外出顺序流，为每个顺序流都创建一个并发分支。              

* 汇聚： 所有到达并行网关，在此等待的进入分支， 直到所有进入顺序流的分支都到达以后， 流程就会通过汇聚网关。              

  注意，如果同一个并行网关有多个进入和多个外出顺序流，   它就同时具有分支和汇聚功能。   这时，网关会先汇聚所有进入的顺序流，然后再切分成多个并行分支。        

与其他网关的主要区别是，并行网关*不会解析条件*。   即使顺序流中定义了条件，也会被忽略。  

>参考[Activiti5.16中文手册](http://www.mossle.com/docs/activiti/index.html)