SpringBoot+Vue+Flowable模拟实现请假审批流程

下面是“SpringBoot+Vue+Flowable模拟实现请假审批流程”的完整攻略。

一、概述

本文介绍了如何使用SpringBoot、Vue以及Flowable框架实现一个完整的请假审批流程,包括:

  • 数据库建表
  • 后端接口编写
  • 前端页面设计
  • 流程图绘制与流程部署
  • 请假申请与审批流程演示

二、数据库建表

本文的请假审批流程需要使用到两个表,分别是oa_leaveoa_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_leaveoa_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. 编写实体类

根据上面创建的两个表,需要编写对应的实体类LeaveLeaveApply

@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包下编写对应的LeaveDaoLeaveApplyDao两个接口,定义需要的数据访问方法。

@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");
    }
}

此处的流程定义的keyleaveProcess,为了让后面的代码能够跑通,我们需要在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

  • Java字节缓存流的构造方法之文件IO流

    Java字节缓存流的构造方法之文件IO流攻略 Java字节缓存流是一种用于处理字节数据的流,它提供了缓存功能,可以提高IO操作的效率。其中,文件IO流是字节缓存流的一种常见用法,用于读取和写入文件。 构造方法 Java字节缓存流的构造方法之文件IO流有以下两种: FileInputStream构造方法:用于创建一个字节缓存输入流,从文件中读取数据。 java…

    other 2023年8月6日
    00
  • 合作推广
    合作推广
    分享本页
    返回顶部