Flowable综合案例一

1.创建一个Maven工程,导入相关依赖:

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.5.RELEASE</version>
        <relativePath />
    </parent>
    <dependencies>
        <!--flowable-->
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-process</artifactId>
            <version>6.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-spring-boot-starter-actuator</artifactId>
            <version>6.4.2</version>
        </dependency>
        <dependency>
            <groupId>org.flowable</groupId>
            <artifactId>flowable-json-converter</artifactId>
            <version>6.4.2</version>
        </dependency>
        <!--数据库-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        <!--rest支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

2.在application.yml中配置数据源和Flowable:

#数据源配置
spring:
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/repair?characterEncoding=UTF-8
    username: root
    password: 1123

#flowable配置
#自动部署验证设置:true-开启(默认)、false-关闭
flowable:
  check-process-definitions: false

3.配置启动类:

package com.flowable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class RepairApp {
    /**
     *日志信息
     */
    private static final Logger log = LoggerFactory.getLogger(RepairApp.class);

    public static void main(String[] args) {
        log.info("项目开始启动");
        SpringApplication.run(RepairApp.class,args);
        log.info("项目启动完成");
    }
}

4.启动项目,此时你会发现你的数据库中多了很多ACT_开头的表

flowable 系统架构 flowable实战_List

5.案例演示:

前面我们介绍了流程设计器的使用,现在我们以真实业务需求从画图开始讲解。

下面从一个真实的业务来讲解Flowable如何启动、跳转、查看流程跳转日志、和具体的业务关联。

需求:

销售人员申请项目提成→部门经理审批→总经理审批

不难发现:总经理这个人是不变的,而部门经理这个审批人可能会随着发起人的改变而改变。

在上一节流程设计器中我们简单介绍了审批人配置和任务监听器的使用。下面我们从代码层面进行讲解。

5.1、 流程图:

flowable 系统架构 flowable实战_activiti_02

flowable 系统架构 flowable实战_spring_03


flowable 系统架构 flowable实战_spring_04


flowable 系统架构 flowable实战_flowable 系统架构_05


flowable 系统架构 flowable实战_flowable 系统架构_06


flowable 系统架构 flowable实战_flowable 系统架构_07

5.2、代码讲解:

1、任务监听器代码:

package org.springblade.modules.business.listener;

import org.apache.commons.lang.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.task.service.delegate.DelegateTask;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.modules.business.service.SendMessageService;
import org.springblade.modules.business.utils.GetUserIdByAccountUtils;
import org.springblade.modules.business.utils.ManagerUtils;
import org.springblade.modules.qywx.entity.HeadEntity;
import org.springblade.modules.qywx.service.IHeadService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component("DeptManagerListener")
public class DeptManagerListener implements TaskListener {
    public static DeptManagerListener findManager;
    @Autowired
    private TaskService taskService;
    @Autowired
    private IHeadService headService;
    @Autowired
    private SendMessageService sendMessageService;

    //初试化
    @PostConstruct
    public void init() {
        findManager = this;
        findManager.taskService = this.taskService;
        findManager.headService = this.headService;
        findManager.sendMessageService = this.sendMessageService;
    }
   
    @Override
    public void notify(DelegateTask delegateTask) {
       //获取所有部门领导id
        List<Long> managerIds = ManagerUtils.getManagers();
        //当前登录用户
        BladeUser user = AuthUtil.getUser();
        //如果是部门经理本人,默认审批用过
        if (managerIds.contains(AuthUtil.getUserId())) {
            findManager.taskService.setAssignee(delegateTask.getId(), user.getUserId().toString());
            Map<String, Object> m = new HashMap<>();
            m.put("outcome", 1);
            findManager.taskService.setAssignee(delegateTask.getId(), user.getUserId().toString());
            findManager.taskService.complete(delegateTask.getId(), m);
            //通知老板审批
            this.sendMessage(delegateTask, "总经理的账号");
            return;
        }
        //根据当前登录用户部门ID找部门负责人ID
        String deptId = AuthUtil.getDeptId();
        HeadEntity headEntity = new HeadEntity();
        String userAccount = null;
        if (StringUtils.isNotEmpty(deptId)) {
            long parseLong = Long.parseLong(deptId);
            headEntity.setDeptId(parseLong);
        }
        List<HeadEntity> list = findManager.headService.list(Condition.getQueryWrapper(headEntity));
        //这里默认一个部门只有一个负责人
        HeadEntity header = list.get(0);
        if (header != null) {
            userAccount = header.getUserAccount();
            //派发任务
            findManager.taskService.setAssignee(delegateTask.getId(), GetUserIdByAccountUtils.getUserId(userAccount));            //发送审批通知
            //给审批人推送审批通知
            this.sendMessage(delegateTask, userAccount);
        }
    }

