Activiti

本质

Activiti最本质最核心的东西就是将流程定义(xml文件)转换成表记录(MySQL数据)

 

核心Service

ProcessEngine

package org.activiti.engine;

import org.activiti.engine.api.internal.Internal;

@Internal
public interface ProcessEngine {
    String VERSION = "7.1.0-M6";

    String getName();

    void close();

    // 流程部署、流程定义、静态数据
    RepositoryService getRepositoryService();

    // 流程实例、流程变量
    RuntimeService getRuntimeService();

    // 任务相关
    TaskService getTaskService();

    // 历史数据
    HistoryService getHistoryService();

    ManagementService getManagementService();

    DynamicBpmnService getDynamicBpmnService();

    // 流程定义相关信息
    ProcessEngineConfiguration getProcessEngineConfiguration();
}

 

数据表说明

表名 说明
act_evt_log 流程引擎通用日志表
act_ge_bytearray 二进制表,存储通用的流程资源
act_ge_property 系统存储表,存储整个流程引擎数据,默认存储三条数据
act_hi_actinst 历史节点表
act_hi_attachment 历史附件表
act_hi_comment 历史意见表
act_hi_detail 历史详情表
act_hi_identitylink 历史用户信息表
act_hi_procinst 历史流程实例表
act_hi_taskinst 历史任务实例表
act_hi_varinst 历史变量表
act_procdef_info 流程定义的动态变更信息
act_re_deployment 部署信息表
act_re_model 流程设计实体表
act_re_procdef 流程定义数据表
act_ru_deadletter_job 作业失败表,失败次数>重试次数
act_ru_event_subscr 运行时事件表
act_ru_execution 运行时流程执行实例表
act_ru_identitylink 运行时用户信息表
act_ru_integration 运行时综合表
act_ru_job 作业表
act_ru_suspended_job 作业暂停表
act_ru_task 运行时任务信息表
act_ru_timer_job 运行时定时器表
act_ru_variable 运行时变量表

注:

  1. ACT_RE_*:  'RE'表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
  2. ACT_RU_*:  'RU'表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。
  3. ACT_ID_*:  'ID'表示identity。 这些表包含身份信息,比如用户,组等等。
  4. ACT_HI_*:  'HI'表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。
  5. ACT_GE_*:  'GE'表示general。通用数据, 用于不同场景下,如存放资源文件。

 

核心API

流程部署
     @RequestMapping(value = "/deploy", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult fileupload(@RequestParam MultipartFile uploadfile) {
        try {
            String filename = uploadfile.getOriginalFilename();
            InputStream is = uploadfile.getInputStream();
            if (filename.endsWith("zip")) {
                repositoryService.createDeployment().name(filename).addZipInputStream(new ZipInputStream(is)).deploy();
            } else if (filename.endsWith("bpmn") || filename.endsWith("xml")) {
                repositoryService.createDeployment().name(filename).addInputStream(filename, is).deploy();
            } else {
                return AjaxResult.error("文件格式错误");
            }
        } catch (Exception e) {
            e.printStackTrace();
            return AjaxResult.error("流程部署失败");
        }
        return AjaxResult.success("流程部署成功");
    }
流程发起
     @PostMapping("/startProcess")
    @ResponseBody
    public AjaxResult startProcess(@RequestParam String pdid)
    {
        // 设置流程发起人
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // 会自动在表ACT_HI_PROCINST 中的START_USER_ID_中设置用户ID,以便后续获取流程发起人信息
        // 设置的认证用户会在当前线程的上下文中生效,直到线程执行完成或者手动清除认证用户
        identityService.setAuthenticatedUserId(user.getUserName());
        // 动态传递参数
        HashMap<String, Object> v = new HashMap<>();
        v.put("name", "wsz");
        runtimeService.startProcessInstanceById(pdid, v);
        return AjaxResult.success();
    }
流程待办
     @PostMapping("/todoList")
    @ResponseBody
    public TableDataInfo todoList(TaskInfo param)
    {
        // 获取当前登录用户
        String username = getUsername();
        TaskQuery condition = taskService.createTaskQuery().taskAssignee(username);
        if (StringUtils.isNotEmpty(param.getTaskName())) {
            condition.taskName(param.getTaskName());
        }
        if (StringUtils.isNotEmpty(param.getProcessName())) {
            condition.processDefinitionName(param.getProcessName());
        }
        // 过滤掉流程挂起的待办任务(激活的任务)
        int total = condition.active().orderByTaskCreateTime().desc().list().size();
        int start = (param.getPageNum()-1) * param.getPageSize();
        // 分页查询
        List<Task> taskList = condition.active().orderByTaskCreateTime().desc().listPage(start, param.getPageSize());
        List<TaskInfo> tasks = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        taskList.stream().forEach(a->{
            // 根据任务获取流程实例,封装任务信息
            ProcessInstance process = runtimeService.createProcessInstanceQuery().processInstanceId(a.getProcessInstanceId()).singleResult();
            TaskInfo info = new TaskInfo();
            info.setAssignee(a.getAssignee());
            info.setBusinessKey(process.getBusinessKey());
            info.setCreateTime(sdf.format(a.getCreateTime()));
            info.setTaskName(a.getName());
            info.setExecutionId(a.getExecutionId());
            info.setProcessInstanceId(a.getProcessInstanceId());
            info.setProcessName(process.getProcessDefinitionName());
            info.setStarter(process.getStartUserId());
            info.setStartTime(sdf.format(process.getStartTime()));
            info.setTaskId(a.getId());
            String formKey = formService.getTaskFormData(a.getId()).getFormKey();
            info.setFormKey(formKey);
            tasks.add(info);
        });
        TableDataInfo rspData = new TableDataInfo();
        rspData.setCode(200);
        rspData.setRows(tasks);
        rspData.setTotal(total);
        return rspData;
    }
流程审批
     @RequestMapping(value = "/completeTask/{taskId}", method = RequestMethod.POST)
    @ResponseBody
    public AjaxResult completeTask(@PathVariable("taskId") String taskId, @RequestBody(required=false) Map<String, Object> variables) {
        String username = getUsername();
        // 设置任务的办理人,记录该操作人为当前登录用户
        taskService.setAssignee(taskId, username);
        // 查出流程实例id
        String processInstanceId = taskService.createTaskQuery().taskId(taskId).singleResult().getProcessInstanceId();
        if (variables == null) {
            taskService.complete(taskId);
        } else {
            // 添加审批意见
            if (variables.get("comment") != null) {
                taskService.addComment(taskId, processInstanceId, (String) variables.get("comment"));
                // 移除审批意见
                variables.remove("comment");
            }
            // 流程变量可以在流程实例级别传播
            taskService.complete(taskId, variables);
        }
        return AjaxResult.success();
    }
流程跳转
     @GetMapping(value = "/jump/{taskId}/{sid}")
    @ResponseBody
    public AjaxResult jump(@PathVariable String taskId, @PathVariable String sid) {
        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        // 寻找流程实例当前任务的activeId
        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
        String activityId = execution.getActivityId();
        // 当前节点
        FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId);
        // 目标节点
        FlowNode targetNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(sid);
        // 创建连接线
        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newFlow");
        newSequenceFlow.setSourceFlowElement(currentNode);
        newSequenceFlow.setTargetFlowElement(targetNode);
        newSequenceFlowList.add(newSequenceFlow);
        // 备份原有方向
        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
        oriSequenceFlows.addAll(dataflows);
        // 清空原有方向
        currentNode.getOutgoingFlows().clear();
        // 设置新方向
        currentNode.setOutgoingFlows(newSequenceFlowList);
        // 完成当前任务
        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "跳转节点");
        taskService.complete(taskId);
        // 恢复原有方向
        currentNode.setOutgoingFlows(oriSequenceFlows);
        return AjaxResult.success();
    }
