Activiti实现会签功能程序Demo

Activiti会签功能

1、会签是什么?

会签功能指多个人员针对同一个事务进行协商处理,共同签署决定一件事情。 

在工作流中会签,是指多个人员在同一个环节进行处理,同一环节的有多个处理人并行处理,按照配置规则,固定比例的人员办理完成后即可继续流转至下一环节。

2、会签的种类

a)    按数量通过:达到一定数量的通过表决后,会签通过。

b)    按比例通过:达到一定比例的通过表决后,会签通过。

c)    一票否决:只要有一个表决时否定的,会签通过。

d)    一票通过:只要有一个表决通过的,会签通过。

3、Activiti实现会签

Activiti实现会签是基于多实例任务,将节点设置成多实例,主要通过在UserTask节点的属性上配置

4、完整代码

4.1流程图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="http://www.activiti.org/test">

  <process id="applyHoliday2" name="请假申请" isExecutable="true">

    <startEvent id="startevent1" name="Start"></startEvent>

    <userTask id="usertask1" name="申请"></userTask>

    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>

    <userTask id="usertask2" name="会签" activiti:assignee="${signer}">

      <extensionElements>

        <activiti:taskListener event="complete" class="cn.com.xu.applyHoliday.SignListener"></activiti:taskListener>

      </extensionElements>

      <multiInstanceLoopCharacteristics isSequential="false" activiti:collection="${signList}" activiti:elementVariable="signer">

        <completionCondition>${pass == false}</completionCondition>

      </multiInstanceLoopCharacteristics>

    </userTask>

    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>

    <userTask id="usertask3" name="记录"></userTask>

    <endEvent id="endevent1" name="End"></endEvent>

    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>

    <exclusiveGateway id="exclusivegateway1" name="Exclusive Gateway"></exclusiveGateway>

    <sequenceFlow id="flow7" sourceRef="usertask2" targetRef="exclusivegateway1"></sequenceFlow>

    <sequenceFlow id="flow8" name="通过" sourceRef="exclusivegateway1" targetRef="usertask3">

      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "Y"}]]></conditionExpression>

    </sequenceFlow>

    <sequenceFlow id="flow9" name="拒绝" sourceRef="exclusivegateway1" targetRef="usertask1">

      <conditionExpression xsi:type="tFormalExpression"><![CDATA[${result == "N"}]]></conditionExpression>

    </sequenceFlow>

  </process>

  <bpmndi:BPMNDiagram id="BPMNDiagram_applyHoliday2">

    <bpmndi:BPMNPlane bpmnElement="applyHoliday2" id="BPMNPlane_applyHoliday2">

      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">

        <omgdc:Bounds height="35.0" width="35.0" x="250.0" y="210.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">

        <omgdc:Bounds height="55.0" width="105.0" x="330.0" y="200.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">

        <omgdc:Bounds height="55.0" width="105.0" x="500.0" y="200.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">

        <omgdc:Bounds height="55.0" width="105.0" x="860.0" y="200.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">

        <omgdc:Bounds height="35.0" width="35.0" x="1080.0" y="210.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNShape bpmnElement="exclusivegateway1" id="BPMNShape_exclusivegateway1">

        <omgdc:Bounds height="40.0" width="40.0" x="710.0" y="207.0"></omgdc:Bounds>

      </bpmndi:BPMNShape>

      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">

        <omgdi:waypoint x="285.0" y="227.0"></omgdi:waypoint>

        <omgdi:waypoint x="330.0" y="227.0"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">

        <omgdi:waypoint x="435.0" y="227.0"></omgdi:waypoint>

        <omgdi:waypoint x="500.0" y="227.0"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">

        <omgdi:waypoint x="965.0" y="227.0"></omgdi:waypoint>

        <omgdi:waypoint x="1080.0" y="227.0"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">

        <omgdi:waypoint x="605.0" y="227.0"></omgdi:waypoint>

        <omgdi:waypoint x="710.0" y="227.0"></omgdi:waypoint>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">

        <omgdi:waypoint x="750.0" y="227.0"></omgdi:waypoint>

        <omgdi:waypoint x="860.0" y="227.0"></omgdi:waypoint>

        <bpmndi:BPMNLabel>

          <omgdc:Bounds height="14.0" width="100.0" x="750.0" y="227.0"></omgdc:Bounds>

        </bpmndi:BPMNLabel>

      </bpmndi:BPMNEdge>

      <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">

        <omgdi:waypoint x="730.0" y="247.0"></omgdi:waypoint>

        <omgdi:waypoint x="729.0" y="354.0"></omgdi:waypoint>

        <omgdi:waypoint x="382.0" y="354.0"></omgdi:waypoint>

        <omgdi:waypoint x="382.0" y="255.0"></omgdi:waypoint>

        <bpmndi:BPMNLabel>

          <omgdc:Bounds height="14.0" width="100.0" x="730.0" y="247.0"></omgdc:Bounds>

        </bpmndi:BPMNLabel>

      </bpmndi:BPMNEdge>

    </bpmndi:BPMNPlane>

  </bpmndi:BPMNDiagram>