    /**
     * 推送审批通知
     *
     * @param delegateTask
     * @param userAccount
     */
    public void sendMessage(DelegateTask delegateTask, String userAccount) {
        findManager.sendMessageService.sendDeptMessage(delegateTask, userAccount);
    }
}

2、部署流程:
(1)、如果你的流程设计器和你当前的项目连的是同一个数据库的话:

controller层:

/**
     * 部署流程
     */
    @GetMapping(value = "/deployByKey")
    @ApiOperationSupport(order = 4)
    @ApiOperation(value = "部署流程", notes = "部署流程")
    public R<String> deployByKey(@ApiParam(value = "流程定义的key", required = true) @RequestParam String processDefinitionKey) {
        try {
            processService.deployByKey(processDefinitionKey);
            return R.data("部署成功。");
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("服务器异常!");
        }
    }

service层:

//需要注入的Flowable相关service:
    private final ModelRepository modelRepository;
    private final RepositoryService repositoryService;


    @Override
   public void deployByKey(String processDefinitionKey) {
       List<Model> models = modelRepository.findByKeyAndType(processDefinitionKey, 0);
       if (models.size() > 0) {
           for (Model model : models) {
               String id = model.getId();
               this.deployModel(id, "flow_2", null);
           }
       }
   }

   public boolean deployModel(String modelId, String category, List<String> tenantIdList) {
       FlowModel model = this.getById(modelId);
       if (model == null) {
           throw new ServiceException("No model found with the given id: " + modelId);
       }
       byte[] bytes = getBpmnXml(model);
       String processName = model.getName();
       if (!StringUtil.endsWithIgnoreCase(processName, FlowEngineConstant.SUFFIX)) {
           processName += FlowEngineConstant.SUFFIX;
       }
       String finalProcessName = processName;
       if (Func.isNotEmpty(tenantIdList)) {
           tenantIdList.forEach(tenantId -> {
               Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModelKey()).tenantId(tenantId).deploy();
               deploy(deployment, category);
           });
       } else {
           Deployment deployment = repositoryService.createDeployment().addBytes(finalProcessName, bytes).name(model.getName()).key(model.getModelKey()).deploy();
           deploy(deployment, category);
       }
       return true;
   }

(2)、如果你的流程设计器和项目连的不是一个库:

首先你需要把你的流程图下载下来保存到本地,然后利用代码找到这个bpmn文件进行部署。

flowable 系统架构 flowable实战_spring_08

/**
     * 部署流程
     * filePath 文件路径 name 流程名字
     */
    public Map<String, Object> deploymentFlow(String filePath, String name) {
        try {
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment()
                    .addClasspathResource(filePath).name(name);
            Deployment deployment = deploymentBuilder.deploy();
            logger.info("成功:部署工作流程:" + filePath);
            //acr_re_deployment表的id
            String id = deployment.getId();
            ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
            //搜索条件deploymentId
            query.deploymentId(id);
            //最新版本过滤
            query.latestVersion();
            //查询
            ProcessDefinition definition = query.singleResult();
            //act_re_procdef表的key和id
            String key = definition.getKey();
            String definitionId = definition.getId();
            Map<String, Object> map = new HashMap<>();
            map.put("流程定义的key", key);
            map.put("流程定义的的id", definitionId);
            return map;
        } catch (Exception e) {
            logger.error("失败:部署工作流:" + e);
            return null;
        }
    }

