「Activiti精品 悟纤出品」开发一个简单的SpringBoot activiti应用 - 第330篇
一、开发说明
1.1 开发环境说明
(1)OS:Mac OS;
(2)IDEA : IntellijIDEA;
(3)MySQL:8.0.12;
(4)Spring Boot : 2.3.3.RELEASE;
(5)Activiti:activiit7的7.1.0.M6 starter;
(6)bpmn:idea的插件actiBPM;
1.2 开发说明
在接下来我们要使用activiti7开发一个请假流程:
员工发起申请请假申请->填写请假表单(请假时间、请假原因)->部门领导审批意见->请假流程结束。
根据activiti的这个任务流程,那么有几个核心的事件:
·我要请假 、·填写请假单 、·领导审批
在接下来我们会按照之前在《「工作流Activiti」流程模型搭建-小试牛刀》的流程构建来说明从代码层面应该去进行使用activiti7。
问:对于前面的章节,看懂了,但是没有搭建流程模型环境,影响本节学习嘛?
答:不影响,对于activiti相关的知识点,如果以前就学习过,只是不清楚在Spring Boot中不知道如何使用,那么直接看本节就可以了。
1.3 集成方式说明
Spring Boot整合activiti的方案主要是两种方式:
(1)不使用starter整合(不推荐):使用activiti-spring的依赖进行使用,那么就需要有一个ActivitiConfig的配置类进行注入activiti相关的,比如数据源、流程引擎工厂类ProcessEngineFactoryBean,还有我么上面提到的Service,TaskService、RuntimeService。结论:这种方式比较不复杂,不推荐。
(2)使用starter(推荐):使用activiti-spring-boot-starter,无需自己在进行activiti的相关配置,可以直接进行开发流程相关的。结论:入门简单,推荐。
本文主要是使用第二种方式进行展开讲解。
二、开发实战
2.1 创建项目
我们使用SpringBoot的start快速构建一个项目,取名为:spring-boot-activiti7-demo。
那么这时候@SpringBootApplication的启动类就自动生成了,无需自己进行创建。
2.2 流程图构建
要开发一个请假流程,那么就需要构建一个流程图,我们使用actiBPM进行创建,
在/resources新建一个目录processes新建一个leave-process.bpmn,也就是:
/resources/processes/leave-process.bpmn
2.2.1 使用BPMN元素创建一个请假流程图
使用BPMN的元素进行创建一个请假流程图,结果如下:
2.2.2 为元素创建ID属性
相信使用bpmn的元素构建上面的流程图,并不是难事,那么创建完成之后,我们之后需要通过代码进行操作这个流程图的元素,那么怎么操作呢,肯定是通过元素的唯一标识嘛,所以我们设置一下id属性。
【StartEvent】节点:id=startEvent、name=开始事件
【EndEvent】节点:id=endEvent、name=结束事件
【员工申请】节点:id=applyTask、name=员工申请
【部门领导审批】节点:id=deptApproveTask、name=部门领导审批
举个栗子员工申请节点:
其实上面这些好像在代码中并不一定能使用到,不设置好像也无所谓啦,但是name的还是设置下吧,方便进行流程图的查看。
但是有一个地方的id的设置非常重要,试问一下,你怎么获取到这个流程图呐,流程图的id吧,所以这个得设置一下,点击流程图空白的地方就可以进行设置流程图的id属性了:
【process】:id=leaveProcess、name=请假流程
2.2.3 分配任务人:动态分配
还记得我们在使用activiti的时候,有一个很重要的地方,就是谁发起、谁审批了,也就是Assignee这个属性的配置,在实际项目中我们不会使用activiti的用户体系,我们有自己的用户体系,那么我们就需要能够在代码层面进行动态的设置这个属性了,我们使用EL表达式进行标识出来即可:
【员工申请】节点:assignee=${jobNumber}
【部门领导审批】节点:assignee=${deptJobNumber}
注意:这两个参数不能设置为一样的,否则就无法进行动态的设置分配人了。
举例说明员工申请节点示例如下:
其它注意的地方:对于Assignee这个字段,如果设置好了之后,对于actiBPM这个插件,如果重启了Idea,Assignee这个属性不能够进行回显,但是在xml文件是有这个值的,好像是actiBPM的bug,这个插件好像之后就没有在更新过了,截止到2020.08.29更新下来的就是有这样的问题。
2.2.4 表单说明
对于表单部分,这里我们无需进行构建表单,我们之后会通过代码动态的进行设置表单参数,这里暂时也不用进行创建表单。
2.2.5 bpmn文件
根据上面的配置之后,具体的bpmn文件如下:
- <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
- <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" 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" xmlns:tns="http://www.activiti.org/test" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1598520463370" name="" targetNamespace="http://www.activiti.org/test" typeLanguage="http://www.w3.org/2001/XMLSchema">
- <process id="leaveProcess" isClosed="false" isExecutable="true" name="请假流程" processType="None">
- <startEvent id="startEvent" name="开始事件"/>
- <userTask activiti:assignee="${jobNumber}" activiti:exclusive="true" id="applyTask" name="员工申请"/>
- <userTask activiti:assignee="${deptJobNumber}" activiti:exclusive="true" id="deptApproveTask" name="部门领导审批"/>
- <endEvent id="endEvent" name="结束事件"/>
- <sequenceFlow id="_5" sourceRef="deptApproveTask" targetRef="endEvent"/>
- <sequenceFlow id="_11" sourceRef="startEvent" targetRef="applyTask"/>
- <sequenceFlow id="_2" sourceRef="applyTask" targetRef="deptApproveTask"/>
- </process>
- <bpmndi:BPMNDiagram documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0" id="Diagram-_1" name="New Diagram">
- <bpmndi:BPMNPlane bpmnElement="leaveProcess">
- <bpmndi:BPMNShape bpmnElement="startEvent" id="Shape-startEvent">
- <omgdc:Bounds height="32.0" width="32.0" x="70.0" y="230.0"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="applyTask" id="Shape-applyTask">
- <omgdc:Bounds height="55.0" width="85.0" x="165.0" y="220.0"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="deptApproveTask" id="Shape-deptApproveTask">
- <omgdc:Bounds height="55.0" width="85.0" x="350.0" y="220.0"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNShape bpmnElement="endEvent" id="Shape-endEvent">
- <omgdc:Bounds height="32.0" width="32.0" x="495.0" y="230.0"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNShape>
- <bpmndi:BPMNEdge bpmnElement="_2" id="BPMNEdge__2" sourceElement="applyTask" targetElement="deptApproveTask">
- <omgdi:waypoint x="250.0" y="247.5"/>
- <omgdi:waypoint x="350.0" y="247.5"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge bpmnElement="_5" id="BPMNEdge__5" sourceElement="deptApproveTask" targetElement="endEvent">
- <omgdi:waypoint x="435.0" y="247.5"/>
- <omgdi:waypoint x="495.0" y="246.0"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNEdge>
- <bpmndi:BPMNEdge bpmnElement="_11" id="BPMNEdge__11" sourceElement="startEvent" targetElement="applyTask">
- <omgdi:waypoint x="102.0" y="246.0"/>
- <omgdi:waypoint x="165.0" y="247.5"/>
- <bpmndi:BPMNLabel>
- <omgdc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/>
- </bpmndi:BPMNLabel>
- </bpmndi:BPMNEdge>
- </bpmndi:BPMNPlane>
- </bpmndi:BPMNDiagram>
- </definitions>
2.3 添加依赖
我们看看使用内存数据库的依赖,主要依赖有:
H2:内存数据库;
activiti7 starter:activiti7的starter,6版本的这个很不一样,可以参考文章《「工作流Activiti」核心类以及如何在SpringBoot集成说明》
spring security:这是activiti底层使用到了userDetail,所以需要引入,不然启动会报错。
具体的pom.xml文件如下:
- <?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.3.3.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.kfit</groupId>
- <artifactId>spring-boot-activiti7-demo</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>spring-boot-activiti7-demo</name>
- <description>Demo project for Spring Boot</description>
-
- <properties>
- <java.version>1.8</java.version>
- </properties>
-
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
-
- <dependency>
- <groupId>org.activiti</groupId>
- <artifactId>activiti-spring-boot-starter</artifactId>
- <version>7.1.0.M6</version>
- </dependency>
-
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.h2database</groupId>
- <artifactId>h2</artifactId>
- </dependency>
-
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- </plugin>
- </plugins>
- </build>
-
- </project>
这里使用了spring security的话,那么每次访问都需要进行登录,特别不方便,可以关闭掉,修改启动类即可:
- @SpringBootApplication(
- exclude = {SecurityAutoConfiguration.class,
- ManagementWebSecurityAutoConfiguration.class}
- )
2.4 启动测试
到这里正常情况下,即可以进行启动了,启动查看控制台,注意一个打印信息:
1)The following process definition files will be deployed: [leave-process.bpmn]
(2)No process extensions were found for auto-deployment in the location 'classpath*:**/processes/'
(3)performing create on engine with resource org/activiti/db/create/activiti.h2.create.engine.sql
performing create on history with resource org/activiti/db/create/activiti.h2.create.history.sql
(4)ProcessEngine default created
(5)Process deployed: {id: leaveProcess:1:5a36f256-e9c9-11ea-8705-463e6370b561, key: leaveProcess, name: 请假流程 }
这里有一个很重要的信息,就是当我们启动应用的时候,会自动的发布我们的流程。也就是说白了我们就不用create app->publish这个步骤了。
2.5 持久化mysql
上面这个内存数据库不能看到内在的东西,实在是不舒服,难免会有点担忧,睡不着觉,那么我们使用mysql数据库来持久化。
2.5.1 修改pom.xml
首先修改pom.xml文件,删除h2的依赖,添加mysql和数据源依赖:
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- </dependency>
-
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.23</version>
- </dependency>
2.5.2 添加配置信息
在application.properties文件添加数据源和activiti的配置信息:
- ### 数据源的配置
- spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
- spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
- spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activiti7_demo?createDatabaseIfNotExist=true&useUnicode=true&characterEncoding=utf-8&useSSL=false&nullCatalogMeansCurrent=true
- spring.datasource.username=root
- spring.datasource.password=root
-
- ### activiti数据库的配置
- #表示启动时检查数据库表,不存在则创建
- spring.activiti.database-schema-update=true
- #表示哪种情况下使用历史表,这里配置为full表示全部记录历史
- spring.activiti.history-level=full
- #为true表示使用历史表,如果不配置,则工程启动后可以检查数据库
- spring.activiti.db-history-used=true
2.5.3 启动测试下
启动成功的话,可以看到数据库中有25张表,具体这些表信息我们在下节进行说明,你只需要有看到表就可以了,另外我们可以验证下我们之前说的:在启动的时候就已经部署了。
SELECT *from ACT_RE_DEPLOYMENT;
说明:ACT_RE_DEPLOYMENT部署信息表,另外可以通过ACT_RE_PROCDEF看到一个流程信息。
截图看下效果吧:
这里可以看出部署表和流程表的关系,当部署表创建之后,会和流程表进行绑定,对应的字段是DEPLOYMENT_ID_
2.5.4 启动报错
如果是报一下错误:
SQLSyntaxErrorException: Table'activiti7_demo.act_ge_property' doesn't exist
在application.properties文件中的配置spring.datasource.url添加参数:&nullCatalogMeansCurrent=true
2.6 开发 – 准备工作
我们新建一个LeaveController用来进行编写整个流程的操作。
- @RestController
- @RequestMapping("/leave")
- public class LeaveController {
-
- //org.activiti.engine.RuntimeService
- @Autowired
- private RuntimeService runtimeService;//流程相关
-
- //org.activiti.engine.TaskService
- @Autowired
- private TaskService taskService;//任务相关
-
- //org.activiti.engine.HistoryService
- @Autowired
- private HistoryService historyService;//历史记录相关
- }
说明:RuntimeService、TaskService、HistoryService都是activiti给我们提供的。
2.7 开发 – A1001提交申请
2.7.1 代码
当我们用户点击【提交申请】的时候,我们需要调用runtimeService.startProcessInstanceByKey()方法来开始一个流程。流程开启成功之后,会创建一个流程实例对象ProcessInstance。对于用户下一步就可以进行填写请假时间和请假原因。
我们在LeaveController创建start()方法,具体代码如下:
- /**
- * 开始流程
- * @param jobNumber
- * @author 悟纤
- * @return
- */
- @RequestMapping(value="/start")
- public String start(String jobNumber) {
- //设置流程的发起者
- Authentication.setAuthenticatedUserId(jobNumber);
-
- // bpmn中定义process的id。
- String instanceKey = "leaveProcess";
- System.out.println("开启请假流程...");
-
- // 设置流程参数,开启流程
- Map<String,Object> variables = new HashMap<String,Object>();
- //设置参数,这里的key就是上面配置的assignee的${jobNumber},会进行赋值。
- variables.put("jobNumber",jobNumber);
-
- //使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动
- // 流程开启成功之后,获取到ProcessInstance信息。
- ProcessInstance instance = runtimeService.startProcessInstanceByKey(instanceKey, variables);
-
- System.out.println("流程实例ID:"+instance.getId());
- System.out.println("流程定义ID:"+instance.getProcessDefinitionId());
-
-
- //验证是否启动成功
- //通过查询正在运行的流程实例来判断
- ProcessInstanceQuery processInstanceQuery = runtimeService.createProcessInstanceQuery();
- //根据流程实例ID来查询
- List<ProcessInstance> runningList = processInstanceQuery.processInstanceId(instance.getProcessInstanceId()).list();
- System.out.println("根据流程ID查询条数:"+runningList.size());
-
- // 返回流程ID
- return instance.getId();
- }
代码上已经注释的很清楚了,这里就不过多说明,这里的发起核心就是调用了startProcessInstanceByKey()方法。另外有一处代码很重要就是:
- //设置流程的发起者
- Authentication.setAuthenticatedUserId(jobNumber);
如果使用的是activiti6的版本使用
- //设置流程的发起者
- identityService.setAuthenticatedUserId(jobNumber);
这一个需要尽心设置,在查询历史记录的时候,会访问ACT_HI_PROCINST这个表和START_USER_ID进行比较,这个值就是上面的这个代码进行设置的。
2.7.2 测试
到这里我们就可以来测试下了,启动我们的应用,访问:
http://127.0.0.1:8080/leave/start?jobNumber=A1001
这里我们假设员工的工号为A1001进行发起了请假申请,访问地址成功的话,返回一个流程实例ID:4518e0a4-e9d7-11ea-9e4c-9ab0362195b5。
2.8 开发 – A1001任务查询
对于员工A1001可以查询到自己代办的任务了,因为他提交了申请,但是还没有填写请假缘由呐,我们先看下A1001的任务:
- /**
- * <p>查看任务</p>
- * @author 悟纤
- */
- @RequestMapping(value="/showTask")
- public List<Map<String, String>> showTask(String jobNumber) {
- /*
- * 获取请求参数
- */
- TaskQuery taskQuery = taskService.createTaskQuery();
-
- List<Task> taskList = null;
- if(jobNumber == null){
- //获取所有人的所有任务.
- taskList = taskQuery.list();
- }else{
- //获取分配人的任务.
- taskList = taskQuery.taskAssignee(jobNumber).list();
- }
-
- if(taskList == null || taskList.size() == 0) {
- System.out.println("查询任务列表为空!");
- return null;
- }
-
-
- /*
- * 查询所有任务,并封装
- */
- List<Map<String, String>> resultList = new ArrayList<>();
- for(Task task : taskList) {
- Map<String, String> map = new HashMap<>();
- map.put("taskId", task.getId());
- map.put("name", task.getName());
- map.put("createTime", task.getCreateTime().toString());
- map.put("assignee", task.getAssignee());
- map.put("instanceId", task.getProcessInstanceId());
- map.put("executionId", task.getExecutionId());
- map.put("definitionId", task.getProcessDefinitionId());
- resultList.add(map);
- }
-
-
- /*
- * 返回结果
- */
- return resultList;
- }
测试访问地址:
http://127.0.0.1:8080/leave/showTask?jobNumber=A1001
这里会返回一个很核心的参数taskId:
- [
- {
- executionId: "45197ce7-e9d7-11ea-9e4c-9ab0362195b5",
- instanceId: "4518e0a4-e9d7-11ea-9e4c-9ab0362195b5",
- createTime: "Sat Aug 29 17:08:57 CST 2020",
- name: "员工申请",
- assignee: "A1001",
- taskId: "451c14fa-e9d7-11ea-9e4c-9ab0362195b5",
- definitionId: "leaveProcess:1:43f2ff73-e9cc-11ea-935c-463e6370b561"
- }
- ]
说明任务当前到A1001上,任务taskId在进行表单的操作需要用到,请牢记。
2.9 开发 – A1001员工提交申请
这时候员工在前端进行表单的填写,填写完成之后,需要进行任务的完成,那么就需要调用后端服务,使用taskService.complete()进行任务的完成,任务完成会传递到下一个节点:
- /**
- * 员工提交申请
- * @author 悟纤
- * @return String 申请受理结果
- */
- @RequestMapping(value="/employeeApply")
- public String employeeApply(HttpServletRequest request){
- System.out.println("--> 提交申请单信息");
- /*
- * 获取请求参数
- */
- String taskId = request.getParameter("taskId"); // 任务ID
- //String jobNumber = request.getParameter("jobNumber"); // 工号
- String deptJobNumber = request.getParameter("deptJobNumber"); //上级
- String leaveDays = request.getParameter("leaveDays"); // 请假天数
- String leaveReason = request.getParameter("leaveReason"); // 请假原因
-
-
- /*
- * 查询任务
- */
- Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
- if(task == null) {
- System.out.println("任务ID:"+taskId+"查询到任务为空!");
- return "fail";
- }
-
-
- /*
- * 参数传递并提交申请
- */
- Map<String, Object> variables = new HashMap<String, Object>();
- variables.put("days", leaveDays);
- variables.put("date", new Date());
- variables.put("reason", leaveReason);
- variables.put("deptJobNumber", deptJobNumber);
- taskService.complete(task.getId(), variables);
- System.out.println("执行【员工申请】环节,流程推动到【部门审核】环节");
-
- /*
- * 返回成功
- */
- return "success";
- }
这里有一个参数很重要,在这里特别说明下,就是任务的下一个节点:deptJobNumber的分配人,这里我们使用前端进行传递的方式,等同于前端有一个地方可以进行勾选人员进行处理,那么在实际项目中,这个参数可以后端调用一个该员工的部门经理的工号进行设置即可。
访问测试下:
http://127.0.0.1:8080/leave/employeeApply?taskId=451c14fa-e9d7-11ea-9e4c-9ab0362195b5&deptJobNumber=A1002&leaveDays=2&leaveReason=家里有事
这里的taskId就是上面查询出来的taskId。
2.10 开发 – A1002任务查询
这时候任务由A1001流转到A1002了,进行任务查询下:
http://127.0.0.1:8080/leave/showTask?jobNumber=A1002
返回的数据如下:
-
- [
- {
- executionId: "45197ce7-e9d7-11ea-9e4c-9ab0362195b5",
- instanceId: "4518e0a4-e9d7-11ea-9e4c-9ab0362195b5",
- createTime: "Sat Aug 29 18:09:53 CST 2020",
- name: "部门领导审批",
- assignee: "A1002",
- taskId: "c843d9a9-e9df-11ea-94ed-72df69b1f835",
- definitionId: "leaveProcess:1:43f2ff73-e9cc-11ea-935c-463e6370b561"
- }
- ]
注意taskId和上面是不一样的,说明activiti对于任务的流转是删除原先的,创建一个新的任务节点,而不是使用update原先的任务。
2.11 开发 – A1002审批操作
到这里就是A1002进行审批操作,审批是同意还是拒绝。
- /**
- * <p>部门经理审核</p>
- * @return String 受理结果
- * @author 悟纤
- */
- @ResponseBody
- @RequestMapping(value="/deptManagerAudit")
- public String deptManagerAudit(HttpServletRequest request) {
- /*
- * 获取请求参数
- */
- //任务id
- String taskId = request.getParameter("taskId");
- //审批意见
- String auditOpinion = request.getParameter("auditOpinion");
- //审批结果:同意1;不同意0
- String audit = request.getParameter("audit");
-
- if(StringUtils.isBlank(taskId)) return "fail";
-
-
-
- /*
- * 查找任务
- */
- Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
- if(task == null) {
- System.out.println("审核任务ID:"+taskId+"查询到任务为空!");
- return "fail";
- }
-
-
- /*
- * 设置局部变量参数,完成任务
- */
- Map<String, Object> map = new HashMap<String, Object>();
- map.put("audit", audit);
- map.put("auditOpinion", auditOpinion);
- taskService.complete(taskId, map);
-
- return "success";
- }
访问测试下:
http://127.0.0.1:8080/leave/deptManagerAudit?taskId=c843d9a9-e9df-11ea-94ed-72df69b1f835&audit=1&auditOpinion=同意
至此整个流程完毕。
2.12 开发 – A1001查看请假记录
由于已完成的请假在数据库runtime表中查不到(runtime表只保存正在进行的流程示例信息),所以需要在history表中查询。
- @RequestMapping("/historyList")
- public List<Map<String,Object>> historyList(String jobNumber){
-
- List<HistoricProcessInstance> historicProcessInstances =historyService // 历史任务Service
- .createHistoricProcessInstanceQuery() // 创建历史活动实例查询
- .processDefinitionKey("leaveProcess")//processDefinitionKey
- .finished().startedBy(jobNumber)
- .orderByProcessInstanceEndTime().desc()
- .list();
-
- List<Map<String,Object>> list = new ArrayList<>();
- for(HistoricProcessInstance hpi:historicProcessInstances){
-
- Map<String, Object> map = new HashMap<>();
- map.put("startUserId", hpi.getStartUserId());
- map.put("startTime", hpi.getStartTime());
- map.put("endTime", hpi.getEndTime());
- list.add(map);
-
- //查询审批结果:
- Map<String, Object> variableMap = new HashMap<>();
- List<HistoricVariableInstance> varInstanceList = historyService.createHistoricVariableInstanceQuery().processInstanceId(hpi.getId()).list();
- for(HistoricVariableInstance hvi:varInstanceList){
- variableMap.put(hvi.getVariableName(),hvi.getValue());
- }
- map.put("variables", variableMap);
- list.add(map);
- }
- return list;
- }
访问如下地址进行测试下:
http://127.0.0.1:8080/leave/historyList?jobNumber=A1001
请求结果:
- [
- {
- startUserId: "A1001",
- variables: {
- date: "2020-08-30T09:22:52.019+00:00",
- reason: "家里有事",
- auditOpinion: "同意",
- deptJobNumber: "A1002",
- audit: "1",
- days: "2",
- jobNumber: "A1001",
- },
- startTime: "2020-08-30T09:22:27.076+00:00",
- endTime: "2020-08-30T09:23:10.892+00:00"
- }
- ]
悟纤小结
师傅:今天这个代码量有点大,大脑都快接收不了了吧。
悟纤:可不,搞的脑瓜都疼了。
师傅:第一次研究的时候,也是很头大,很难、很难,还有很多坑,都跳的爬不起来了。
悟纤:师傅也辛苦了,剩下的就交给我了吧。
(1)核心步骤:
① 创建一个bpmn文件;
② 引人activiti的依赖;
③ 调用activiti提供的api进行流程的相关操作。
购买完整视频,请前往:http://www.mark-to-win.com/TeacherV2.html?id=287