强制结束流程
     @GetMapping(value = "/forceEnd/{taskId}")
    @ResponseBody
    public AjaxResult forceEnd(@PathVariable String taskId) {
        Task t = taskService.createTaskQuery().taskId(taskId).singleResult();
        String processDefinitionId = runtimeService.createProcessInstanceQuery().processInstanceId(t.getProcessInstanceId()).singleResult().getProcessDefinitionId();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        // 寻找流程实例当前任务的activeId
        Execution execution = runtimeService.createExecutionQuery().executionId(t.getExecutionId()).singleResult();
        String activityId = execution.getActivityId();
        FlowNode currentNode = (FlowNode)bpmnModel.getMainProcess().getFlowElement(activityId);
        // 创建结束节点和连接线
        EndEvent end = new EndEvent();
        end.setName("强制结束");
        end.setId("forceEnd");
        List<SequenceFlow> newSequenceFlowList = new ArrayList<SequenceFlow>();
        SequenceFlow newSequenceFlow = new SequenceFlow();
        newSequenceFlow.setId("newFlow");
        newSequenceFlow.setSourceFlowElement(currentNode);
        newSequenceFlow.setTargetFlowElement(end);
        newSequenceFlowList.add(newSequenceFlow);
        // 备份原有方向
        List<SequenceFlow> dataflows = currentNode.getOutgoingFlows();
        List<SequenceFlow> oriSequenceFlows = new ArrayList<SequenceFlow>();
        oriSequenceFlows.addAll(dataflows);
        // 清空原有方向
        currentNode.getOutgoingFlows().clear();
        // 设置新方向
        currentNode.setOutgoingFlows(newSequenceFlowList);
        // 完成当前任务
        taskService.addComment(taskId, t.getProcessInstanceId(), "comment", "撤销流程");
        taskService.complete(taskId);
        // 恢复原有方向,避免影响其他流程实例
        currentNode.setOutgoingFlows(oriSequenceFlows);
        return AjaxResult.success();
    }
查看进度
 // 查看当前活动任务(可能当前流程实例有多个任务)
List<Task> tasks =  taskService.createTaskQuery().processInstanceId(p.getProcessInstanceId()).list();
if (tasks.size() > 0) {
    String taskName = "";
    String assignee = "";
    for (Task t : tasks) {
        taskName += t.getName() + ",";
        assignee += t.getAssignee() + ",";
    }
    // 去掉最后一个逗号
    taskName = taskName.substring(0, taskName.length() -1);
    assignee = assignee.substring(0, assignee.length() -1);
    // 设置当前任务
    info.setCurrentTask(taskName);
    info.setAssignee(assignee);
}

 

SpringBoot 整合Activity7

引入依赖

注:引入依赖后启动项目会自动生成相对应的表

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <version>7.1.0.M6</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

 禁用security框架

// 禁用SpringSecurity
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
public class ActivitiApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActivitiApplication.class, args);
    }

}

控制台打印SQL语句

logging:
  level:
    org.activiti.engine.impl.persistence.entity: debug

 

遇到的坑

流程设计器不兼容

https://www.cnblogs.com/ReturnOfTheKing/p/18198068

 

 

参考链接

【1】idea的activiti插件

 
posted @   先娶国王后取经  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击右上角即可分享
微信分享提示