3、启动流程:
本案例我们使用业务绑定流程的方式,通俗讲就是在业务表里面加一个流程实例的id。一条业务数据绑定一个流程实例。其他方案后期会再介绍。

controller层:

private final IProjectRoyaltiesProcessService project_royalties_processService;
    private final RuntimeService runtimeService;
    private final IdentityService identityService;
    
    /**
     * 申请项目提成
     */
    @PostMapping("/start")
    @ApiOperationSupport(order = 20)
    @ApiOperation(value = "申请", notes = "传入id")
    public R submitProjectRoyalties(Long id) {
        try {
            //根据业务id获取业务数据
            ProjectRoyaltiesProcessEntity entity = project_royalties_processService.getById(id);
            // 设置流程启动用户(当前登录用户)
            identityService.setAuthenticatedUserId(AuthUtil.getUserId().toString());
            //启动流程(这个key就是我前面强调的流程图定义的key)
            ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("projectRoyalties");
            //流程实例id
            String processInstanceId = processInstance.getId();
            //把流程实例id存入业务表使流程与业务绑定
            entity.setProcessId(processInstanceId);
            //如果是部门经理本人,直接跳过部门经理审批
            List<Long> managerIds = ManagerUtils.getManagers();
            if (managerIds.contains(AuthUtil.getUserId())) {
                //修改业务状态为待总经理审批
                entity.setStatus(2);
                return R.status(project_royalties_processService.saveOrUpdate(entity));
            }
            //修改业务状态为待部门经理审批
            entity.setStatus(1);
            return R.status(project_royalties_processService.saveOrUpdate(entity));
        } catch (Exception e) {
            e.printStackTrace();
            return R.fail("服务器异常!");
        }
    }

4、查询是否有审批权限(可理解为审批按钮权限):
这里只介绍service层。

private final ProjectRoyaltiesProcessMapper projectRoyaltiesProcessMapper;
    private final TaskService taskService;

    @Override
    public IPage<ProjectRoyaltiesProcessVO> pageList(IPage<ProjectRoyaltiesProcessVO> page, Map<String, Object> params) {
        //分页查询结果
        List<ProjectRoyaltiesProcessVO> list = projectRoyaltiesProcessMapper.list(page, params);
        //获取当前登录用户
        BladeUser user = AuthUtil.getUser();
        Long userId = user.getUserId();
        //遍历分页查询结果
        for (ProjectRoyaltiesProcessVO vo : list) {
            //获取流程实例id
            String processId = vo.getProcessId();
            //查询当前登录用户在当前流程实例中有无代办任务
            List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId.toString()).processInstanceId(processId).list();
            //如果有就赋予审批权限
            if (!tasks.isEmpty()) {
                vo.setFlag(true);
            }
        }
        return page;
    }

5、流程跳转(审批通过、驳回):

@Override
    public String completeTaskByProcessId(String processInstanceId, Integer outcome, String comment) {
        BladeUser user = AuthUtil.getUser();
        String userId = user.getUserId().toString();
        //根据流程实例id和用户id查询代办任务
        Task task = taskService.createTaskQuery().processInstanceId(processInstanceId).taskAssignee(userId).singleResult();
        if (task == null) {
            throw new RuntimeException("未匹配到代办任务!");
        }
        //审批评论
        taskService.addComment(task.getId(), processInstanceId, comment);
        //审批人
        taskService.setAssignee(task.getId(), userId);
        //流程跳转
        Map<String, Object> paras = new HashMap<>();
        //传入审批结果(流程图中配置了流条件,这里必须传参,否则会报错。1是通过,0是驳回)
        paras.put("outcome", outcome);
        taskService.complete(task.getId(), paras);
        return "流程跳转成功!";
    }

6、流程操作日志:

import lombok.Data;

import java.io.Serializable;
import java.util.Date;
import java.util.Map;

/**
 * 工作流通用实体类
 *
 * @author Chill
 */
