为了账号安全,请及时绑定邮箱和手机立即绑定

springBoot2.0集成Activiti6.0.0工作流

标签:
Java

那么首先我们应该知道工作流是干什么的
简单来说工作流就是多个参与者,按照某种预定义的规则,传递业务信息,进行审核的功能一个框架
Activiti就是通过流程引擎processEngine,调用Service,从而操作activiti提供的数据库的23表

数据表分类
ACT_GE_* 通用数据表(GE表示General)
ACT_RE_* 流程定义存储表(RE表示repository)
ACT_ID_* 身份信息表(ID表示IDentity)
ACT_RU_* 运行是数据库表(RU表示runtime)
ACT_HI_* 历史数据库表(HI表示history)

processEnigne 流程引擎
我们可以通过流程引擎来获取一些service
图片描述

ReopsitoryService :
负责对流程文件的管理,主要操作一些静态文件,比如流程文件中的xml,流程图.bpmn文件等
我们通过repositoryService部署流程对象, 会涉及到两个实体对象,一个是部署对象,一个是资源对象,部署对象和资源对象是一个一对多的关系,那么就可以说明, 一次部署可以包含多个资源文件,最常见的流程部署就是把流程图的xml或者.bpmn图片部署到数据库里面,
图片描述

RuntimeService :主要是对流程进行控制的API,可以用于启动一个流程实例,针对制定的流程实例,进行暂停,挂起,和继续执行,也可以查询正在运行中的流程实例和执行对象,也可以对流程中的上下文数据进行设置和获取
图片描述
通过RuntimeService启动流程,processDefinitionKey就是设置的整个流程的Id,businessKey因为整个流程为完成的时候都会存在,那么就可以设置成自己的业务数据表的Id,这样可以和activiti的数据表有一个交互的作用,也可以在自己的业务表中存放processInstanceId或者taskId,这样也可以直接通过业务数据命中该流程的实例,
variables也可以存放一些业务数据,这些都是需要在启动流程的时候的才能存放的

TaskService 主要管理userTask, 也就是人工任务, 可以对人工任务进行增删改查,也可以对用户任务设置指定的操作权限,指定的用户或用户主,同时也可以对用户任务上下文的变量设置或获取

	    // 通过流程实例Id获取当前任务
        Task task = taskService.createTaskQuery()
                .processInstanceId(processInstance.getProcessInstanceId())
                .singleResult();
          // 通过businessKey获取当前任务实例
          Task task2 = taskService.createTaskQuery()
                .processInstanceBusinessKey("业务表Id")
                .singleResult();      
		// 执行任务
        taskService.complete(task.getId());
		// 也可以携带参数执行,比如排他网关需要的参数等
        taskService.complete(task.getId(), map);

IdentityService 是对用户或者用户主管理,我们可以创建用户或用户主,并维护用户之间的关系

FormService 可以解析出流程定义中的设计表单,对表单的输入类型和格式做数据渲染

HistoryService 主要提供了对运行结束的流程实例的查询功能,也提供了基于流程维度和用户维度的删除操作,方便我们统计流程执行过程的变化,

ManagementService 主要是对流程引擎基础的管理, 一般用的比较少,还提供了对定时任务的管理

DynamicBPMService 动态,侵入性比较高的功能, 他可以动态的对流程定义的模型做修改, 一般不推荐使用

BPMN2.0(Buisness Process Model and Notation)

是一套业务流程模型与符号建模标准
精准的执行语义来描述元素的操作
以XML为载体,以符号可视化业务
BPMN2.0元素
FlowObjects 流对象 包括了事件,活动和网关,这些流对象通过连接对象连接起来,表示数据流转,过程中的数据流转主要通过连接对象来描述的,
ConnectingObjects 连接对象
Swimlanes 泳道 适用于对业务做一个范围维度的区分, 一般通过不同的职能做区分,比如角色和部门来区分不同的范围
Data 数据
Artifacs 描述对象

图片描述

idea+actiBPM画图工具+jdk8+springBoot2.0+activiti6.0.0+jpa
pom.xml需要的依赖

