activiti02

二级审批流程的实现

1.设计一个二级审批流程

2.创建三个不同用户组为流程参与者

3.参与者协同完成流程

 

 

second_approve.bpmn 设计

 

对应xml文件如下

  1 <?xml version="1.0" encoding="UTF-8"?>
  2 <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">
  3   <process id="LeaveProcess" name="请假流程" isExecutable="true">
  4     <startEvent id="startevent" name="开始"></startEvent>
  5     <userTask id="submitform" name="填写请假申请">
  6       <extensionElements>
  7         <activiti:formProperty id="message" name="申请信息" type="string" required="true"></activiti:formProperty>
  8         <activiti:formProperty id="name" name="申请人姓名" type="string" required="true"></activiti:formProperty>
  9         <activiti:formProperty id="submitTime" name="提交时间" type="date" datePattern="yyyy-MM-dd" required="true"></activiti:formProperty>
 10         <activiti:formProperty id="submitType" name="确认申请" type="string" required="true"></activiti:formProperty>
 11       </extensionElements>
 12     </userTask>
 13     <sequenceFlow id="flow1" sourceRef="startevent" targetRef="submitform"></sequenceFlow>
 14     <exclusiveGateway id="decideSubmit" name="提交或取消"></exclusiveGateway>
 15     <sequenceFlow id="flow2" sourceRef="submitform" targetRef="decideSubmit"></sequenceFlow>
 16     <userTask id="ZG_approve" name="部门主管审批">
 17       <extensionElements>
 18         <activiti:formProperty id="ZGapprove" name="主管审批结果" type="string" required="true"></activiti:formProperty>
 19         <activiti:formProperty id="ZGmessage" name="主管备注" type="string" required="true"></activiti:formProperty>
 20       </extensionElements>
 21     </userTask>
 22     <sequenceFlow id="flow3" sourceRef="decideSubmit" targetRef="ZG_approve">
 23       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType=="y" || submitType=="Y"}]]></conditionExpression>
 24     </sequenceFlow>
 25     <exclusiveGateway id="decideZGapprove" name="主管审批校验"></exclusiveGateway>
 26     <sequenceFlow id="flow4" sourceRef="ZG_approve" targetRef="decideZGapprove"></sequenceFlow>
 27     <userTask id="ZJL_approve" name="总经理审批">
 28       <extensionElements>
 29         <activiti:formProperty id="ZJLapprove" name="总经理审批结果" type="string" required="true"></activiti:formProperty>
 30         <activiti:formProperty id="ZJLmessage" name="总经理备注" type="string" required="true"></activiti:formProperty>
 31       </extensionElements>
 32     </userTask>
 33     <sequenceFlow id="flow5" sourceRef="decideZGapprove" targetRef="ZJL_approve">
 34       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ZGapprove=="y" || ZGapprove=="Y"}]]></conditionExpression>
 35     </sequenceFlow>
 36     <exclusiveGateway id="decideZJLapprove" name="总经理审批校验"></exclusiveGateway>
 37     <sequenceFlow id="flow6" sourceRef="ZJL_approve" targetRef="decideZJLapprove"></sequenceFlow>
 38     <endEvent id="endevent" name="结束"></endEvent>
 39     <sequenceFlow id="flow7" sourceRef="decideZJLapprove" targetRef="endevent">
 40       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ZJLapprove=="y" || ZJLapprove=="Y"}]]></conditionExpression>
 41     </sequenceFlow>
 42     <endEvent id="endeventCancel" name="取消"></endEvent>
 43     <sequenceFlow id="flow8" sourceRef="decideSubmit" targetRef="endeventCancel">
 44       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${submitType=="n" || submitType=="N"}]]></conditionExpression>
 45     </sequenceFlow>
 46     <sequenceFlow id="flow9" sourceRef="decideZGapprove" targetRef="submitform">
 47       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ZGapprove=="n" || ZGapprove=="N"}]]></conditionExpression>
 48     </sequenceFlow>
 49     <sequenceFlow id="flow10" sourceRef="decideZJLapprove" targetRef="submitform">
 50       <conditionExpression xsi:type="tFormalExpression"><![CDATA[${ZJLapprove=="n" || ZJLapprove=="N"}]]></conditionExpression>
 51     </sequenceFlow>
 52   </process>
 53   <bpmndi:BPMNDiagram id="BPMNDiagram_LeaveProcess">
 54     <bpmndi:BPMNPlane bpmnElement="LeaveProcess" id="BPMNPlane_LeaveProcess">
 55       <bpmndi:BPMNShape bpmnElement="startevent" id="BPMNShape_startevent">
 56         <omgdc:Bounds height="35.0" width="35.0" x="65.0" y="279.0"></omgdc:Bounds>
 57       </bpmndi:BPMNShape>
 58       <bpmndi:BPMNShape bpmnElement="submitform" id="BPMNShape_submitform">
 59         <omgdc:Bounds height="55.0" width="105.0" x="145.0" y="269.0"></omgdc:Bounds>
 60       </bpmndi:BPMNShape>
 61       <bpmndi:BPMNShape bpmnElement="decideSubmit" id="BPMNShape_decideSubmit">
 62         <omgdc:Bounds height="40.0" width="40.0" x="295.0" y="277.0"></omgdc:Bounds>
 63       </bpmndi:BPMNShape>
 64       <bpmndi:BPMNShape bpmnElement="ZG_approve" id="BPMNShape_ZG_approve">
 65         <omgdc:Bounds height="55.0" width="105.0" x="380.0" y="270.0"></omgdc:Bounds>
 66       </bpmndi:BPMNShape>
 67       <bpmndi:BPMNShape bpmnElement="decideZGapprove" id="BPMNShape_decideZGapprove">
 68         <omgdc:Bounds height="40.0" width="40.0" x="530.0" y="278.0"></omgdc:Bounds>
 69       </bpmndi:BPMNShape>
 70       <bpmndi:BPMNShape bpmnElement="ZJL_approve" id="BPMNShape_ZJL_approve">
 71         <omgdc:Bounds height="55.0" width="105.0" x="615.0" y="271.0"></omgdc:Bounds>
 72       </bpmndi:BPMNShape>
 73       <bpmndi:BPMNShape bpmnElement="decideZJLapprove" id="BPMNShape_decideZJLapprove">
 74         <omgdc:Bounds height="40.0" width="40.0" x="765.0" y="279.0"></omgdc:Bounds>
 75       </bpmndi:BPMNShape>
 76       <bpmndi:BPMNShape bpmnElement="endevent" id="BPMNShape_endevent">
 77         <omgdc:Bounds height="35.0" width="35.0" x="850.0" y="282.0"></omgdc:Bounds>
 78       </bpmndi:BPMNShape>
 79       <bpmndi:BPMNShape bpmnElement="endeventCancel" id="BPMNShape_endeventCancel">
 80         <omgdc:Bounds height="35.0" width="35.0" x="395.0" y="329.0"></omgdc:Bounds>
 81       </bpmndi:BPMNShape>
 82       <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
 83         <omgdi:waypoint x="100.0" y="296.0"></omgdi:waypoint>
 84         <omgdi:waypoint x="145.0" y="296.0"></omgdi:waypoint>
 85       </bpmndi:BPMNEdge>
 86       <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
 87         <omgdi:waypoint x="250.0" y="296.0"></omgdi:waypoint>
 88         <omgdi:waypoint x="295.0" y="297.0"></omgdi:waypoint>
 89       </bpmndi:BPMNEdge>
 90       <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
 91         <omgdi:waypoint x="335.0" y="297.0"></omgdi:waypoint>
 92         <omgdi:waypoint x="380.0" y="297.0"></omgdi:waypoint>
 93       </bpmndi:BPMNEdge>
 94       <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
 95         <omgdi:waypoint x="485.0" y="297.0"></omgdi:waypoint>
 96         <omgdi:waypoint x="530.0" y="298.0"></omgdi:waypoint>
 97       </bpmndi:BPMNEdge>
 98       <bpmndi:BPMNEdge bpmnElement="flow5" id="BPMNEdge_flow5">
 99         <omgdi:waypoint x="570.0" y="298.0"></omgdi:waypoint>