@Data
public class BladeFlow implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * 任务执行人编号
     */
    private String assignee;

    /**
     * 创建时间
     */
    private Date createTime;
    /**
     * 结束时间
     */
    private Date endTime;
    /**
     * 流程实例是否结束
     */
    private String processIsFinished;
    /**
     * 历史活动id
     */
    private String historyActivityId;
    /**
     * 历史活动流程
     */
    private String historyActivityName;
    /**
     * 历史活动耗时
     */
    private String historyActivityDurationTime;
    /**
     * 任务意见
     */
    private String comment;
    /**
     * 申请人名称
     */
    private String startUserName;

    /**
     * 流程实例id
     */
    private String processId;
}
@Service
@AllArgsConstructor
public class FlowEngineServiceImpl implements FlowEngineService {
    private final HistoryService historyService;
    private final TaskService taskService;
    private final SysUserMapper userMapper;

    @Override
    public List<BladeFlow> historyFlowList(String processInstanceId, String startActivityId, String endActivityId) {
        List<BladeFlow> flowList = new ArrayList<>();
        List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processInstanceId).orderByHistoricActivityInstanceEndTime().asc().list();
        boolean start = false;
        Map<String, Integer> activityMap = new HashMap<>(16);
        for (int i = 0; i < historicActivityInstanceList.size(); i++) {
            HistoricActivityInstance historicActivityInstance = historicActivityInstanceList.get(i);
            if (historicActivityInstance.getEndTime() == null || historicActivityInstance.getActivityName() == null) {
                continue;
            }
            // 过滤开始节点前的节点
            if (StringUtils.isNotEmpty(startActivityId) && startActivityId.equals(historicActivityInstance.getActivityId())) {
                start = true;
            }
            if (StringUtils.isNotEmpty(startActivityId) && !start) {
                continue;
            }
            // 显示开始节点和结束节点,并且执行人不为空的任务
            if (StringUtils.isNotBlank(historicActivityInstance.getAssignee())
                    || "startEvent".equals(historicActivityInstance.getActivityType())
                    || "endEvent".equals(historicActivityInstance.getActivityType())) {
                // 给节点增加序号
                Integer activityNum = activityMap.get(historicActivityInstance.getActivityId());
                if (activityNum == null) {
                    activityMap.put(historicActivityInstance.getActivityId(), activityMap.size());
                }
                BladeFlow flow = new BladeFlow();
                flow.setProcessId(historicActivityInstance.getProcessInstanceId());
                flow.setHistoryActivityId(historicActivityInstance.getActivityId());
                flow.setHistoryActivityName(historicActivityInstance.getActivityName());
                flow.setCreateTime(historicActivityInstance.getStartTime());
                flow.setEndTime(historicActivityInstance.getEndTime());
                // 获取流程发起人名称
                if ("startEvent".equals(historicActivityInstance.getActivityType())) {
                    List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).orderByProcessInstanceStartTime().asc().list();
                    if (processInstanceList.size() > 0) {
                        if (StringUtils.isNotBlank(processInstanceList.get(0).getStartUserId())) {
                            String taskUser = processInstanceList.get(0).getStartUserId();
                            SysUser sysUser = new SysUser();
                            sysUser.setId(Long.parseLong(taskUser));
                            SysUser user = userMapper.selectOne(sysUser);
                            if (user != null) {
                                flow.setAssignee(taskUser);
                                flow.setAssigneeName(user.getName());
                                flow.setStartUserName(user.getName());
                            }
                        }
                    }
                }
                // 获取任务执行人名称
                if (StringUtils.isNotBlank(historicActivityInstance.getAssignee())) {
                    this.getTaskAssign(historicActivityInstance, flow);
                }
                // 获取意见评论内容
                if (StringUtils.isNotBlank(historicActivityInstance.getTaskId())) {
                    List<Comment> commentList = taskService.getTaskComments(historicActivityInstance.getTaskId());
                    if (commentList.size() > 0) {
                        String fullMessage = commentList.get(0).getFullMessage();
                        flow.setComment(commentList.get(0).getFullMessage());
                    }
                }
                flowList.add(flow);
            }
            // 过滤结束节点后的节点
            if (StringUtils.isNotBlank(endActivityId) && endActivityId.equals(historicActivityInstance.getActivityId())) {
                boolean temp = false;
                Integer activityNum = activityMap.get(historicActivityInstance.getActivityId());
                // 该活动节点,后续节点是否在结束节点之前,在后续节点中是否存在
                for (int j = i + 1; j < historicActivityInstanceList.size(); j++) {
                    HistoricActivityInstance hi = historicActivityInstanceList.get(j);
                    Integer activityNumA = activityMap.get(hi.getActivityId());
                    boolean numberTemp = activityNumA != null && activityNumA < activityNum;
                    boolean equalsTemp = StringUtils.equals(hi.getActivityId(), historicActivityInstance.getActivityId());
                    if (numberTemp || equalsTemp) {
                        temp = true;
                    }
                }
                if (!temp) {
                    break;
                }
            }
        }
        return flowList;
    }

    public void getTaskAssign(HistoricActivityInstance historicActivityInstance, BladeFlow flow) {
        String taskId = historicActivityInstance.getTaskId();
        if (taskId != null) {
            List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().taskId(taskId).list();
            if (list.size() > 0) {
                HistoricTaskInstance historicTaskInstance = list.get(0);
                String assignee = historicTaskInstance.getAssignee();
                if (assignee != null) {
                    //这里的assignee就是userId
                    Long id = 0L;
                    try {
                        id = Long.parseLong(assignee);
                    } catch (Exception e) {
                        return;
                    }
                    SysUser sysUser = new SysUser();
                    sysUser.setId(id);
                    SysUser byId = userMapper.selectOne(sysUser);
                    if (byId != null) {
                        //审批人id
                        flow.setAssignee(id.toString());
                        //审批人姓名
                        flow.setAssigneeName(byId.getName());
                    }
                }
            }
        }
    }
}