org.springframework.boot
spring-boot-starter-parent
2.0.2.RELEASE

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</java.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-dmn-model</artifactId>
            <version>6.0.0</version>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-actuator</artifactId>
        <exclusions>
            <exclusion>
                <artifactId>log4j-api</artifactId>
                <groupId>org.apache.logging.log4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-hateoas</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-tomcat</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-el</artifactId>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-spring-boot-starter-basic</artifactId>
        <version>6.0.0</version>
        <exclusions>
            <exclusion>
                <artifactId>slf4j-log4j12</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>org.activiti</groupId>
        <artifactId>activiti-app-conf</artifactId>
        <version>6.0.0</version>
        <exclusions>
            <exclusion>
                <artifactId>slf4j-log4j12</artifactId>
                <groupId>org.slf4j</groupId>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid-spring-boot-starter</artifactId>
        <version>1.1.8</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

自己的业务数据表
package com.ActivitiDemo.domain;

import com.ActivitiDemo.dto.TaskDto;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.util.StringUtils;

import javax.persistence.*;
import java.util.Date;

@Entity
@Table(name = “t_leave_task”)
public class LeaveTask {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "user_id", columnDefinition = "int(10) COMMENT '请假人ID'")
private Integer userId;
@Column(name = "user_name", columnDefinition = "varchar(20) COMMENT '请假人性名'")
private String userName;
@Column(name = "start_date", columnDefinition = "timestamp COMMENT '请假开始时间'")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date startDate;
@Column(name = "end_date",columnDefinition = "timestamp COMMENT '请假结束时间'")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date endDate;

@Column(name = "leave_type", columnDefinition = "int(10) COMMENT '流程: 0.已提交, 1.主管审批, 2.人事审批, 3.已取消, 4.已完成'")
private LeaveType type;
@Column(name = "leave_cause",columnDefinition = "varchar(50) COMMENT '请假原因'")
private String leaveCause;

@Column(name = "create_date",columnDefinition = "timestamp COMMENT '任务创建时间'")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date createDate;
@Column(name = "review_status",columnDefinition = "int(1) COMMENT '审批结果'")
private Boolean reviewStatus;
@Column(name = "review_date", columnDefinition = "timestamp COMMENT '审批时间'")
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private Date reviewDate;

@Column(name = "review_by", columnDefinition = "varchar(50) COMMENT '审批人'")
private String reviewBy;
@Column(name = "review_in", columnDefinition = "varchar(50) COMMENT '审批原因'")
private String reviewIn;

public LeaveTask() {
}

public LeaveTask(TaskDto dto) {
    this.userId = dto.getUserId();
    this.userName = dto.getUserName();
    this.startDate = dto.getStartDate();
    this.endDate = dto.getEndDate();
    this.leaveCause = StringUtils.isEmpty(dto.getLeaveCause()) ? null : dto.getLeaveCause();
    this.type = LeaveType.tl_approve;
    this.createDate = new Date();
    this.reviewBy = dto.getUserName();
    this.reviewIn = StringUtils.isEmpty(dto.getLeaveCause()) ? null : dto.getLeaveCause();
    this.reviewDate = new Date();
    this.reviewStatus = dto.getDecision();

// setter和getter方法省略。。。
}

spring-jpa可以根据映射表自动在数据库建立表,有兴趣的可以去看一下相关的API

package com.ActivitiDemo.domain;

public enum LeaveType {

submit_leave("已提交"),
tl_approve("主管审批"),
hr_approve("人事审批"),
error_leave("已取消"),
end_leave("已完成");

private final String desc;

LeaveType(String desc) {
    this.desc = desc;
}

public String getDesc() {
    return desc;
}

}

package com.ActivitiDemo.domain;

import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;

import java.util.Date;
import java.util.Optional;

@Repository
public interface LeaveTaskRepository extends CrudRepository<LeaveTask, Long> {

@Query(value = "update LeaveTask set reviewStatus = ?1, reviewBy = ?2, reviewIn = ?3, reviewDate = ?4, type = ?5 where id = ?6")
@Modifying
void updateReviewById(boolean reviewStatus, String reviewBy, String reviewIn, Date reviewDate, LeaveType type, Long id);

/**
 * 查询用户是否有未完成订单
 *
 * @param userId
 * @param type0
 * @param type1
 * @return
 */
Optional<LeaveTask> findByUserIdAndTypeNotAndTypeNot(Integer userId, LeaveType type0, LeaveType type1);

}

package com.ActivitiDemo.service;