100         <omgdi:waypoint x="615.0" y="298.0"></omgdi:waypoint>
101       </bpmndi:BPMNEdge>
102       <bpmndi:BPMNEdge bpmnElement="flow6" id="BPMNEdge_flow6">
103         <omgdi:waypoint x="720.0" y="298.0"></omgdi:waypoint>
104         <omgdi:waypoint x="765.0" y="299.0"></omgdi:waypoint>
105       </bpmndi:BPMNEdge>
106       <bpmndi:BPMNEdge bpmnElement="flow7" id="BPMNEdge_flow7">
107         <omgdi:waypoint x="805.0" y="299.0"></omgdi:waypoint>
108         <omgdi:waypoint x="850.0" y="299.0"></omgdi:waypoint>
109       </bpmndi:BPMNEdge>
110       <bpmndi:BPMNEdge bpmnElement="flow8" id="BPMNEdge_flow8">
111         <omgdi:waypoint x="315.0" y="317.0"></omgdi:waypoint>
112         <omgdi:waypoint x="315.0" y="346.0"></omgdi:waypoint>
113         <omgdi:waypoint x="395.0" y="346.0"></omgdi:waypoint>
114       </bpmndi:BPMNEdge>
115       <bpmndi:BPMNEdge bpmnElement="flow9" id="BPMNEdge_flow9">
116         <omgdi:waypoint x="550.0" y="318.0"></omgdi:waypoint>
117         <omgdi:waypoint x="549.0" y="382.0"></omgdi:waypoint>
118         <omgdi:waypoint x="397.0" y="382.0"></omgdi:waypoint>
119         <omgdi:waypoint x="197.0" y="382.0"></omgdi:waypoint>
120         <omgdi:waypoint x="197.0" y="324.0"></omgdi:waypoint>
121       </bpmndi:BPMNEdge>
122       <bpmndi:BPMNEdge bpmnElement="flow10" id="BPMNEdge_flow10">
123         <omgdi:waypoint x="785.0" y="279.0"></omgdi:waypoint>
124         <omgdi:waypoint x="784.0" y="222.0"></omgdi:waypoint>
125         <omgdi:waypoint x="505.0" y="222.0"></omgdi:waypoint>
126         <omgdi:waypoint x="197.0" y="222.0"></omgdi:waypoint>
127         <omgdi:waypoint x="197.0" y="269.0"></omgdi:waypoint>
128       </bpmndi:BPMNEdge>
129     </bpmndi:BPMNPlane>
130   </bpmndi:BPMNDiagram>
131 </definitions>