</definitions>

(如需项目DEMO源码同学可发送主题“springboot-activiti”至1829003685@qq.com)

4.2会签监听代码

package cn.com.xu.applyHoliday;

import org.activiti.engine.ProcessEngine;

import org.activiti.engine.ProcessEngines;

import org.activiti.engine.RuntimeService;

import org.activiti.engine.TaskService;

import org.activiti.engine.delegate.DelegateTask;

import org.activiti.engine.delegate.TaskListener;

import org.activiti.engine.task.Task;

/**

* 会签监听

* @author1829003685@qq.com2019年5月7日 上午11:12:42

*

*/

public class SignListener implements TaskListener {

private static final long serialVersionUID = 1L;

@Override

public void notify(DelegateTask delegateTask) {

System.out.println("会签监听");

//获取流程id

String exId = delegateTask.getExecutionId();

//获取流程参数pass,会签人员完成自己的审批任务时会添加流程参数pass,false为拒绝,true为同意

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

RuntimeService runtimeService = engine.getRuntimeService();

TaskService taskService = engine.getTaskService();

boolean pass = (Boolean) runtimeService.getVariable(exId, "pass");

/*

* false:有一个人拒绝,整个流程就结束了,

* 因为Complete condition的值为pass == false,即,当流程参数为pass时会签就结束开始下一个任务

* 所以,当pass == false时,直接设置下一个流程跳转需要的参数

* true:审批人同意,同时要判断是不是所有的人都已经完成了,而不是由一个人同意该会签就结束

* 值得注意的是如果一个审批人完成了审批进入到该监听时nrOfCompletedInstances的值还没有更新,因此需要+1

*/

if(pass == false){

//会签结束,设置参数result为N,下个任务为申请

runtimeService.setVariable(exId, "result", "N");

//下个任务

String processInstanceId = delegateTask.getProcessInstanceId();

Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

System.out.println("下个任务编码:" + task.getId() + ",下个任务名称:" + task.getName());

}else{

Integer complete = (Integer) runtimeService.getVariable(exId, "nrOfCompletedInstances");

Integer all = (Integer) runtimeService.getVariable(exId, "nrOfInstances");

//说明都完成了并且没有人拒绝

if((complete + 1) / all == 1){

runtimeService.setVariable(exId, "result", "Y");

//下个任务

String processInstanceId = delegateTask.getProcessInstanceId();

Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();

System.out.println("下个任务编码:" + task.getId() + ",下个任务名称:" + task.getName());

}

}

}

}

4.3流程图部署以及启动

package cn.com.xu.applyHoliday;

import java.util.ArrayList;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.activiti.engine.IdentityService;

import org.activiti.engine.ProcessEngine;

import org.activiti.engine.ProcessEngines;

import org.activiti.engine.RepositoryService;

import org.activiti.engine.RuntimeService;

import org.activiti.engine.TaskService;

import org.activiti.engine.repository.DeploymentBuilder;

import org.activiti.engine.runtime.ProcessInstance;

import org.activiti.engine.task.Task;

import cn.com.xu.bean.Emp;

/**

* 流程部署以及启动

* @author1829003685@qq.com 2019年5月7日 上午11:07:36

*

*/