import com.ActivitiDemo.domain.LeaveTask;
import com.ActivitiDemo.domain.LeaveTaskRepository;
import com.ActivitiDemo.domain.LeaveType;
import com.ActivitiDemo.dto.ApprovalDto;
import com.ActivitiDemo.dto.TaskDto;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.client.HttpServerErrorException;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
@Transactional
public class ActivitiService {

@Resource
private LeaveTaskRepository leaveTaskRepository;

@Resource
private RuntimeService runtimeService;

@Resource
private TaskService taskService;

@Resource
private RepositoryService repositoryService;


public void postLeaveTask(TaskDto dto) {

    // 判断是否已有流程在走
    Optional<LeaveTask> optionalLeaveTask = leaveTaskRepository.findByUserIdAndTypeNotAndTypeNot(dto.getUserId(), LeaveType.end_leave, LeaveType.error_leave);

    // 流程已存在
    if(optionalLeaveTask.isPresent()) {

        Task task = taskService.createTaskQuery()
                .processInstanceBusinessKey(optionalLeaveTask.get().getId().toString())
                .singleResult();

        if (!ObjectUtils.isEmpty(task) && "ask_for_leave".equals(task.getTaskDefinitionKey())) {

            Map<String, Object> map = new HashMap<>();
            map.put("tlApprove", dto.getDecision() ? "Y" : "N");
            taskService.complete(task.getId(), map);

            // 修改请假单表的审批信息
            leaveTaskRepository.updateReviewById(dto.getDecision()
                    , dto.getUserName()
                    , StringUtils.isEmpty(dto.getLeaveCause()) ? null : dto.getLeaveCause()
                    , new Date()
                    , dto.getDecision() ? LeaveType.tl_approve : LeaveType.error_leave
                    , optionalLeaveTask.get().getId());

        }else {
            throw new HttpServerErrorException(HttpStatus.BAD_REQUEST, "错误!");
        }
    }else {
        // 没有流程, 新建
        LeaveTask leaveTask = new LeaveTask(dto);
        LeaveTask result = leaveTaskRepository.save(leaveTask);

        String processDefinitionKey = "LeaveTheProcess";
        // 启动流程
        ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("LeaveTheProcess", result.getId().toString());

        // 获取当前任务
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).singleResult();

        Map<String, Object> map = new HashMap<>();
        map.put("submitType", dto.getDecision() ? "Y" : "N");

        taskService.complete(task.getId(), map);
    }
}


/**
 * 审批流程
 *
 * @param dto
 */
public void approveProcess(ApprovalDto dto) {

    Task task = taskService.createTaskQuery()
            .processInstanceBusinessKey(dto.getLeaveId().toString())
            .singleResult();

    if (!ObjectUtils.isEmpty(task) && "tl_approve".equals(task.getTaskDefinitionKey())) {
        this.completeTlApproveTask(dto, task.getId());
    } else if (!ObjectUtils.isEmpty(task) && "hr_approve".equals(task.getTaskDefinitionKey())) {
        this.completeHrApproveTask(dto, task.getId());
    }

}


/**
 * 主管审批
 *
 * @param dto
 */
public void completeTlApproveTask(ApprovalDto dto, String taskId) {

    Map<String, Object> map = new HashMap<>();
    map.put("tlApprove", dto.getReviewStatus() ? "Y" : "N");
    taskService.complete(taskId, map);

    // 修改请假但表的审批信息
    leaveTaskRepository.updateReviewById(dto.getReviewStatus(), dto.getReviewBy(), dto.getReviewIn(), new Date(), dto.getReviewStatus() ? LeaveType.hr_approve : LeaveType.submit_leave, dto.getLeaveId());

}


/**
 * 人事审批
 *
 * @param dto
 */
public void completeHrApproveTask(ApprovalDto dto, String taskId) {

    Map<String, Object> map = new HashMap<>();
    map.put("hrApprove", dto.getReviewStatus() ? "Y" : "N");
    taskService.complete(taskId, map);

    // 修改请假但表的审批信息
    leaveTaskRepository.updateReviewById(dto.getReviewStatus(), dto.getReviewBy(), dto.getReviewIn(), new Date(), dto.getReviewStatus() ? LeaveType.end_leave : LeaveType.submit_leave, dto.getLeaveId());
}


/**
 * 请假流程部署
 */
public void deploy() {
    repositoryService.createDeployment()
            .addClasspathResource("processes/leave_the_process.bpmn")
            .name("请假审批流程")
            .category("请假")
            .deploy();

}

}

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消