新建springboot工程

引入依赖

 <dependencies>

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

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.11</version>
            <scope>test</scope>
        </dependency>
 
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.1.11</version>
        </dependency>
 
        <dependency>
            <groupId>com.google.guava</groupId>
            <artifactId>guava</artifactId>
            <version>23.0</version>
        </dependency>
 
        <!-- h2内存级数据库 -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.3.176</version>
        </dependency>
    </dependencies>

简化logback输出,logback.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <configuration>
 3     <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
 4     <property name="LOG_HOME" value="/home/tomcatlog/logs/agent" />
 5     <property name="plain" value="%msg%n" />
 6 
 7     <!-- 控制台输出 -->
 8     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
 9         <encoder>
10             <pattern>${plain}</pattern>
11         </encoder>
12     </appender>
13 
14     <!-- 按照每天生成日志文件 -->
15     <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
16         <file>${LOG_HOME}/agent.log</file>
17         <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
18             <!--日志文件输出的文件名 -->
19             <fileNamePattern>${LOG_HOME}/agent.%d{yyyy-MM-dd}.log
20             </fileNamePattern>
21             <!--日志文件保留天数 -->
22             <maxHistory>30</maxHistory>
23         </rollingPolicy>
24         <encoder>
25             <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符 -->
26             <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{80} - %msg%n
27             </pattern>
28         </encoder>
29     </appender>
30 
31     <logger name="jdbc.sqlonly" level="OFF" />
32     <logger name="jdbc.resultsettable" level="OFF" />
33     <logger name="jdbc.sqltiming" level="erroe" />
34     <logger name="jdbc.audit" level="error" />
35     <logger name="jdbc.connection" level="error" />
36     <logger name="jdbc.resultset" level="error" />
37     <logger name="root">
38         <level value="ERROR"/>
39     </logger>
40     <logger name="com.imooc">
41         <level value="DEBUG"/>
42     </logger>
43 
44     <!-- 日志输出级别 -->
45     <root level="info"><!-- ERROR、WARN、INFO、DEBUG -->
46         <appender-ref ref="STDOUT" />
47         <appender-ref ref="FILE" />
48     </root>
49 </configuration>