public class ActivitiDeploy {

public static void main(String[] args) {

//获取流程引擎

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

//获取流程存储服务组件

RepositoryService repositoryService = engine.getRepositoryService();

//部署流程描述文件

DeploymentBuilder builder = repositoryService.createDeployment();

builder.addClasspathResource("bpmn/applyHoliday.bpmn").deploy();

//获取运行时服务组件

RuntimeService runtimeService = engine.getRuntimeService();

TaskService taskService = engine.getTaskService();

//启动流程引擎

ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("applyHoliday2");

//获取身份服务组件

IdentityService identityService = engine.getIdentityService();

System.out.println("启动成功,流程id为:" + processInstance.getId());

//创建模拟用户

createUser(identityService);

//启动任务

startTask(taskService, processInstance.getId());

}

/**

* 设置会签人员并启动任务

* @param taskService

* @param proId

*/

public static void startTask(TaskService taskService, String proId){

Task task = taskService.createTaskQuery().processInstanceId(proId).singleResult();

System.out.println("当前任务编码:" + task.getId() + ",当前任务名称:" + task.getName());

//设置会签人员

Map<String, Object> var = new HashMap<String, Object>();

List<String> signList = new ArrayList<String>();

signList.add("zhangSan");

signList.add("liSi");

var.put("signList", signList);

taskService.complete(task.getId(), var);

}

/**

* 新增员工,模拟流程

* @param identityService

*/

public static void createUser(IdentityService identityService){

Emp.createUser(identityService, "zhangSan", "张", "三");

Emp.createUser(identityService, "liSi", "李", "四");

Emp.createUser(identityService, "wangWu", "王", "五");

System.out.println("新建员工成功");

}

}

4.4会签人员任务处理代码

package cn.com.xu.applyHoliday;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import org.activiti.engine.ProcessEngine;

import org.activiti.engine.ProcessEngines;

import org.activiti.engine.TaskService;

import org.activiti.engine.task.Task;

/**

* 会签处理

* @author1829003685@qq.com2019年5月7日 上午11:07:12

*

*/

public class SignHandle {

public static void main(String[] args) {

ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();

TaskService taskService = engine.getTaskService();

handleWaitWork(taskService, "liSi", true);

}

/**

* 处理代办任务

* @param taskService

* @param empCode

* @param result 审批结果;true:同意;false:拒绝

*/

public static void handleWaitWork(TaskService taskService, String empCode, boolean result){

List<Task> tasks = taskService.createTaskQuery().taskAssignee(empCode).orderByTaskId().desc().list();

if(tasks != null && tasks.size() != 0){

for(Task tempTask : tasks){

//处理代办

Map<String, Object> map = new HashMap<String, Object>();

map.put("pass", result);

taskService.complete(tempTask.getId(), map);

}

}else{

System.out.println("没有代办任务");

}

}

}

4.5 用户实体类

package cn.com.xu.bean;

import java.util.ArrayList;

import java.util.List;

import org.activiti.engine.IdentityService;

import org.activiti.engine.identity.Group;

import org.activiti.engine.identity.User;

/**

* 创建用户

* @author1829003685@qq.com 2019年2月18日 下午3:32:15

*

*/

public class Emp {

/**

* 创建用户信息

* @param service 身份组件

* @param empCode 员工编码

* @return

*/

public static User createUser(IdentityService service, String empCode, String firstName, String lastName){

User user = service.newUser(empCode);

user.setFirstName(firstName);//姓

user.setLastName(lastName);//名

user.setPassword("123456");//密码

service.saveUser(user);

return service.createUserQuery().userId(empCode).singleResult();

}

/**

* 根据用户编码查询用户信息

* @param service

* @param empCode

* @return

*/

public static User getUserByUserCode(IdentityService service, String empCode){

return service.createUserQuery().userLastName(empCode).singleResult();

}

/**

* 根据用户编码查询所属角色

* @param service

* @param empCode

* @return

*/

public static List<String> getGroupList(IdentityService service, String empCode){

List<String> rstList = new ArrayList<String>();

List<Group> groups = service.createGroupQuery().groupMember(getUserByUserCode(service, empCode).getId()).list();

if(groups != null && groups.size() != 0){

for(Group g : groups){

rstList.add(g.getType());

}

}

return rstList;

}

}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355