7、流程节点进程图:
controller层:

/**
     * 查看流程图
     * 传入流程实例id
     */
    @RequestMapping("/processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        flowableService.genProcessDiagram(httpServletResponse, processId);
    }

service层:

/**
     * 查看流程图
     */
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) {
        /**
         * 获得当前活动的节点
         */
        String processDefinitionId = "";
        if (this.isFinished(processId)) {
            // 如果流程已经结束,则得到结束节点
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery().processInstanceId(processId).singleResult();

            processDefinitionId = pi.getProcessDefinitionId();
        } else {
            // 如果流程没有结束,则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        List<String> highLightedActivitis = new ArrayList<String>();

        /**
         * 获得活动的节点
         */
        List<HistoricActivityInstance> highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();

        for (HistoricActivityInstance tempActivity : highLightedActivitList) {
            String activityId = tempActivity.getActivityId();
            highLightedActivitis.add(activityId);
        }

        List<String> flows = new ArrayList<>();

        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "bmp", highLightedActivitis, flows, engconf.getActivityFontName(),
                engconf.getLabelFontName(), engconf.getAnnotationFontName(), engconf.getClassLoader(), 1.0, true);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } catch (IOException e) {
            logger.error("操作异常", e);
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    /**
     * 查看流程是否完成
     */
    public boolean isFinished(String processInstanceId) {
        return historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processInstanceId).count() > 0;
    }

解决流程图中文乱码:

package com.haiyang.flowable.config;


import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.springframework.context.annotation.Configuration;

/**
 * @author WangChenyang
 * date:  2020-12-14
 * desc: flowable配置----为放置生成的流程图中中文乱码
 */
@Configuration
public class FlowableConfig implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {


    @Override
    public void configure(SpringProcessEngineConfiguration engineConfiguration) {
        engineConfiguration.setActivityFontName("宋体");
        engineConfiguration.setLabelFontName("宋体");
        engineConfiguration.setAnnotationFontName("宋体");
    }
}

成品页面展示:

flowable 系统架构 flowable实战_activiti_09


flowable 系统架构 flowable实战_List_10

8.流程启动到结束数据库变化:

部署完毕后,act_re_deployment表中会有一条部署记录,记录这次部署的基本信息,然后是act_ge_bytearray表中有两条记录,记录的是本次上传的bpmn文件和对应的图片文件,每条记录都有act_re_deployment表的外键关联,然后是act_re_procdef表中有一条记录,记录的是该bpmn文件包含的基本信息,包含act_re_deployment表外键。

