下面是“SpringBoot+Vue+Flowable模拟实现请假审批流程”的完整攻略。
一、概述
本文介绍了如何使用SpringBoot、Vue以及Flowable框架实现一个完整的请假审批流程,包括:
- 数据库建表
- 后端接口编写
- 前端页面设计
- 流程图绘制与流程部署
- 请假申请与审批流程演示
二、数据库建表
本文的请假审批流程需要使用到两个表,分别是oa_leave
和oa_leave_apply
。
oa_leave
表用于存储请假记录,包括请假类型、开始时间、结束时间、请假天数、请假原因等信息。
CREATE TABLE `oa_leave` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '请假记录ID',
`leave_type` varchar(20) NOT NULL COMMENT '请假类型',
`start_time` datetime NOT NULL COMMENT '开始时间',
`end_time` datetime NOT NULL COMMENT '结束时间',
`leave_days` float NOT NULL COMMENT '请假天数',
`reason` varchar(255) NOT NULL COMMENT '请假原因',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='请假记录表';
oa_leave_apply
表用于存储请假流程相关记录,包括流程实例ID、当前任务ID、申请人、审批人、审批意见等信息。
CREATE TABLE `oa_leave_apply` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '记录ID',
`leave_id` bigint(20) NOT NULL COMMENT '请假记录ID',
`process_instance_id` varchar(255) NOT NULL COMMENT '流程实例ID',
`current_task_id` varchar(255) NOT NULL COMMENT '当前任务ID',
`applicant` varchar(50) NOT NULL COMMENT '申请人',
`approver` varchar(50) NOT NULL COMMENT '审批人',
`approve_opinion` varchar(255) DEFAULT NULL COMMENT '审批意见',
`create_time` datetime NOT NULL COMMENT '创建时间',
`update_time` datetime NOT NULL COMMENT '更新时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='请假流程记录表';
三、后端接口编写
前置条件准备
- 具备Java开发能力,熟悉SpringBoot框架和Maven构建工具。
- 安装MySQL数据库,并创建上述
oa_leave
和oa_leave_apply
两个表。 - 配置好
application.yml
文件中的数据库和端口配置。
1. 引入依赖
首先需要在pom.xml
文件中引入SpringBoot和Flowable的依赖:
<dependencies>
<!-- SpringBoot依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MySQL驱动依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!-- Flowable依赖 -->
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.5.0</version>
</dependency>
</dependencies>
2. 编写实体类
根据上面创建的两个表,需要编写对应的实体类Leave
和LeaveApply
:
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Leave implements Serializable {
private static final long serialVersionUID = -2275018397830220969L;
private Long id;
private String leaveType;
private Date startTime;
private Date endTime;
private Float leaveDays;
private String reason;
private Date createTime;
private Date updateTime;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LeaveApply implements Serializable {
private static final long serialVersionUID = 8251364016214808851L;
private Long id;
private Long leaveId;
private String processInstanceId;
private String currentTaskId;
private String applicant;
private String approver;
private String approveOpinion;
private Date createTime;
private Date updateTime;
}
3. 编写DAO层接口和SQL语句
接着,在dao
包下编写对应的LeaveDao
和LeaveApplyDao
两个接口,定义需要的数据访问方法。
@Mapper
public interface LeaveDao {
int saveLeave(Leave leave);
List<Leave> getLeaveList();
Leave getLeaveById(Long id);
}
@Mapper
public interface LeaveApplyDao {
int saveLeaveApply(LeaveApply leaveApply);
int updateLeaveApply(LeaveApply leaveApply);
List<LeaveApply> getLeaveApplyList();
List<LeaveApply> getLeaveApplyListByApprover(String approver);
LeaveApply getLeaveApplyById(Long id);
}
同时,也需要在resource
目录下的mapper
文件夹下编写对应的SQL语句。
<!-- LeaveDao对应的SQL语句 -->
<mapper namespace="com.example.demo.dao.LeaveDao">
<insert id="saveLeave" parameterType="com.example.demo.entity.Leave">
INSERT INTO `oa_leave`
(`leave_type`,`start_time`,`end_time`,`leave_days`,
`reason`,`create_time`,`update_time`)
VALUES
(#{leaveType},#{startTime},#{endTime},#{leaveDays},
#{reason},#{createTime},#{updateTime})
</insert>
<select id="getLeaveList" resultType="com.example.demo.entity.Leave">
SELECT * FROM `oa_leave`
</select>
<select id="getLeaveById" resultType="com.example.demo.entity.Leave">
SELECT * FROM `oa_leave`
WHERE `id`=#{id}
</select>
</mapper>
<!-- LeaveApplyDao对应的SQL语句 -->
<mapper namespace="com.example.demo.dao.LeaveApplyDao">
<insert id="saveLeaveApply" parameterType="com.example.demo.entity.LeaveApply">
INSERT INTO `oa_leave_apply`
(`leave_id`,`process_instance_id`,`current_task_id`,
`applicant`,`approver`,`create_time`,`update_time`)
VALUES
(#{leaveId},#{processInstanceId},#{currentTaskId},
#{applicant},#{approver},#{createTime},#{updateTime})
</insert>
<update id="updateLeaveApply" parameterType="com.example.demo.entity.LeaveApply">
UPDATE `oa_leave_apply` SET
`current_task_id`=#{currentTaskId},
`approve_opinion`=#{approveOpinion},
`update_time`=#{updateTime}
WHERE `id`=#{id}
</update>
<select id="getLeaveApplyList" resultType="com.example.demo.entity.LeaveApply">
SELECT * FROM `oa_leave_apply`
</select>
<select id="getLeaveApplyListByApprover" resultType="com.example.demo.entity.LeaveApply">
SELECT * FROM `oa_leave_apply`
WHERE `approver`=#{approver}
</select>
<select id="getLeaveApplyById" resultType="com.example.demo.entity.LeaveApply">
SELECT * FROM `oa_leave_apply`
WHERE `id`=#{id}
</select>
</mapper>
4. 动态生成流程图
接下来,需要编写一个生成流程图的接口,以及对应的Java类。
@RestController
@RequestMapping("/process")
public class ProcessController {
@Autowired
private FlowableProcessDiagramGenerator diagramGenerator;
@GetMapping("/diagram")
public void generateDiagram(@RequestParam("definitionId") String definitionId,
HttpServletResponse response) throws IOException {
response.setContentType("image/png");
InputStream is = diagramGenerator.generateDiagram(definitionId);
OutputStream os = response.getOutputStream();
IOUtils.copy(is, os);
os.flush();
os.close();
}
}
@Component
public class FlowableProcessDiagramGenerator {
@Autowired
private RepositoryService repositoryService;
public InputStream generateDiagram(String definitionId) {
BpmnModel bpmnModel = repositoryService.getBpmnModel(definitionId);
ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
return processDiagramGenerator.generateDiagram(bpmnModel, "png", Collections.emptyList(), Collections.emptyList(),
"WenQuanYi Micro Hei Mono", "WenQuanYi Micro Hei Mono", "WenQuanYi Micro Hei Mono", null, 1.0);
}
}
5. 编写请假申请后端接口
最后,需要编写请假申请的后端接口。
@RestController
@RequestMapping("/leave")
public class LeaveController {
@Autowired
private LeaveDao leaveDao;
@Autowired
private LeaveApplyDao leaveApplyDao;
@Autowired
private RuntimeService runtimeService;
@PostMapping("/apply")
public ApiResult<String> applyLeave(@RequestBody Leave leave,
@RequestParam("applicant") String applicant,
@RequestParam("approver") String approver) {
leave.setCreateTime(new Date());
leave.setUpdateTime(new Date());
leaveDao.saveLeave(leave);
Map<String, Object> variables = new HashMap<>();
variables.put("applicant", applicant);
variables.put("approver", approver);
variables.put("leave", leave);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("leaveProcess", variables);
LeaveApply leaveApply = new LeaveApply();
leaveApply.setLeaveId(leave.getId());
leaveApply.setProcessInstanceId(processInstance.getId());
leaveApply.setCurrentTaskId(processInstance.getActivityId());
leaveApply.setApplicant(applicant);
leaveApply.setApprover(approver);
leaveApply.setCreateTime(new Date());
leaveApply.setUpdateTime(new Date());
leaveApplyDao.saveLeaveApply(leaveApply);
return ApiResult.success("success");
}
}
此处的流程定义的key
为leaveProcess
,为了让后面的代码能够跑通,我们需要在Flowable的流程设计器中手动设计并导出流程图和相关流程定义文件。
其中,leaveProcess.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:activiti="http://activiti.org/bpmn"
targetNamespace="http://www.activiti.org/test">
<process id="leaveProcess" name="请假流程">
<startEvent id="startEvent" name="开始"></startEvent>
<userTask id="applyTask" name="请假申请" activiti:assignee="${applicant}">
<extensionElements>
<activiti:taskListener event="complete" class="${leaveController}">
<activiti:field name="approveResult"><activiti:string>申请已提交</activiti:string></activiti:field>
<activiti:field name="approveOpinion"><activiti:expression>${leave.reason}</activiti:expression></activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<userTask id="approveTask" name="请假审批" activiti:assignee="${approver}">
<extensionElements>
<activiti:taskListener event="complete" class="${leaveController}">
<activiti:field name="approveOpinion"><activiti:expression>${approveOpinion}</activiti:expression></activiti:field>
<activiti:field name="approveResult"><activiti:expression>${approveResult}</activiti:expression></activiti:field>
</activiti:taskListener>
</extensionElements>
</userTask>
<endEvent id="endEvent" name="结束"></endEvent>
<sequenceFlow id="startToApply" sourceRef="startEvent" targetRef="applyTask"></sequenceFlow>
<sequenceFlow id="applyToApprove" sourceRef="applyTask" targetRef="approveTask"></sequenceFlow>
<sequenceFlow id="approveToEnd" sourceRef="approveTask" targetRef="endEvent"></sequenceFlow>
</process>
</definitions>
6. 示例说明
这里通过两组示例,演示了请假申请流程的完整过程。
示例一:提交请假申请
请求方式:POST
请求地址:http://localhost:8080/leave/apply
请求体:
{
"leaveType": "事假",
"startTime": "2021-08-10T00:00:00.000+0000",
"endTime": "2021-08-15T00:00:00.000+0000",
"leaveDays": 5.0,
"reason": "家中有事,需请假5天。"
}
请求参数:
参数名 | 类型 | 说明 |
---|---|---|
applicant | String | 申请人 |
approver | String | 审批人 |
响应结果:
{
"code": 200,
"message": "success",
"data": null
}
示例二:审批请假申请
请求方式:POST
请求地址:http://localhost:8080/leave/approve
请求体:
{
"leaveApplyId": 1,
"approveOpinion": "同意",
"approveResult": "同意"
}
响应结果:
{
"code": 200,
"message": "success",
"data": null
}
四、前端页面设计
本文的前端页面使用Vue+ElementUI编写,主要包括两个页面:
- 请假申请页面
- 请假审批页面
1. 请假申请页面
```html