美文网首页
Activiti实现会签功能程序Demo

Activiti实现会签功能程序Demo

作者: 名字还没想好呢 | 来源:发表于2020-08-26 11:13 被阅读0次

    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;

    }

    }

    相关文章

      网友评论

          本文标题:Activiti实现会签功能程序Demo

          本文链接:https://www.haomeiwen.com/subject/dxzujktx.html