流程启动,首先向act_ru_execution表中插入一条记录,记录的是这个流程定义的执行实例,其中id和proc_inst_id相同都是流程执行实例id,也就是本次执行这个流程定义的id,包含流程定义的id外键。

然后向act_ru_task插入一条记录,记录的是第一个任务的信息,也就是开始执行第一个任务。包括act_ru_execution表中的execution_id外键和proc_inst_id外键,也就是本次执行实例id。

然后向act_hi_procinst表和act_hi_taskinst表中各插入一条记录,记录的是本次执行实例和任务的历史记录:

任务提交后,首先向act_ru_variable表中插入变量信息,包含本次流程执行实例的两个id外键,但不包括任务的id,因为setVariable方法设置的是全局变量,也就是整个流程都会有效的变量:

当流程中的一个节点任务完成后,进入下一个节点任务,act_ru_task表中这个节点任务的记录被删除,插入新的节点任务的记录。

同时act_ru_execution表中的记录并没有删除,而是将正在执行的任务变成新的节点任务。

同时向act_hi_var_inst和act_hi_taskinst插入历史记录。

整个流程执行完毕,act_ru_task,act_ru_execution和act_ru_variable表相关记录全被清空。

全程有一个表一直在记录所有动作,就是act_hi_actinst表:

以上就是flowable流程启动到结束的所有流程的变化。

9.flowable中的五个引擎

  • 内容引擎 ContentEngine
  • 身份识别引擎 IdmEngine
  • 表单引擎 FormEngine
  • 决策引擎DmnEngine
  • 流程引擎 ProcessEngine

1.流程引擎 ProcessEngine
1.1 RepositoryService

管理流程定义

1.2 RuntimeService

执行管理,包括启动、推进、删除流程实例等操作

1.3 TaskService

任务管理

1.4 *HistoryService

历史管理(执行完的数据的管理)

1.5 IdentityService

组织机构管理

1.6 FormService

一个可选服务,任务表单管理

1.7 ManagerService

获取引擎所在的数据库中存在的表、获取表的元数据信息、创建删除等作业、执行命令类、执行自定义SQL、操作事件日志。

1.8 DynamicBpmnService

动态修改Bpmn流程定义以及部署库等操作。

2.内容引擎ContentEngine

2.1 内容引擎包含的服务有:ContentService和ContentManagementService。

2.2 ContentManagementService提供对数据库表的管理操作。

Map<String, Long> getTableCount(); 获取每个表的记录数量;
String getTableName(Class<?> flowableEntityClass);根据实体类获得对应的数据库表名
TableMetaData getTableMetaData(String tableName);根据实体类获得对应的数据库表名
TablePageQuery createTablePageQuery();创建一个可以进行排序、根据条件分页的查询类
3.身份识别引擎 IdmEngine

身份识别引擎包含的服务有:IdmIdentityService、IdmManagementService、IdmEngineConfiguration。

3.1 IdmIdentityService

  • 提供用户的创建、修改、删除、密码修改、登录、用户头像设置等;
  • 提供组Group的创建、删除、用户与组关系的关联、删除关联;
  • 提供权限的创建、删除、关联等.

3.2 IdmManagementService

对身份识别相关的数据库表进行统计、获取表的列信息。

3.3 IdmEngineConfiguration

提供数据库配置信息。

4.表单引擎 FormEngine

4.1 FormManagementService

提供对数据库表的管理操作。

4.2 FormRepositoryService

表单资源服务。

4.3 FormService

提供表单实例的增删改查操作服务。

5.决策引擎DmnEngine

5.1 DmnManagementService

该类主要用于获取一系列的数据表元数据信息。

5.2 DmnRepositoryService

动态部署流程资源。

5.3 DmnRuleService

按照规则启动流程实例。

5.4 DmnHistoryService

提供对决策执行历史的访问的服务。

本案例仅供参考,后期我们会介绍一个比较通用的写法;敬请期待…。