resources引入second_approve.bpmn20.xml文件

新建启动类Main.class

创建流程引擎

部署流程定义文件

启动运行流程

处理流程任务

按照以上四步构建引动类,为了简化启动类,建议对每个方法进行重构,CTRL+ALT+M快捷键

  1 package com.imooc.activiti.helloword;
  2 
  3 
  4 import com.google.common.collect.Maps;
  5 import org.activiti.engine.*;
  6 import org.activiti.engine.form.FormProperty;
  7 import org.activiti.engine.form.TaskFormData;
  8 import org.activiti.engine.impl.form.DateFormType;
  9 import org.activiti.engine.impl.form.StringFormType;
 10 import org.activiti.engine.repository.Deployment;
 11 import org.activiti.engine.repository.DeploymentBuilder;
 12 import org.activiti.engine.repository.ProcessDefinition;
 13 import org.activiti.engine.runtime.ProcessInstance;
 14 import org.activiti.engine.task.Task;
 15 import org.slf4j.Logger;
 16 import org.slf4j.LoggerFactory;
 17 
 18 import java.text.ParseException;
 19 import java.text.SimpleDateFormat;
 20 import java.util.Date;
 21 import java.util.List;
 22 import java.util.Map;
 23 import java.util.Scanner;
 24 
 25 public class Main {
 26 
 27     private static final Logger LOGGER = LoggerFactory.getLogger(Main.class);
 28 
 29     public static void main(String[] args) throws ParseException {
 30         LOGGER.info("启动程序");
 31         //创建流程引擎
 32         ProcessEngine processEngine = getProcessEngine();
 33 
 34         //部署流程定义文件
 35         ProcessDefinition processDefinition = getProcessDefinition(processEngine);
 36 
 37         //启动运行流程
 38         ProcessInstance processInstance =getProcessInstance(processEngine, processDefinition);
 39 
 40         //处理流程任务
 41         Scanner scanner = new Scanner(System.in);
 42         while (processInstance != null && !processInstance.isEnded()) {   //判断流程不为空,且流程没有结束
 43             TaskService taskService = processEngine.getTaskService();
 44             List<Task> list = taskService.createTaskQuery().list();    //列出当前需要处理的任务
 45             LOGGER.info("待处理任务数量 [{}]", list.size());
 46             for (Task task : list) {
 47 
 48                 LOGGER.info("待处理任务 [{}]", task.getName());
 49                 Map<String, Object> variables = getStringObjectMap(processEngine, scanner, task);
 50                 taskService.complete(task.getId(),variables);
 51                 processInstance = processEngine.getRuntimeService().createProcessInstanceQuery()
 52                         .processInstanceId(processInstance.getId()).singleResult();
 53             }
 54         }
 55         scanner.close();
 56         LOGGER.info("结束程序");
 57 
 58     }
 59     //获取变量
 60     private static Map<String, Object> getStringObjectMap(ProcessEngine processEngine, Scanner scanner, Task task) throws ParseException {
 61         FormService formService = processEngine.getFormService();    //通过formService来获取form表单输入
 62         TaskFormData taskFormData = formService.getTaskFormData (task.getId());
 63         List<FormProperty> formProperties = taskFormData.getFormProperties();    //获取taskFormData的表单内容
 64         Map<String,Object> variables = Maps.newHashMap();    //这个Map键值对来存对应表单用户输入的内容
 65         for (FormProperty property : formProperties){   //property为表单中的内容
 66             String line = null;    //这里获取输入的信息
 67             if(StringFormType.class.isInstance(property.getType())){   //如果是String类型的话
 68                 LOGGER.info("请输入 [{}] ?" , property.getName());    //输入form表单的某一项内容
 69                 line = scanner.nextLine();
 70                 variables.put(property.getId(),line);
 71             }else if(DateFormType.class.isInstance(property.getType())){   //如果是日期类型的话
 72                 LOGGER.info("请输入 [{}] ? 格式为(yyyy-MM-dd)" , property.getName());    //输入form表单的某一项内容
 73                 line = scanner.nextLine();
 74                 SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");   //设置输入的日期格式
 75                 Date date = dateFormat.parse(line);
 76                 variables.put(property.getId(),date);
 77             }else{
 78                 LOGGER.info("类型不支持 [{}]",property.getType());
 79             }
 80             LOGGER.info("您输入的内容是 [{}] " , line);
 81         }
 82         return variables;
 83     }
 84 
 85     private static ProcessInstance getProcessInstance(ProcessEngine processEngine, ProcessDefinition processDefinition) {
 86         RuntimeService runtimeService = processEngine.getRuntimeService();
 87         ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId());
 88         LOGGER.info("启动流程{}",processInstance.getProcessDefinitionKey());
 89         return processInstance;
 90     }
 91 
 92     private static ProcessDefinition getProcessDefinition(ProcessEngine processEngine) {
 93         RepositoryService repositoryService = processEngine.getRepositoryService();
 94         DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
 95         deploymentBuilder.addClasspathResource("second_approve.bpmn20.xml");
 96         Deployment deploy = deploymentBuilder.deploy();
 97         String id = deploy.getId();
 98         ProcessDefinition processDefinition = repositoryService
 99                 .createProcessDefinitionQuery()
100                 .deploymentId(id)
101                 .singleResult();
102         LOGGER.info("流程定义对象{},流程定义id {}",processDefinition.getName(),processDefinition.getId());
103         return processDefinition;
104     }
105 
106     private static ProcessEngine getProcessEngine() {
107         ProcessEngineConfiguration cfg = ProcessEngineConfiguration.createStandaloneInMemProcessEngineConfiguration();
108         ProcessEngine processEngine = cfg.buildProcessEngine();
109         String name = processEngine.getName();
110         String version = ProcessEngine.VERSION;
111         LOGGER.info("流程引擎名称{},版本{}",name,version);
112         return processEngine;
113     }
114 
115 
116 }

 

