一、导入依赖
flowable依赖:
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.2</version>
</dependency>
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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>flowable_study</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
</parent>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.7.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
</dependency>
</dependencies>
</project>
注意:以上为整个项目的pom.xml文件,根据自己实际情况修改,如果只想在现有环境加入Flowable,那么直接引入最上方的Flowable依赖即可
二、数据库配置
Flowable需要连接数据库,并会在项目启动的时候新建表。因此我们在application.yml中配置:
spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
username: root
password: 199692
url: jdbc:mysql://127.0.0.1:3306/flowable?serverTimezone=Asia/Shanghai&useSSL=false
配置成功后,我们启动项目时,会自动给我们建表,如图:
三、下载插件 Flowable BPMN visualizer
如果IDE选择的是IDEA的话,可以下载插件 Flowable BPMN visualizer。
快捷键 Ctrl + Alt + S 打开设置,找到 Plugins,选择 Marketplace,输入 Flowable BPMN visualizer,最后点击安装。
安装完成后点击 Apply 应用,最后点击 OK 关闭窗口。
四、绘图
我们在项目的resources目录下,新建文件,能看到多了一个 New Flowable BPMN 2.0 file 选项,我们选择它,新建一个请假流程的文件,文件名为:ask_for_leave,可根据自己业务命名。
新建过后,我们右击文件,选择 View BPMN (Flowable) Diagram :
打开可视化界面,开始画流程图。
右击空白处可以新建各种各样的事件和流程。
如图为一个简单的请假流程示意图:
画图的时候,我们需要在下方更改它的一些属性,如:ID、Name等,便于我们后面代码见名知意。
画好后,我们可以看到会自动给我们生成文件内容:
<?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:flowable="http://flowable.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.flowable.org/processdef">
<process id="ask_for_leave" name="ask_for_leave" isExecutable="true">
<startEvent id="start_leave" name="开始请假"/>
<userTask id="employee" name="员工" flowable:assignee="#{employee}"/>
<sequenceFlow id="flow_start" sourceRef="start_leave" targetRef="employee"/>
<userTask id="leader" name="组长" flowable:assignee="#{leader}"/>
<sequenceFlow id="leave" sourceRef="employee" targetRef="leader" name="请假"/>
<exclusiveGateway id="leader_judge"/>
<sequenceFlow id="leader_audit" sourceRef="leader" targetRef="leader_judge" name="组长审批"/>
<serviceTask id="send_message" flowable:exclusive="true" name="发送请假失败消息" flowable:class="src.com.dxc.service.AskForLeaveFail"/>
<sequenceFlow id="leader_reject" sourceRef="leader_judge" targetRef="send_message" name="驳回">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='驳回'}]]></conditionExpression>
</sequenceFlow>
<userTask id="manager" name="总经理" flowable:assignee="#{manager}"/>
<sequenceFlow id="leader_agree" sourceRef="leader_judge" targetRef="manager" name="同意">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='同意'}]]></conditionExpression>
</sequenceFlow>
<endEvent id="请假失败" name="leave_fail"/>
<sequenceFlow id="flow_fail_end" sourceRef="send_message" targetRef="请假失败"/>
<exclusiveGateway id="manager_judge"/>
<sequenceFlow id="manager_audit" sourceRef="manager" targetRef="manager_judge" name="经理审批"/>
<sequenceFlow id="manager_rejet" sourceRef="manager_judge" targetRef="send_message" name="驳回">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='驳回'}]]></conditionExpression>
</sequenceFlow>
<endEvent id="请假成功" name="leave_success"/>
<sequenceFlow id="manager_agree" sourceRef="manager_judge" targetRef="请假成功" name="同意">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${checkResult=='同意'}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_ask_for_leave">
<bpmndi:BPMNPlane bpmnElement="ask_for_leave" id="BPMNPlane_ask_for_leave">
<bpmndi:BPMNShape id="shape-ad5ec363-de3b-4ede-883e-629cbe497515" bpmnElement="start_leave">
<omgdc:Bounds x="-555.0" y="-580.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="shape-0d5a8676-83b3-46ea-a710-b73fb38a6ded" bpmnElement="employee">
<omgdc:Bounds x="-452.44943" y="-605.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-bf2b83dc-ad4f-4ffa-ba9d-82d8128c2dde" bpmnElement="flow_start">
<omgdi:waypoint x="-525.0" y="-565.0"/>
<omgdi:waypoint x="-485.0497" y="-565.0"/>
<omgdi:waypoint x="-452.44943" y="-565.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-d00296f1-1a06-4052-bd3c-d373c1f9ad74" bpmnElement="leader">
<omgdc:Bounds x="-260.0" y="-605.00006" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-6a821f76-9583-438b-810e-5a8b48466ebb" bpmnElement="leave">
<omgdi:waypoint x="-352.44943" y="-565.0"/>
<omgdi:waypoint x="-260.0" y="-565.00006"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-57050807-ffe2-4a4d-a60b-eb224575ef4b" bpmnElement="leader_judge">
<omgdc:Bounds x="-75.0" y="-585.0001" width="40.0" height="40.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-795a0427-2f83-4607-a40d-4b359790275e" bpmnElement="leader_audit">
<omgdi:waypoint x="-160.0" y="-565.00006"/>
<omgdi:waypoint x="-75.0" y="-565.0001"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-35bcb335-0516-4c89-9148-ead6c956472d" bpmnElement="send_message">
<omgdc:Bounds x="-105.0" y="-465.0" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-c6b5f535-d7f2-4816-8d3a-e8499ad0c923" bpmnElement="leader_reject">
<omgdi:waypoint x="-55.0" y="-545.0001"/>
<omgdi:waypoint x="-55.0" y="-465.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-79a775c0-5c7a-4adf-b544-9954eedb08f6" bpmnElement="manager">
<omgdc:Bounds x="50.0" y="-605.0001" width="100.0" height="80.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-57cd436f-f129-4044-b65c-637cf63465a6" bpmnElement="leader_agree">
<omgdi:waypoint x="-35.0" y="-565.0001"/>
<omgdi:waypoint x="50.0" y="-565.0001"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-37759eb0-7cf1-4da0-8aba-39c8443675ac" bpmnElement="请假失败">
<omgdc:Bounds x="-240.0" y="-440.0" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-3acbccbb-9a56-4ff0-86b1-f2f6641f125c" bpmnElement="flow_fail_end">
<omgdi:waypoint x="-105.0" y="-425.0"/>
<omgdi:waypoint x="-210.0" y="-425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-b3da428e-37fc-410e-a90f-40eb0230e892" bpmnElement="manager_judge">
<omgdc:Bounds x="250.0" y="-585.0001" width="40.0" height="40.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-e56b296d-0690-44e3-bdaf-6e3864a826ca" bpmnElement="manager_audit">
<omgdi:waypoint x="150.0" y="-565.0001"/>
<omgdi:waypoint x="250.0" y="-565.0001"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="edge-a806347f-3f50-49da-ab26-d571a6104c0c" bpmnElement="manager_rejet">
<omgdi:waypoint x="270.0" y="-545.0001"/>
<omgdi:waypoint x="269.99997" y="-424.99997"/>
<omgdi:waypoint x="-5.0" y="-425.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="shape-416e3b9e-2e1a-489a-808e-fa5fd3f8c691" bpmnElement="请假成功">
<omgdc:Bounds x="395.0" y="-580.00006" width="30.0" height="30.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="edge-33f48358-b60a-4ea8-bd80-9729cfdf6a11" bpmnElement="manager_agree">
<omgdi:waypoint x="290.0" y="-565.0001"/>
<omgdi:waypoint x="395.0" y="-565.00006"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
不想画的小伙伴可以直接复制我的内容。
这个文件中,我们只需要关注被 <process> </process> 标签包起来的内容,这是一个完整的流程定义。
其实XML的内容非常容易理解,根据标签和流程图来对照看,可以知道具体的含义:
- <process> : 表示一个完整的工作流程。
- <startEvent> : 工作流中起点位置,也就是图中的绿色按钮。
- <endEvent> : 工作流中结束位置,也就是图中的红色按钮。
- <userTask> :代表一个任务审核节点(组长、经理等角色),这个节点上有一个 flowable:assignee 属性,这表示这个节点该由谁来处理,将来在 Java 代码中调用的时候,我们需要指定对应的处理人的 ID 或者其他唯一标记。
- <serviceTask>:这是服务任务,在具体的实现中,这个任务可以做任何事情,这里我们使用flowable:class 属性配置了一个类,表示如果走到该节点则自动执行该类中的方法。
- <exclusiveGateway> :逻辑判断节点,相当于流程图中的菱形框。
- <sequenceFlow> :链接各个节点的线条,sourceRef 属性表示线的起始节点,targetRef 属性表示线指向的节点,我们图中的线条都属于这种。
根据上述对每个标签的解释,能够很轻易的看懂生成出来的XML文件。
五、代码测试
Gitee代码地址:https://gitee.com/du_xin_cheng/flowable_study
启动类:
package src.com.dxc;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.DeploymentBuilder;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import javax.annotation.Resource;
import java.io.InputStream;
/**
* 启动类
*
* @Author xincheng.du
* @Date 2023/5/22 16:50
*/
@SpringBootApplication
public class Application implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Resource
private RepositoryService repositoryService;
/**
* 项目启动加载流程文件
*
* @param args args
*/
@Override
public void run(String... args) {
InputStream inputStream = this.getClass().getResourceAsStream("/ask_for_leave.bpmn20.xml");
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
deploymentBuilder.addInputStream("ask_for_leave.bpmn20.xml", inputStream);
deploymentBuilder.deploy();
}
}
发起请假流程参数类 AskForLeaveStartDTO:
package src.com.dxc.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 发起请假流程参数
*
* @Author xincheng.du
* @Date 2023/5/23 15:00
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AskForLeaveStartDTO {
/**
* 员工id
*/
private String employeeId;
/**
* 员工姓名
*/
private String name;
/**
* 请假原因
*/
private String reason;
/**
* 请假天数
*/
private Integer days;
}
审核参数类 AuditDTO:
package src.com.dxc.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 审核参数
*
* @Author xincheng.du
* @Date 2023/5/23 15:12
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class AuditDTO {
/**
* 下级id {员工id || 组长id}
*/
private String lowerId;
/**
* 下级名称 {employee || leader}
* 此处的名称对应 ask_for_leave.bpmn20.xml 文件中<userTask>标签下的 flowable:assignee 属性
*/
private String lowerName;
/**
* 上级id {组长id || 经理id}
*/
private String superiorId;
/**
* 上级名称 {leader || manager}
* 此处的名称对应 ask_for_leave.bpmn20.xml 文件中<userTask>标签下的 flowable:assignee 属性
*/
private String superiorName;
/**
* 审核结果 {同意 || 驳回}
*/
private String checkResult;
/**
* 是否为最上级
* true->leaderId为最上级,managerId为空
* false->leaderId不为最上级,managerId为leaderId的上级
*/
private Boolean isTop;
}
请假流程接口 AskForLeaveService:
package src.com.dxc.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import src.com.dxc.model.AskForLeaveStartDTO;
import src.com.dxc.model.AuditDTO;
import src.com.dxc.service.AskForLeaveService;
import java.util.*;
/**
* 请假流程
*
* @Author xincheng.du
* @Date 2023/5/23 14:51
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AskForLeaveServiceImpl implements AskForLeaveService {
private final RuntimeService runtimeService;
private final TaskService taskService;
public static final String EMPLOYEE = "employee";
public static final String FLOW_KEY = "ask_for_leave";
public static final String NAME = "name";
public static final String REASON = "reason";
public static final String DAYS = "days";
public static final String CHECK_RESULT = "checkResult";
@Override
public void askForLeave(AskForLeaveStartDTO dto) {
HashMap<String, Object> map = new HashMap<>();
map.put(EMPLOYEE, dto.getEmployeeId());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(FLOW_KEY, map);
runtimeService.setVariable(processInstance.getId(), NAME, dto.getName());
runtimeService.setVariable(processInstance.getId(), REASON, dto.getReason());
runtimeService.setVariable(processInstance.getId(), DAYS, dto.getDays());
log.info("创建请假流程 processId:{}", processInstance.getId());
}
@Override
public void executeProcess(AuditDTO dto) {
// 查找到下级的任务,然后提交给上级审批
List<Task> list = taskService.createTaskQuery().taskAssignee(dto.getLowerId()).orderByTaskId().desc().list();
for (Task task : list) {
log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended());
Map<String, Object> map = new HashMap<>();
// 如果当前处理人不为最顶级处理人,那么需要指定当前处理人的上级id
Optional.of(dto.getIsTop()).ifPresent(isTop -> {
if (Objects.equals(Boolean.FALSE, isTop)) {
map.put(dto.getSuperiorName(), dto.getSuperiorId());
}
});
Optional.ofNullable(dto.getCheckResult()).ifPresent(result -> map.put(CHECK_RESULT, result));
taskService.complete(task.getId(), map);
}
}
}
请假流程实现类 AskForLeaveServiceImpl:
package src.com.dxc.service.impl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.springframework.stereotype.Service;
import src.com.dxc.model.AskForLeaveStartDTO;
import src.com.dxc.model.AuditDTO;
import src.com.dxc.service.AskForLeaveService;
import java.util.*;
/**
* 请假流程
*
* @Author xincheng.du
* @Date 2023/5/23 14:51
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class AskForLeaveServiceImpl implements AskForLeaveService {
private final RuntimeService runtimeService;
private final TaskService taskService;
public static final String EMPLOYEE = "employee";
public static final String FLOW_KEY = "ask_for_leave";
public static final String NAME = "name";
public static final String REASON = "reason";
public static final String DAYS = "days";
public static final String CHECK_RESULT = "checkResult";
@Override
public void askForLeave(AskForLeaveStartDTO dto) {
HashMap<String, Object> map = new HashMap<>();
map.put(EMPLOYEE, dto.getEmployeeId());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(FLOW_KEY, map);
runtimeService.setVariable(processInstance.getId(), NAME, dto.getName());
runtimeService.setVariable(processInstance.getId(), REASON, dto.getReason());
runtimeService.setVariable(processInstance.getId(), DAYS, dto.getDays());
log.info("创建请假流程 processId:{}", processInstance.getId());
}
@Override
public void executeProcess(AuditDTO dto) {
// 查找到下级的任务,然后提交给上级审批
List<Task> list = taskService.createTaskQuery().taskAssignee(dto.getLowerId()).orderByTaskId().desc().list();
for (Task task : list) {
log.info("任务 ID:{};任务处理人:{};任务是否挂起:{}", task.getId(), task.getAssignee(), task.isSuspended());
Map<String, Object> map = new HashMap<>();
// 如果当前处理人不为最顶级处理人,那么需要指定当前处理人的上级id
Optional.of(dto.getIsTop()).ifPresent(isTop -> {
if (Objects.equals(Boolean.FALSE, isTop)) {
map.put(dto.getSuperiorName(), dto.getSuperiorId());
}
});
Optional.ofNullable(dto.getCheckResult()).ifPresent(result -> map.put(CHECK_RESULT, result));
taskService.complete(task.getId(), map);
}
}
}
请假失败执行类 AskForLeaveFail:
package src.com.dxc.service;
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
@Slf4j
public class AskForLeaveFail implements JavaDelegate {
@Override
public void execute(DelegateExecution execution) {
log.info("请假失败。。。");
}
}
查看流程进度Controller,通过启动项目调用接口查看:
package src.com.dxc.controller;
import lombok.RequiredArgsConstructor;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.engine.ProcessEngine;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
/**
* 查看流程进度
*
* @Author xincheng.du
* @Date 2023/5/23 15:25
*/
@RestController
@RequiredArgsConstructor
public class ShowController {
private final RuntimeService runtimeService;
private final RepositoryService repositoryService;
private final ProcessEngine processEngine;
@GetMapping("/showFlowPic")
public void showPic(HttpServletResponse resp, String processId) throws Exception {
ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
if (pi == null) {
return;
}
List<Execution> executions = runtimeService
.createExecutionQuery()
.processInstanceId(processId)
.list();
List<String> activityIds = new ArrayList<>();
List<String> flows = new ArrayList<>();
for (Execution exe : executions) {
List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
activityIds.addAll(ids);
}
BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", activityIds, flows, engconf.getActivityFontName(), engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, false);
OutputStream out = null;
byte[] buf = new byte[1024];
int legth = 0;
try {
out = resp.getOutputStream();
while ((legth = in.read(buf)) != -1) {
out.write(buf, 0, legth);
}
} finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
}
}
流程测试类 AskForLeaveServiceImplTest :
package src.com.dxc.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import src.com.dxc.Application;
import src.com.dxc.model.AskForLeaveStartDTO;
import src.com.dxc.model.AuditDTO;
import src.com.dxc.service.AskForLeaveService;
@Slf4j
@SpringBootTest(classes = Application.class)
class AskForLeaveServiceImplTest {
@Autowired
public AskForLeaveService askForLeaveService;
/**
* 发起请假流程
*/
@Test
void askForLeave() {
AskForLeaveStartDTO dto = new AskForLeaveStartDTO();
dto.setEmployeeId("1");
dto.setName("xiaoMing");
dto.setReason("旅游");
dto.setDays(10);
askForLeaveService.askForLeave(dto);
}
/**
* 员工提交流程到组长处
*/
@Test
void submit() {
AuditDTO dto = new AuditDTO();
dto.setLowerId("1");
dto.setLowerName("employee");
dto.setSuperiorId("2");
dto.setSuperiorName("leader");
dto.setIsTop(false);
askForLeaveService.executeProcess(dto);
}
/**
* 组长审批 - 同意
*/
@Test
void leaderAgree() {
AuditDTO dto = new AuditDTO();
dto.setLowerId("2");
dto.setLowerName("leader");
dto.setSuperiorId("3");
dto.setSuperiorName("manager");
dto.setCheckResult("同意");
dto.setIsTop(false);
askForLeaveService.executeProcess(dto);
}
/**
* 组长审批 - 驳回
*/
@Test
void leaderReject() {
AuditDTO dto = new AuditDTO();
dto.setLowerId("2");
dto.setLowerName("leader");
dto.setSuperiorId("3");
dto.setSuperiorName("manager");
dto.setCheckResult("驳回");
dto.setIsTop(false);
askForLeaveService.executeProcess(dto);
}
/**
* 经理审批 - 同意
*/
@Test
void managerAgree() {
AuditDTO dto = new AuditDTO();
dto.setLowerId("3");
dto.setLowerName("manager");
dto.setCheckResult("同意");
dto.setIsTop(true);
askForLeaveService.executeProcess(dto);
}
/**
* 经理审批 - 驳回
*/
@Test
void managerReject() {
AuditDTO dto = new AuditDTO();
dto.setLowerId("3");
dto.setLowerName("manager");
dto.setCheckResult("驳回");
dto.setIsTop(true);
askForLeaveService.executeProcess(dto);
}
}
每走一步都可以通过访问接口 /showFlowPic 查看到当前进度是否正确,接口中所需的processId 为 askForLeave() 方法打印出的 processId。