Activiti6.0 多级审批流程 代码执行

Activiti6.0 多级审批流程 代码执行

背景:公司要求有流程审批系统以便于适应不同客户的审批层级;确定以Activiti6.0作为流程引擎;

这里给出一个简单的多级审批流程:

  • 创建流程图,我这里流程图在eclipse中生成的,使用了Activiti Eclipse BPMN 2.0 Designer插件;流程图为.bpmn格式,我们在解析的时候,可以重命名为.bpmn20.xml;

这里给出一个多级审批的流程图:

这个图我加了一些文字说明,丑了点,将就着看吧;

然后我给出这个流程图对应的源码:文件全名称为ApprovalProcess.bpmn20.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="myProcess" name="流程审批" isExecutable="true">
        <startEvent id="startEvent" name="开始"></startEvent>
        <userTask id="Submit" name="填写信息提交校对">
            <extensionElements>
                <activiti:formProperty id="SubmitMessage" name="提交时填写的信息" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="SubmitUserName" name="申请人" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="SubmitTime" name="提交时间" type="date" datePattern="yyyy-MM-dd"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="SubmitType" name="是否提交校对" type="string"
                                       required="true"></activiti:formProperty>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow1" sourceRef="startEvent" targetRef="Submit"></sequenceFlow>
        <exclusiveGateway id="decideSubmit" name="提交校对或者取消"></exclusiveGateway>
        <sequenceFlow id="flow2" sourceRef="Submit" targetRef="decideSubmit"></sequenceFlow>
        <userTask id="Proofread" name="校对">
            <extensionElements>
                <activiti:formProperty id="ProofreadMessage" name="校对时填写的信息" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ProofreadUserName" name="校对人" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ProofreadTime" name="校对时间" type="date" datePattern="yyyy-MM-dd"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ProofreadType" name="是否校对通过" type="string"
                                       required="true"></activiti:formProperty>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow3" sourceRef="decideSubmit" targetRef="Proofread">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${SubmitType=="Y" || SubmitType=="y"}]]></conditionExpression>
        </sequenceFlow>
        <exclusiveGateway id="decideProofread" name="校对通过或者失败"></exclusiveGateway>
        <sequenceFlow id="flow4" sourceRef="Proofread" targetRef="decideProofread"></sequenceFlow>
        <userTask id="Review" name="审核">
            <extensionElements>
                <activiti:formProperty id="ReviewMesage" name="审核时填写的信息" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ReviewUserName" name="审核人" type="string"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ReviewTime" name="审核时间" type="date" datePattern="yyyy-MM-dd"
                                       required="true"></activiti:formProperty>
                <activiti:formProperty id="ReviewType" name="是否审核通过" type="string"
                                       required="true"></activiti:formProperty>
            </extensionElements>
        </userTask>
        <sequenceFlow id="flow5" sourceRef="decideProofread" targetRef="Review">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${ProofreadType=="Y" || ProofreadType=="y"}]]></conditionExpression>
        </sequenceFlow>
        <exclusiveGateway id="decideReview" name="审核通过或者失败"></exclusiveGateway>
        <sequenceFlow id="flow6" sourceRef="Review" targetRef="decideReview"></sequenceFlow>
        <endEvent id="endEvent1" name="结束"></endEvent>
        <sequenceFlow id="flow7" sourceRef="decideReview" targetRef="endEvent1">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${ReviewType=="Y" || ReviewType=="y"}]]></conditionExpression>
        </sequenceFlow>
        <endEvent id="endEventCancel" name="取消"></endEvent>
        <sequenceFlow id="flow8" sourceRef="decideSubmit" targetRef="endEventCancel">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${SubmitType=="N" || SubmitType=="n"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow9" sourceRef="decideProofread" targetRef="Submit">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${ProofreadType=="N" || ProofreadType=="n"}]]></conditionExpression>
        </sequenceFlow>
        <sequenceFlow id="flow10" sourceRef="decideReview" targetRef="Submit">
            <conditionExpression xsi:type="tFormalExpression">
                <![CDATA[${ReviewType=="N" || ReviewType=="n"}]]></conditionExpression>
        </sequenceFlow>
    </process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
        <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
            <bpmndi:BPMNShape bpmnElement="startEvent" id="BPMNShape_startEvent">
                <omgdc:Bounds height="35.0" width="35.0" x="130.0" y="260.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="Submit" id="BPMNShape_Submit">
                <omgdc:Bounds height="55.0" width="105.0" x="210.0" y="250.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="decideSubmit" id="BPMNShape_decideSubmit">
                <omgdc:Bounds height="40.0" width="40.0" x="360.0" y="258.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="Proofread" id="BPMNShape_Proofread">
                <omgdc:Bounds height="55.0" width="105.0" x="445.0" y="251.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="decideProofread" id="BPMNShape_decideProofread">
                <omgdc:Bounds height="40.0" width="40.0" x="595.0" y="259.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="Review" id="BPMNShape_Review">
                <omgdc:Bounds height="55.0" width="105.0" x="680.0" y="252.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="decideReview" id="BPMNShape_decideReview">
                <omgdc:Bounds height="40.0" width="40.0" x="830.0" y="260.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="endEvent1" id="BPMNShape_endEvent1">
                <omgdc:Bounds height="35.0" width="35.0" x="915.0" y="263.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="endEventCancel" id="BPMNShape_endEventCancel">
                <omgdc:Bounds height="35.0" width="35.0" x="440.0" y="350.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
                <omgdi:waypoint x="165.0" y="277.0"></omgdi:waypoint>
                <omgdi:waypoint x="210.0" y="277.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
                <omgdi:waypoint x="315.0" y="277.0"></omgdi:waypoint>
                <omgdi:waypoint x="360.0" y="278.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
                <omgdi:waypoint x="400.0" y="278.0"></omgdi:waypoint>
                <omgdi:waypoint x="445.0" y="278.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
                <omgdi:waypoint x="550.0" y="278.0"></omgdi:waypoint>
                <omgdi:waypoint x="595.0" y="279.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
                <omgdi:waypoint x="635.0" y="279.0"></omgdi:waypoint>
                <omgdi:waypoint x="680.0" y="279.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
                <omgdi:waypoint x="785.0" y="279.0"></omgdi:waypoint>
                <omgdi:waypoint x="830.0" y="280.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
                <omgdi:waypoint x="870.0" y="280.0"></omgdi:waypoint>
                <omgdi:waypoint x="915.0" y="280.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
                <omgdi:waypoint x="380.0" y="298.0"></omgdi:waypoint>
                <omgdi:waypoint x="380.0" y="367.0"></omgdi:waypoint>
                <omgdi:waypoint x="440.0" y="367.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
                <omgdi:waypoint x="615.0" y="299.0"></omgdi:waypoint>
                <omgdi:waypoint x="614.0" y="401.0"></omgdi:waypoint>
                <omgdi:waypoint x="262.0" y="398.0"></omgdi:waypoint>
                <omgdi:waypoint x="262.0" y="305.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
                <omgdi:waypoint x="850.0" y="260.0"></omgdi:waypoint>
                <omgdi:waypoint x="850.0" y="87.0"></omgdi:waypoint>
                <omgdi:waypoint x="565.0" y="87.0"></omgdi:waypoint>
                <omgdi:waypoint x="262.0" y="87.0"></omgdi:waypoint>
                <omgdi:waypoint x="262.0" y="250.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</definitions>
  • maven项目引入dependency依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.sd</groupId>
    <artifactId>process</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-engine</artifactId>
            <version>6.0.0</version>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>28.2-jre</version>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</project>

这里说明一下因为是代码测试,因此数据库使用的是H2内存数据库;

  • 流程执行代码
package org.sd.processs;

import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.form.FormProperty;
import org.activiti.engine.form.TaskFormData;
import org.activiti.engine.impl.form.DateFormType;
import org.activiti.engine.impl.form.StringFormType;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.Executors;

/**
 * @author sword_happy
 */
@Slf4j
public class ProcessMain {

    public static void main(String[] args) throws ParseException {
        log.info("启动我们的程序!");
        //1 创建流程引擎,基于内存的数据库处理
        ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
        ProcessEngine processEngine = cfg.buildProcessEngine();
        String name = processEngine.getName();
        String version = ProcessEngine.VERSION;

        log.info("流程引擎名称:[{}] 版本:[{}]", name, version);
        //2 部署流程定义文件
        RepositoryService repositoryService = processEngine.getRepositoryService();
        DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
        deploymentBuilder.addClasspathResource("ApprovalProcess.bpmn20.xml");
        Deployment deployment = deploymentBuilder.deploy();
        String deploymentId = deployment.getId();

        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .deploymentId(deploymentId)
                .singleResult();

        log.info("流程定义文件 [{}],流程ID [{}]", processDefinition.getName(), processDefinition.getId());

        //3 启动运行流程
        RuntimeService runtimeService = processEngine.getRuntimeService();
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());

        log.info("启动流程 [{}]", processInstance.getProcessDefinitionKey());

        //4 处理流程任务
        Scanner scanner = new Scanner(System.in);
        while (processInstance != null && !processInstance.isEnded()) {

            TaskService taskService = processEngine.getTaskService();
            List<Task> list = taskService.createTaskQuery().list();

            System.out.println("共计[" + list.size() + "]个任务");

            for (Task task : list) {
                log.info("待处理任务 [{}]", task.getName());

                FormService formService = processEngine.getFormService();

                TaskFormData taskFormData = formService.getTaskFormData(task.getId());

                List<FormProperty> formProperties = taskFormData.getFormProperties();

                Map<String, Object> variables = Maps.newHashMap();
                for (FormProperty formProperty : formProperties) {
                    String line = null;
                    if (StringFormType.class.isInstance(formProperty.getType())) {
                        log.info("请输入 {} ?", formProperty.getName());
                        line = scanner.nextLine();
                        variables.put(formProperty.getId(), line);
                    } else if (DateFormType.class.isInstance(formProperty.getType())) {
                        log.info("请输入 {} ? 格式 (yyyy-MM-dd)", formProperty.getName());
                        line = scanner.nextLine();
                        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
                        Date date = simpleDateFormat.parse(line);
                        variables.put(formProperty.getId(), date);
                    } else {
                        log.info("类型暂不支持 {}", formProperty.getType());
                    }
                    log.info("您输入的内容是 [{}] ?", line);
                }

                taskService.complete(task.getId(), variables);
                processInstance = processEngine.getRuntimeService()
                        .createProcessInstanceQuery()
                        .processInstanceId(processInstance.getId())
                        .singleResult();
            }

        }

        log.info("结束我们的程序!");
    }
}

OK,到此为止,大功告成;

提示一下,这里是基于H2的内存数据库,因此构造对象的时候使用了Memory的方法;

后面的一些对象都是通过ProcessEngine进行获取或者间接获取的;==>意味着在Spring中,我们使用Activiti各种service的时候,只需要添加@Autowired注解就可以直接使用;

过段时间我会再写一篇基于SpringBoot的activiti6.0多级审批的博客.

希望本篇博客对你有帮助;

 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sword_happy

您的鼓励亦是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值