使用springboot打包

更新pom.xml

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.0.RELEASE</version>
        <relativePath/>
    </parent>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>   <!-- 基于plugin启动这个程序 -->
            </plugin>
        </plugins>
    </build>

在<dependencies></dependencies>中添加spring-boot的依赖

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

进入这个项目目录,然后输入  mvn package  ,就可以将项目打包:mvn package

target目录中,可以看到两个jar包:

直接使用以下指令来执行我们编译好的二级审批流程文件

java-jar xxxxxx.jar

 

 

将二级审批流程创建archetype脚手架

打开源码目录 Activiti-6.x\tooling\archetypes\activiti-archetype-unittest

安装脚手架 mvn clean install

copy activiti-archetype-unittest2

修改pom.xml中的 artifactId

创建main/java与main/resources两个目录

修改Main.java中的package,后面路径改为 ${package}; package ${package}

修改 META-INF/maven/archetype-metadata.xml

 1  <?xml version="1.0" encoding="UTF-8"?>
 2   <archetype-descriptor name="activiti-archetype-unittest2">
 3     <fileSets>
 4       <fileSet filtered="true" packaged="true">   <!-- filtered是否过滤,packaged:是否经过包结构过滤 -->
 5         <directory>src/main/java</directory>
 6         <includes>
 7           <include>**/*.java</include>
 8        </includes>
 9       </fileSet>
10      <fileSet filtered="false" packaged="false">
11        <directory>src/main/resources</directory>   <!-- 资源目录下面的三个文件 -->
12        <includes>
13          <include>activiti.cfg.xml</include>
14          <include>LeaveProcess.bpmn20.xml</include>
15         <include>logback.xml</include>
16       </includes>
17    </fileSet>
18    <fileSet filtered="true" packaged="true">
19        <directory>src/test/java</directory>
20       <includes>
21         <include>**/*.java</include>
22        </includes>
23      </fileSet>
24      <fileSet filtered="true" packaged="true">
25        <directory>src/test/resources</directory>
26        <includes>
27         <include>second_approve.bpmn20.xml</include>
28       </includes>
29      </fileSet>
30  
31   </fileSets>
32  </archetype-descriptor>

进入activiti-archetype-unittest2的路径下,执行 mvn clean install

在本地的maven仓库中已经创建好的脚手架

Create from archetype后Add Archetype

GroupId org.activiti

ArtifactId activiti-archetype-unittest2

Version 6.0.0

即可继续创建工程

 

 

 

posted @ 2019-07-05 09:57  曲阳阳  阅读(238)  评论(0编辑  收藏  举报