springboot集成flowable

简介: springboot集成flowable

参考示例:RuoYi-flowable: 🌟 基于RuoYi-vue + flowable 6.7.2 的工作流管理 右上角点个 star、fork 🌟 持续关注更新哟 农业认养商城系统:https://gitee.com/tony2y/smart-breed 智慧景区管理系统 :https://gitee.com/tony2y/scenic-spot
————————————————

                        版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                    

原文链接:https://blog.csdn.net/weixin_41037490/article/details/130063627
先上图

1.0接入项目目录 image.png
2.0 项目集成配置

2.1 流程模型图

文件名称:demo-1.8.xml
<?xml version="1.0" encoding="UTF-8"?>

<startEvent id="start_event" name="开始">
  <outgoing>Flow_0af0rkc</outgoing>
</startEvent>
<userTask id="Activity_0bmjsnr" name="发起" flowable:userType="assignee" flowable:dataType="dynamic" flowable:assignee="${assignee0}">
  <documentation>用户发起</documentation>
  <extensionElements>
    <flowable:taskListener class="com.ruoyi.flowable.listener.FlowTaskServerListener" event="create" />
  </extensionElements>
  <incoming>Flow_0af0rkc</incoming>
  <incoming>Flow_02hyd40</incoming>
  <incoming>Flow_10h45lr</incoming>
  <outgoing>Flow_189un8r</outgoing>
</userTask>
<sequenceFlow id="Flow_0af0rkc" sourceRef="start_event" targetRef="Activity_0bmjsnr" />
<userTask id="Activity_0svderh" name="上级组织处理" flowable:userType="assignee" flowable:dataType="dynamic" flowable:assignee="${assignee1}">
  <extensionElements>
    <flowable:executionListener class="com.ruoyi.flowable.listener.FlowExecutionStopListener" event="end" />
  </extensionElements>
  <incoming>Flow_1s8wcin</incoming>
  <incoming>Flow_022awso</incoming>
  <outgoing>Flow_10r6g5h</outgoing>
  <outgoing>Flow_02hyd40</outgoing>
</userTask>
<endEvent id="Event_1lkkjby" name="结束">
  <incoming>Flow_10r6g5h</incoming>
</endEvent>
<sequenceFlow id="Flow_10r6g5h" name="" sourceRef="Activity_0svderh" targetRef="Event_1lkkjby">
  <conditionExpression xsi:type="tFormalExpression">${isTopReturn==fase}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_02hyd40" name="退回" sourceRef="Activity_0svderh" targetRef="Activity_0bmjsnr">
  <conditionExpression xsi:type="tFormalExpression">${isTopReturn==true}</conditionExpression>
</sequenceFlow>
<exclusiveGateway id="Gateway_16yvw2l" name="判断同级">
  <extensionElements />
  <incoming>Flow_189un8r</incoming>
  <outgoing>Flow_1s8wcin</outgoing>
  <outgoing>Flow_0rn1sdw</outgoing>
</exclusiveGateway>
<sequenceFlow id="Flow_1s8wcin" name="上级组织直接处理" sourceRef="Gateway_16yvw2l" targetRef="Activity_0svderh">
  <conditionExpression xsi:type="tFormalExpression">${isAdmin==false}</conditionExpression>
</sequenceFlow>
<userTask id="Activity_11ipkd6" name="同级管理员" flowable:userType="assignee" flowable:dataType="dynamic" flowable:assignee="${assignee2}">
  <extensionElements />
  <incoming>Flow_0rn1sdw</incoming>
  <outgoing>Flow_022awso</outgoing>
  <outgoing>Flow_10h45lr</outgoing>
</userTask>
<sequenceFlow id="Flow_0rn1sdw" name="提交" sourceRef="Gateway_16yvw2l" targetRef="Activity_11ipkd6">
  <extensionElements>
    <flowable:executionListener class="com.ruoyi.flowable.listener.FlowExecutionListener" event="start" />
  </extensionElements>
  <conditionExpression xsi:type="tFormalExpression">${isAdmin==true}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_022awso" name="" sourceRef="Activity_11ipkd6" targetRef="Activity_0svderh" />
<sequenceFlow id="Flow_10h45lr" name="退回" sourceRef="Activity_11ipkd6" targetRef="Activity_0bmjsnr" />
<sequenceFlow id="Flow_189un8r" name="" sourceRef="Activity_0bmjsnr" targetRef="Gateway_16yvw2l" />


<bpmndi:BPMNDiagram id="BPMNDiagram_flow">

<bpmndi:BPMNPlane id="BPMNPlane_flow" bpmnElement="flow_7cum4yyi">
  <bpmndi:BPMNShape id="BPMNShape_start_event" bpmnElement="start_event" bioc:stroke="">
    <omgdc:Bounds x="-125" y="185" width="30" height="30" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="-122" y="222" width="22" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNShape>
  <bpmndi:BPMNShape id="Activity_0bmjsnr_di" bpmnElement="Activity_0bmjsnr">
    <omgdc:Bounds x="-20" y="160" width="100" height="80" />
    <bpmndi:BPMNLabel />
  </bpmndi:BPMNShape>
  <bpmndi:BPMNShape id="Activity_0svderh_di" bpmnElement="Activity_0svderh">
    <omgdc:Bounds x="390" y="160" width="100" height="80" />
    <bpmndi:BPMNLabel />
  </bpmndi:BPMNShape>
  <bpmndi:BPMNShape id="Event_1lkkjby_di" bpmnElement="Event_1lkkjby">
    <omgdc:Bounds x="582" y="182" width="36" height="36" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="589" y="225" width="22" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNShape>
  <bpmndi:BPMNShape id="Gateway_16yvw2l_di" bpmnElement="Gateway_16yvw2l" isMarkerVisible="true">
    <omgdc:Bounds x="135" y="175" width="50" height="50" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="137" y="153" width="45" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNShape>
  <bpmndi:BPMNShape id="Activity_11ipkd6_di" bpmnElement="Activity_11ipkd6">
    <omgdc:Bounds x="230" y="160" width="100" height="80" />
    <bpmndi:BPMNLabel />
  </bpmndi:BPMNShape>
  <bpmndi:BPMNEdge id="Flow_0af0rkc_di" bpmnElement="Flow_0af0rkc">
    <di:waypoint x="-95" y="200" />
    <di:waypoint x="-20" y="200" />
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_10r6g5h_di" bpmnElement="Flow_10r6g5h">
    <di:waypoint x="490" y="200" />
    <di:waypoint x="582" y="200" />
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_02hyd40_di" bpmnElement="Flow_02hyd40">
    <di:waypoint x="440" y="160" />
    <di:waypoint x="440" y="50" />
    <di:waypoint x="30" y="50" />
    <di:waypoint x="30" y="160" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="224" y="32" width="22" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_1s8wcin_di" bpmnElement="Flow_1s8wcin">
    <di:waypoint x="160" y="225" />
    <di:waypoint x="160" y="310" />
    <di:waypoint x="440" y="310" />
    <di:waypoint x="440" y="240" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="256" y="292" width="89" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_0rn1sdw_di" bpmnElement="Flow_0rn1sdw">
    <di:waypoint x="185" y="200" />
    <di:waypoint x="230" y="200" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="197" y="182" width="22" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_022awso_di" bpmnElement="Flow_022awso">
    <di:waypoint x="330" y="200" />
    <di:waypoint x="390" y="200" />
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_10h45lr_di" bpmnElement="Flow_10h45lr">
    <di:waypoint x="280" y="160" />
    <di:waypoint x="280" y="100" />
    <di:waypoint x="30" y="100" />
    <di:waypoint x="30" y="160" />
    <bpmndi:BPMNLabel>
      <omgdc:Bounds x="144" y="82" width="22" height="14" />
    </bpmndi:BPMNLabel>
  </bpmndi:BPMNEdge>
  <bpmndi:BPMNEdge id="Flow_189un8r_di" bpmnElement="Flow_189un8r">
    <di:waypoint x="80" y="200" />
    <di:waypoint x="135" y="200" />
  </bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>

</bpmndi:BPMNDiagram>

2.2 接入业务核心代码

 启动自己配置的流程实例

/**

 * 根据流程定义ID启动流程实例
 *
 * @param procDefId 流程模板ID
 * @param variables 流程变量
 * @return
 */
@Override
public AjaxResult startProcessInstanceById(String procDefId, Map<String, Object> variables) {
    try {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(procDefId)
                .latestVersion().singleResult();
        if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) {
            return AjaxResult.error("流程已被挂起,请先激活流程");
        }
        // 设置流程发起人Id到流程中
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        identityService.setAuthenticatedUserId(sysUser.getUserId().toString());
        variables.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUserId());
        runtimeService.startProcessInstanceById(procDefId, variables);
        return AjaxResult.success("流程启动成功");
    } catch (Exception e) {
        e.printStackTrace();
        return AjaxResult.error("流程启动错误");
    }
}

2.2.1 流程发起
@Transactional
@Override
public AjaxResult flowStart(StartProcessPayloadVo startProcessPayloadVo/*, String procDefId*/) {

    String businessModeUrl = startProcessPayloadVo.getBusinessModeUrl();
    String businessModeCode = sysConfigService.selectConfigByKey(businessModeUrl);
    TMisFunction tMisFunction = new TMisFunction();

    String[] split = startProcessPayloadVo.getBusinessModeUrl().split("/");
    String funNo = split[split.length - 1].substring(1, split[split.length - 1].length());
    tMisFunction.setCtFunNo(funNo);
    List<TMisFunction> tMisFunctionList = misFunctionMapper.selectTMisFunctionList(tMisFunction);
    if (tMisFunctionList.size() < 1) {
        return AjaxResult.error("功能号 businessModeCode 无效请仔细检查!");
    }
    String procDefId = "";
    try {
        startProcessPayloadVo.setBusinessModeCode(tMisFunctionList.get(0).getCtFunNo());
        procDefId = JSON.parseObject(tMisFunctionList.get(0).getCtFlowConfig(), HashMap.class).get("nowProcdefIId").toString();
    } catch (NullPointerException e) {
        return AjaxResult.error("功能号 businessModeCode 无效请仔细检查!");
    }


    //校验单据已经审批中的拒绝发起审批
    // TODO checkbusinessKeyInFlowIng(businessModeCode,startProcessPayloadVo.getBusinessKey());
    //校验再次发起的单据进入流程前删除act_workflow_formdata  的原有的审批意见
    //TODO  delActWorkflowFormDataById(startProcessPayloadVo.getBusinessKey());

    //校验单据重复发起审批
    boolean isStart = checkbusinessKeyStartFlowIng(startProcessPayloadVo.getBusinessKey(), tMisFunctionList.get(0).getCtTable());
    if (true == isStart) {
        return AjaxResult.error("流程已经发起,请勿重复发起流程!");
    }

    DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String now = df.format(DateUtils.getNowDate());
    SysUser user = SecurityUtils.getLoginUser().getUser();
    Map<String, Object> variabes = new HashMap<>();
    variabes.put("assignee0", user.getUserId());
    variabes.put("assignee1", user.getUserId());
    variabes.put("assignee2", user.getUserId());//占位符 没有任何意义


    //发起流程  写入act业务
    //业务模块名称
    String businessModeName = tMisFunctionList.get(0).getCtFunName();

    try {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(startProcessPayloadVo.getBusinessKey())
                .latestVersion().singleResult();
        if (Objects.nonNull(processDefinition) && processDefinition.isSuspended()) {
            return AjaxResult.error("流程已被挂起,请先激活流程");
        }
        // 设置流程发起人Id到流程中
        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
        identityService.setAuthenticatedUserId(sysUser.getUserId().toString());
        variabes.put(ProcessConstants.PROCESS_INITIATOR, sysUser.getUserId());
        runtimeService.startProcessInstanceById(procDefId, startProcessPayloadVo.getBusinessKey(), variabes);//启动流程实例 业务单据id  流程变量

        List<Execution> list1 = runtimeService.createExecutionQuery().processInstanceBusinessKey(startProcessPayloadVo.getBusinessKey()).list();
        String processInstanceId = list1.get(list1.size() - 1).getProcessInstanceId();

        List<Execution> list2 = runtimeService.createExecutionQuery().processInstanceId(processInstanceId).list();
        String execution_id = list2.get(list2.size() - 1).getId();

        //结束填报单据的节点
        Task task = taskService.createTaskQuery().executionId(execution_id).singleResult();
        FlowTaskVo flowTaskVo = new FlowTaskVo();
        flowTaskVo.setTaskId(task.getId());
        flowTaskVo.setComment("流程发起人默认同意");
        flowTaskService.complete(flowTaskVo);

        //在业务单据中 记录流程是否发起
        SysDeployFormMapper sysDeployFormMapper = ApplicationContextUtils.getBean(SysDeployFormMapper.class);
        String deploymentId = sysDeployFormMapper.selectGenericString("UPDATE " + tMisFunctionList.get(0).getCtTable() + " SET ct_state = 2 WHERE ct_id = '" + startProcessPayloadVo.getBusinessKey() + "';");
        //TODO 写入t_mis_sin
        return AjaxResult.success("流程启动成功");
    } catch (Exception e) {
        e.printStackTrace();
        return AjaxResult.error("流程启动错误");
    }
}

2.2.2 查询我发起的流程任务待办

/**

 * 我发起的流程
 *
 * @param queryVo 请求参数
 * @return
 */
@Override
public AjaxResult myProcess(FlowQueryVo queryVo) {
    Page<FlowTaskDto> page = new Page<>();
    Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
    HistoricProcessInstanceQuery historicProcessInstanceQuery = historyService.createHistoricProcessInstanceQuery()
            .startedBy(userId.toString())
            .orderByProcessInstanceStartTime()
            .desc();
    List<HistoricProcessInstance> historicProcessInstances = historicProcessInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
    page.setTotal(historicProcessInstanceQuery.count());
    List<FlowTaskDto> flowList = new ArrayList<>();
    List<FlowTaskDto> newFlowList = new ArrayList<>();
    for (HistoricProcessInstance hisIns : historicProcessInstances) {

        FlowTaskDto flowTask = new FlowTaskDto();
        flowTask.setCreateTime(hisIns.getStartTime());
        flowTask.setFinishTime(hisIns.getEndTime());
        flowTask.setProcInsId(hisIns.getId());

        // 计算耗时
        if (Objects.nonNull(hisIns.getEndTime())) {
            long time = hisIns.getEndTime().getTime() - hisIns.getStartTime().getTime();
            flowTask.setDuration(getDate(time));
        } else {
            long time = System.currentTimeMillis() - hisIns.getStartTime().getTime();
            flowTask.setDuration(getDate(time));
        }
        // 流程定义信息
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(hisIns.getProcessDefinitionId())
                .singleResult();
        flowTask.setDeployId(pd.getDeploymentId());
        flowTask.setProcDefName(pd.getName());
        flowTask.setProcDefVersion(pd.getVersion());
        flowTask.setCategory(pd.getCategory());
        flowTask.setProcDefVersion(pd.getVersion());
        // 当前所处流程
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(hisIns.getId()).list();
        if (CollectionUtils.isNotEmpty(taskList)) {
            flowTask.setTaskId(taskList.get(0).getId());
            flowTask.setTaskName(taskList.get(0).getName());
            if (StringUtils.isNotBlank(taskList.get(0).getAssignee())) {
                // 当前任务节点办理人信息
                //SysUser sysUser = sysUserService.selectUserById(Long.parseLong(taskList.get(0).getAssignee()));
                //多个办理人时
                String assignee = taskList.get(0).getAssignee();
                SysUser user = SecurityUtils.getLoginUser().getUser();
                String managementOrgLevel = user.getManagementOrgLevel();
                String deptIdSql = "select dept_id from t_dw_branch where ct_code_p2='" + managementOrgLevel + "';";
                SysDeployFormMapper sysDeployFormMapper = ApplicationContextUtils.getBean(SysDeployFormMapper.class);
                String deptId = sysDeployFormMapper.selectGenericString(deptIdSql);


                List<SysUser> sysUsersList = userMapper.selectUserListById("( " + assignee + " )");
             /*   if (Objects.nonNull(sysUser)) {
                    flowTask.setAssigneeId(sysUser.getUserId());
                    flowTask.setAssigneeName(sysUser.getNickName());
                }*/
                for (int i = 0; i < sysUsersList.size(); i++) {
                    FlowTaskDto newFlowTask = new FlowTaskDto();
                    BeanUtils.copyProperties(flowTask, newFlowTask);
                    newFlowTask.setAssigneeId(sysUsersList.get(i).getUserId());
                    newFlowTask.setAssigneeName(sysUsersList.get(i).getNickName());
                    newFlowList.add(newFlowTask);
                }

            }
        } else {
            List<HistoricTaskInstance> historicTaskInstance = historyService.createHistoricTaskInstanceQuery().processInstanceId(hisIns.getId()).orderByHistoricTaskInstanceEndTime().desc().list();
            flowTask.setTaskId(historicTaskInstance.get(0).getId());
            flowTask.setTaskName(historicTaskInstance.get(0).getName());
            if (StringUtils.isNotBlank(historicTaskInstance.get(0).getAssignee())) {
                // 当前任务节点办理人信息
                SysUser sysUser = sysUserService.selectUserById(Long.parseLong(historicTaskInstance.get(0).getAssignee()));
                if (Objects.nonNull(sysUser)) {
                    flowTask.setAssigneeId(sysUser.getUserId());
                    flowTask.setAssigneeName(sysUser.getNickName());
                    //flowTask.setAssigneeDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
                }
            }
        }
        // flowList.add(flowTask);
        flowList.addAll(newFlowList);
    }
    page.setRecords(flowList);
    return AjaxResult.success(page);
}

2.2.3 所有待办流程

/**
 * 代办任务列表
 * todo 这儿查询的数据  没有区分用户所属的  部门,待更改
 *
 * @param queryVo 请求参数
 * @return
 */
@Override
public AjaxResult todoList(FlowQueryVo queryVo) {
    Page<FlowTaskDto> page = new Page<>();
    // 只查看自己的数据
    SysUser sysUser = SecurityUtils.getLoginUser().getUser();
    //safeCandidateGroups,candidateGroup   候选组  里面的值 是角色id

    //代码原有
 /*   TaskQuery taskQuery = taskService.createTaskQuery()
            .active()
            .includeProcessVariables()
            .taskCandidateGroupIn(sysUser.getRoles().stream().map(role -> role.getRoleId().toString()).collect(Collectors.toList()))
            .taskCandidateOrAssigned(sysUser.getUserId().toString())
            .orderByTaskCreateTime().desc();*/

    //用户+部门 待办数据
    //用户+角色数据
    //用户在任何 管辖单位能看到的数据
    SysDeployFormMapper sysDeployFormMapper = ApplicationContextUtils.getBean(SysDeployFormMapper.class);
    String branchType = sysDeployFormMapper.selectGenericString("select ct_branch_category from t_dw_branch where dept_id='" + sysUser.getDeptId() + "';");
    TaskQuery taskQuery = null;

    if (PartyConstants.CATEGORY_COMMITTEE.equals(branchType)) {//上级组织能看到下级组织  提交的待办
        taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                .taskCandidateGroupIn(sysUser.getRoles().stream().map(role -> role.getRoleId().toString()).collect(Collectors.toList()))
                .taskCandidateOrAssigned(sysUser.getUserId().toString())
                .orderByTaskCreateTime().desc();
    } else {
        //用户+部门 待办数据
        taskQuery = taskService.createTaskQuery()
                .active()
                .includeProcessVariables()
                .taskOwner(sysUser.getDeptId().toString())
                .taskCandidateOrAssigned(sysUser.getUserId().toString())
                .orderByTaskCreateTime().desc();
    }

// TODO 传入名称查询不到数据?
// if (StringUtils.isNotBlank(queryVo.getName())){
// taskQuery.processDefinitionNameLike(queryVo.getName());
// }

    page.setTotal(taskQuery.count());
    List<Task> taskList = taskQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
    List<FlowTaskDto> flowList = new ArrayList<>();
    for (Task task : taskList) {
        FlowTaskDto flowTask = new FlowTaskDto();
        // 当前流程信息
        flowTask.setTaskId(task.getId());
        flowTask.setTaskDefKey(task.getTaskDefinitionKey());
        flowTask.setCreateTime(task.getCreateTime());
        flowTask.setProcDefId(task.getProcessDefinitionId());
        flowTask.setExecutionId(task.getExecutionId());
        flowTask.setTaskName(task.getName());
        // 流程定义信息
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId())
                .singleResult();
        flowTask.setDeployId(pd.getDeploymentId());
        flowTask.setProcDefName(pd.getName());
        flowTask.setProcDefVersion(pd.getVersion());
        flowTask.setProcInsId(task.getProcessInstanceId());

        // 流程发起人信息
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(task.getProcessInstanceId())
                .singleResult();
        SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
        flowTask.setStartUserId(startUser.getUserId().toString());
        flowTask.setStartUserName(startUser.getNickName());
        //flowTask.setStartDeptName(Objects.nonNull(startUser.getDept()) ? startUser.getDept().getDeptName() : "");
        flowList.add(flowTask);
    }

    page.setRecords(flowList);
    return AjaxResult.success(page);
}

2.2.4 所有已办任务

/**
 * 已办任务列表
 *
 * @param queryVo 请求参数
 * @return
 */
@Override
public AjaxResult finishedList(FlowQueryVo queryVo) {
    Page<FlowTaskDto> page = new Page<>();
    Long userId = SecurityUtils.getLoginUser().getUser().getUserId();
    HistoricTaskInstanceQuery taskInstanceQuery = historyService.createHistoricTaskInstanceQuery()
            .includeProcessVariables()
            .finished()
            .taskAssignee(userId.toString())
            .orderByHistoricTaskInstanceEndTime()
            .desc();
    List<HistoricTaskInstance> historicTaskInstanceList = taskInstanceQuery.listPage(queryVo.getPageSize() * (queryVo.getPageNum() - 1), queryVo.getPageSize());
    List<FlowTaskDto> hisTaskList = new ArrayList<>();
    for (HistoricTaskInstance histTask : historicTaskInstanceList) {
        FlowTaskDto flowTask = new FlowTaskDto();
        // 当前流程信息
        flowTask.setTaskId(histTask.getId());
        // 审批人员信息
        flowTask.setCreateTime(histTask.getCreateTime());
        flowTask.setFinishTime(histTask.getEndTime());
        flowTask.setDuration(getDate(histTask.getDurationInMillis()));
        flowTask.setProcDefId(histTask.getProcessDefinitionId());
        flowTask.setTaskDefKey(histTask.getTaskDefinitionKey());
        flowTask.setTaskName(histTask.getName());

        // 流程定义信息
        ProcessDefinition pd = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(histTask.getProcessDefinitionId())
                .singleResult();
        flowTask.setDeployId(pd.getDeploymentId());
        flowTask.setProcDefName(pd.getName());
        flowTask.setProcDefVersion(pd.getVersion());
        flowTask.setProcInsId(histTask.getProcessInstanceId());
        flowTask.setHisProcInsId(histTask.getProcessInstanceId());

        // 流程发起人信息
        HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(histTask.getProcessInstanceId())
                .singleResult();
        SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
        flowTask.setStartUserId(startUser.getNickName());
        flowTask.setStartUserName(startUser.getNickName());
        //flowTask.setStartDeptName(startUser.getDept().getDeptName());
        hisTaskList.add(flowTask);
    }
    page.setTotal(taskInstanceQuery.count());
    page.setRecords(hisTaskList);
    return AjaxResult.success(page);
}


2.2.5 流程流转 处理记录

/**
 * 流程历史流转记录
 *
 * @param procInsId 流程实例Id
 * @return
 */
@Override
public AjaxResult flowRecord(String procInsId, String deployId) {
    Map<String, Object> map = new HashMap<String, Object>();
    if (StringUtils.isNotBlank(procInsId)) {
        List<HistoricActivityInstance> list = historyService
                .createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .orderByHistoricActivityInstanceStartTime()
                .desc().list();
        List<FlowTaskDto> hisFlowList = new ArrayList<>();
        for (HistoricActivityInstance histIns : list) {
            // 展示开始节点

// if ("startEvent".equals(histIns.getActivityType())) {
// FlowTaskDto flowTask = new FlowTaskDto();
// // 流程发起人信息
// HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
// .processInstanceId(histIns.getProcessInstanceId())
// .singleResult();
// SysUser startUser = sysUserService.selectUserById(Long.parseLong(historicProcessInstance.getStartUserId()));
// flowTask.setTaskName(startUser.getNickName() + "(" + startUser.getDept().getDeptName() + ")发起申请");
// flowTask.setFinishTime(histIns.getEndTime());
// hisFlowList.add(flowTask);
// } else if ("endEvent".equals(histIns.getActivityType())) {
// FlowTaskDto flowTask = new FlowTaskDto();
// flowTask.setTaskName(StringUtils.isNotBlank(histIns.getActivityName()) ? histIns.getActivityName() : "结束");
// flowTask.setFinishTime(histIns.getEndTime());
// hisFlowList.add(flowTask);
// } else

            if (StringUtils.isNotBlank(histIns.getTaskId())) {
                FlowTaskDto flowTask = new FlowTaskDto();
                flowTask.setTaskId(histIns.getTaskId());
                flowTask.setTaskName(histIns.getActivityName());
                flowTask.setCreateTime(histIns.getStartTime());
                flowTask.setFinishTime(histIns.getEndTime());
                if (StringUtils.isNotBlank(histIns.getAssignee())) {
                    SysUser sysUser = sysUserService.selectUserById(Long.parseLong(histIns.getAssignee()));
                    if (sysUser != null) {
                        flowTask.setAssigneeId(sysUser.getUserId());
                        flowTask.setAssigneeName(sysUser.getNickName());
                    }
                    // flowTask.setDeptName(Objects.nonNull(sysUser.getDept()) ? sysUser.getDept().getDeptName() : "");
                }
                // 展示审批人员
                List<HistoricIdentityLink> linksForTask = historyService.getHistoricIdentityLinksForTask(histIns.getTaskId());
                StringBuilder stringBuilder = new StringBuilder();
                for (HistoricIdentityLink identityLink : linksForTask) {
                    // 获选人,候选组/角色(多个)
                    if ("candidate".equals(identityLink.getType())) {
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
                            stringBuilder.append(sysUser.getNickName()).append(",");
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                            stringBuilder.append(sysRole.getRoleName()).append(",");
                        }
                    } else if ("assignee".equals(identityLink.getType())) {//todo assignee uel表达式
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
                            //stringBuilder.append(sysUser.getNickName()).append(","); java.lang.NullPointerException: null
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                            stringBuilder.append(sysRole.getRoleName()).append(",");
                        }
                    } else if ("assignee0".equals(identityLink.getType())) {//todo assignee0 uel表达式
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
                            stringBuilder.append(sysUser.getNickName()).append(",");
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                            stringBuilder.append(sysRole.getRoleName()).append(",");
                        }
                    }/*else if("assignee1".equals(identityLink.getType())) {//todo assignee1 uel表达式
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
                            stringBuilder.append(sysUser.getNickName()).append(",");
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                            stringBuilder.append(sysRole.getRoleName()).append(",");
                        }
                    }else if("assignee3".equals(identityLink.getType())) {//todo assignee1 uel表达式   加签处理人
                        if (StringUtils.isNotBlank(identityLink.getUserId())) {
                            SysUser sysUser = sysUserService.selectUserById(Long.parseLong(identityLink.getUserId()));
                            stringBuilder.append(sysUser.getNickName()).append(",");
                        }
                        if (StringUtils.isNotBlank(identityLink.getGroupId())) {
                            SysRole sysRole = sysRoleService.selectRoleById(Long.parseLong(identityLink.getGroupId()));
                            stringBuilder.append(sysRole.getRoleName()).append(",");
                        }
                    }*/
                }
                if (StringUtils.isNotBlank(stringBuilder)) {
                    flowTask.setCandidate(stringBuilder.substring(0, stringBuilder.length() - 1));
                }

                //解决流程发起时  发起人为null
                SysUser user = SecurityUtils.getLoginUser().getUser();
                if (StringUtils.isEmpty(flowTask.getCandidate())) {
                    flowTask.setCandidate(user.getUserName());
                }

                flowTask.setDuration(histIns.getDurationInMillis() == null || histIns.getDurationInMillis() == 0 ? null : getDate(histIns.getDurationInMillis()));
                // 获取意见评论内容
                List<Comment> commentList = taskService.getProcessInstanceComments(histIns.getProcessInstanceId());
                commentList.forEach(comment -> {
                    if (histIns.getTaskId().equals(comment.getTaskId())) {
                        flowTask.setComment(FlowCommentDto.builder().type(comment.getType()).comment(comment.getFullMessage()).build());
                    }
                });
                hisFlowList.add(flowTask);
            }
        }
        map.put("flowList", hisFlowList);
    }
    //TODO 2023-03-23注释 第一次申请获取初始化表单
   /* if (StringUtils.isNotBlank(deployId)) {
        SysForm sysForm = sysInstanceFormService.selectSysDeployFormByDeployId(deployId);
        if (Objects.isNull(sysForm)) {
            return AjaxResult.error("请先配置流程表单");
        }
        map.put("formData", JSONObject.parseObject(sysForm.getFormContent()));
    }*/
    return AjaxResult.success(map);
}


2.2.6 流程节点 信息
/*

 * 流程节点信息
 * @param businessKey
 * @return
 */
@Override
public AjaxResult misFlowXmlAndNode(String businessKey, String funNo) {
    TMisFunction tMisFunction = new TMisFunction();
    tMisFunction.setCtFunNo(funNo);
    List<TMisFunction> tMisFunctionList = tMisFunctionMapper.selectTMisFunctionList(tMisFunction);
    if (tMisFunctionList.size() < 1) {
        return AjaxResult.error("业务功能号 funNo有误,请仔细检查!");
    }

    HashMap FlowConfhashMap = JSON.parseObject(tMisFunctionList.get(0).getCtFlowConfig(), HashMap.class);
    RepositoryService repositoryService = ApplicationContextUtils.getBean(RepositoryService.class);
    //流程定义id
    String nowProcdefIId = "";
    try {
        nowProcdefIId = FlowConfhashMap.get("nowProcdefIId").toString();
    } catch (NullPointerException e) {
        return AjaxResult.error("业务功能号 funNo有误,请仔细检查!");
    }

    String ctTable = tMisFunctionList.get(0).getCtTable();
    //校验单据 businessKey
    String ctId = sysDeptMapper.selectGenericString("SELECT ct_id FROM " + ctTable + " WHERE ct_id ='" + businessKey + "';");
    if (StringUtils.isEmpty(ctId) == true) {
        return AjaxResult.error("业务单据 businessKey 有误,请仔细检查!");
    }

    //流程定义id 流程部署id
    String deploymentId = repositoryService.createProcessDefinitionQuery()
            .processDefinitionId(FlowConfhashMap.get("nowProcdefIId").toString()).singleResult().getDeploymentId();
    HistoricProcessInstance historicProcessInstance = null;
    String procInsId = "";
    //流程没有发起 没有待办
    try {
        historicProcessInstance = historyService.createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey).singleResult();
        procInsId = historicProcessInstance.getId();
    } catch (NullPointerException e) {
        e.printStackTrace();
    }

    try {
        List<FlowViewerDto> flowViewerList = new ArrayList<>();
        // 获取已经完成的节点
        List<HistoricActivityInstance> listFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .finished()
                .list();

        // 保存已经完成的流程节点编号
        listFinished.forEach(s -> {
            FlowViewerDto flowViewerDto = new FlowViewerDto();
            flowViewerDto.setKey(s.getActivityId());
            flowViewerDto.setCompleted(true);
            flowViewerList.add(flowViewerDto);
        });

        // 获取代办节点
        List<HistoricActivityInstance> listUnFinished = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(procInsId)
                .unfinished()
                .list();

        // 保存需要代办的节点编号
        listUnFinished.forEach(s -> {
            FlowViewerDto flowViewerDto = new FlowViewerDto();
            flowViewerDto.setKey(s.getActivityId());
            flowViewerDto.setCompleted(false);
            flowViewerList.add(flowViewerDto);
        });
        Map<String, Object> result = new HashMap();
        // xmlData 数据
        ProcessDefinition newDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        InputStream inputStream = repositoryService.getResourceAsStream(newDefinition.getDeploymentId(), newDefinition.getResourceName());
        String xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
        // TODO 用户变量替换为当前登录人 ${assignee0}
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String xmlData1 = xmlData.replace("${assignee0}", user.getUserId().toString());
        result.put("nodeData", flowViewerList);
        result.put("xmlData", xmlData1);
        return AjaxResult.success(result);
    } catch (Exception e) {
        return AjaxResult.error("高亮历史任务失败");
    }
}

2.2.7 任务转办
/**

 * 任务转办
 * @param flowTaskVo
 */
@Transactional
@Override
public AjaxResult msiAssignTask(FlowTaskVo flowTaskVo) {
    SysUser sysUser = new SysUser();
    sysUser.setUserName(flowTaskVo.getAssignee());
    List<SysUser> sysUserList = userMapper.selectUserList(sysUser);
    if (sysUserList.size() < 1) {
        return AjaxResult.error("被提交的人员,没有维护系统账号信息!");
    }
    String nextTaskId = sysDeptMapper.selectGenericString("SELECT MAX(ID_) FROM act_hi_taskinst WHERE PROC_INST_ID_ in (SELECT id_ FROM act_hi_procinst WHERE BUSINESS_KEY_ = '" + flowTaskVo.getBusinessKey() + "');");
    SysUser user = SecurityUtils.getLoginUser().getUser();
    //设置提交人信息 提交人的人员id

    taskService.setAssignee(nextTaskId, sysUserList.get(0).getUserId().toString());
    //这里设置提交用户所属的组织
    taskService.setOwner(nextTaskId, user.getDeptId().toString());

// // 删除指派人重新指派
// taskService.deleteCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee());
// taskService.addCandidateUser(flowTaskVo.getTaskId(),flowTaskVo.getAssignee());
// // 如果要查询转给他人处理的任务,可以同时将OWNER进行设置:
// taskService.setOwner(flowTaskVo.getTaskId(), flowTaskVo.getAssignee());

    return AjaxResult.success();
}

2.2.8 执行监听器
import com.AAA.common.core.domain.entity.SysUser;
import com.AAA.common.utils.SecurityUtils;
import com.AAA.common.utils.bean.ApplicationContextUtils;
import com.AAA.flowable.factory.FlowServiceFactory;
import com.AAA.system.mapper.SysDeployFormMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.common.engine.api.delegate.Expression;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.ExecutionListener;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**

  • 执行监听器

*

  • 执行监听器允许在执行过程中执行Java代码。
  • 执行监听器可以捕获事件的类型:
  • 流程实例启动,结束
  • 输出流捕获
  • 获取启动,结束
  • 路由开始,结束
  • 中间事件开始,结束
  • 触发开始事件,触发结束事件

*

  • @author wangwei
  • @date 2023-03-27-15:26:00

*
*/
@Slf4j
@Component
public class FlowExecutionListener implements ExecutionListener {

/**
 * 流程设计器添加的参数
 */
private Expression param;

@Override
public void notify(DelegateExecution execution) {
    //log.info("执行监听器:{}", JSON.toJSONString(execution));   
    SysUser user = SecurityUtils.getLoginUser().getUser();
    RepositoryService repositoryService = ApplicationContextUtils.getBean(RepositoryService.class);
    SysDeployFormMapper sysDeployFormMapper = ApplicationContextUtils.getBean(SysDeployFormMapper.class);

    String deploymentIdSql = "SELECT DEPLOYMENT_ID_ FROM act_re_procdef WHERE id_ ='"+execution.getProcessDefinitionId()+"';";
    String deploymentId = sysDeployFormMapper.selectGenericString(deploymentIdSql);


    ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
    InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
    String xmlData = "";
    try {
        xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
    } catch (IOException e) {
        e.printStackTrace();
    }

    execution.setVariable("assignee1","0");
}

}

2.2.9 任务监听器

import com.alibaba.fastjson2.JSON;
import com.AAA.common.core.domain.entity.SysUser;
import com.AAA.common.exception.BaseException;
import com.AAA.common.utils.SecurityUtils;
import com.AAA.common.utils.bean.ApplicationContextUtils;
import com.AAA.flowable.factory.FlowServiceFactory;
import com.AAA.flowable.service.IFlowTaskService;
import com.AAA.system.domain.vo.SysDeptUserBranchVo;
import com.AAA.system.mapper.SysDeployFormMapper;
import com.AAA.system.mapper.SysDeptMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.delegate.TaskListener;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.task.api.Task;
import org.flowable.task.service.delegate.DelegateTask;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**

  • 任务监听器
  • create(创建):在任务被创建且所有的任务属性设置完成后才触发
  • assignment(指派):在任务被分配给某个办理人之后触发
  • complete(完成):在配置了监听器的上一个任务完成时触发
  • delete(删除):在任务即将被删除前触发。请注意任务由completeTask正常完成时也会触发

*/

/*

  • 服务直通 执行监听器
  • 在 开始节点开始执行
  • 在流程启动是设置 “上级组织”处理人,处理 在“上级组织” 流程步骤中的业务数据

*
*/

/*

  • @author wangwei
  • @date 2023-03-22 09:48:00

*/
@Slf4j
@Component
public class FlowTaskServerListener implements TaskListener {

@Override
public void notify(DelegateTask delegateTask) {
    SysUser user = SecurityUtils.getLoginUser().getUser();
    SysDeployFormMapper sysDeployFormMapper = ApplicationContextUtils.getBean(SysDeployFormMapper.class);
    SysDeptMapper sysDeptMapper = ApplicationContextUtils.getBean(SysDeptMapper.class);

    String managementOrg = user.getManagementOrgLevel();
    //上级组织的 ct_code_p2
    String ctCodeP1Sql = "select ct_code_p1 from t_dw_branch where ct_code_p2='"+managementOrg+"';";
    String ctCodeP1 = sysDeployFormMapper.selectGenericString(ctCodeP1Sql);
    StringBuffer stringBuffer = new StringBuffer();

    if("admin".equals(user.getUserName()) || "rootadmin".equals(user.getUserName())){//admin 特殊处理
        stringBuffer.append(user.getUserId());
    }else {
        SysDeptUserBranchVo sysDeptUserBranchVo = new SysDeptUserBranchVo();
        sysDeptUserBranchVo.setCtCodeP2(ctCodeP1);
        List<SysDeptUserBranchVo> sysDeptUserBranchVoList = sysDeptMapper.selectDeptUserpartymanBranch(sysDeptUserBranchVo);
        if(sysDeptUserBranchVoList.size()<1){
            throw new BaseException("上级组织  没有设置管理员,请运维人员设置管理员,再重新发起流程!");
        }
        //用户的部门id
        for (SysDeptUserBranchVo sysDeptUserBranchVo1:sysDeptUserBranchVoList){
            stringBuffer.append(sysDeptUserBranchVo1.getUserId()+",");
        }
    }

    String userIdList = stringBuffer.toString();
    String substring = userIdList.substring(0, userIdList.length() - 1);

    log.info("执行监听器:{}", JSON.toJSONString(delegateTask));
    // TODO  获取事件类型 delegateTask.getEventName(),可以通过监听器给任务执行人发送相应的通知消息

    String deploymentIdSql = "SELECT DEPLOYMENT_ID_ FROM act_re_procdef WHERE id_ ='"+delegateTask.getProcessDefinitionId()+"';";
    String deploymentId = sysDeployFormMapper.selectGenericString(deploymentIdSql);

    RepositoryService repositoryService = ApplicationContextUtils.getBean(RepositoryService.class);
    ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
    InputStream inputStream = repositoryService.getResourceAsStream(definition.getDeploymentId(), definition.getResourceName());
    String xmlData = "";
    try {
        xmlData = IOUtils.toString(inputStream, StandardCharsets.UTF_8.name());
    } catch (IOException e) {
        e.printStackTrace();
    }

    // TODO
    if ("发起".equals(delegateTask.getName()) || "create".equals(delegateTask.getEventName())) {
        delegateTask.setVariable("assignee1",substring);
        boolean isSubmit = xmlData.split("提交")[1].substring(0, 500).contains("isAdmin==true");
        if(isSubmit==true){
            delegateTask.setVariable("isAdmin", true, false);
            //delegateTask.setVariable("assignee2","9999");
            delegateTask.setAssignee(user.getUserId().toString());
        }
    } else {
        delegateTask.setVariable("isAdmin", false, false);
    }
}

}

3.0 数据库表,专业名词在这里不进行一一介绍, 请自行百度flowable官网

相关文章
|
5月前
|
Java
SpringBoot项目集成Lombok
SpringBoot项目集成Lombok
56 1
|
11月前
|
SQL 存储 Java
SpringBoot集成Liquibase
SpringBoot集成Liquibase
220 0
|
4月前
|
Java 数据库
Springboot集成SpringSecurity有源码
Springboot集成SpringSecurity有源码
|
SQL 运维 Java
SpringBoot集成Flyway
Flyway:官方解释:Flyway 将 DevOps 扩展到您的数据库,以加速软件交付并确保代码质量。从版本控制到持续交付,Flyway 以应用程序交付流程为基础,实现数据库部署自动化。 官方解释总是那么拗口和不说人话,当然通过加粗的关键字我们基本也能够了解到Flyway的功能特性。 通俗来说,Flyway可以作为数据库迁移工具服务到我们的应用程序升级发布流程中,减少人为处理sql脚本带来的繁琐和易出错问题。 例如,当我们的一个业务微服务从1.5.0升级到1.5.1的时候涉及到数据库的改动(DDL、DML)可以交给Flyway处理,我们无需关心。
888 0
|
SQL XML 存储
SpringBoot集成MybatisFlex
MyBatis-Flex 是一个优雅的 MyBatis 增强框架,它非常轻量、同时拥有极高的性能与灵活性。我们可以轻松的使用 Mybaits-Flex 链接任何数据库,其内置的 QueryWrapper 帮助我们极大的减少了 SQL 编写的工作的同时,减少出错的可能性。 MyBatis-Flex 能够极大地提高我们的开发效率和开发体验,让我们有更多的时间专注于业务上的事情。 通俗来说,Mybatis-Flex 就是对Mybatis 这个orm框架的扩展,地位类似与MybatisPlus。
1492 0
SpringBoot集成MybatisFlex
|
存储 druid Java
SpringBoot3集成Quartz
Quartz由Java编写的功能丰富的开源作业调度框架,可以集成到几乎任何Java应用程序中,并且能够创建多个作业调度;
197 0
|
缓存 监控 easyexcel
SpringBoot集成EasyExcel
简述在SpringBoot中集成EasyExcel完成数据导入功能。
384 0
SpringBoot集成EasyExcel
|
开发框架 Java API
SpringBoot集成knife4j
项目api编写有文档但是调试麻烦,需要借助postman/apipost等第三方工具,需要在开发框架中内置接口管理及调试功能增加开发便捷性
119 0
|
存储 XML 监控
Springboot整合Flowable流程引擎
Springboot整合Flowable流程引擎
|
XML 存储 JSON
SpringBoot集成Flowable实践
实际上是定义一个表单form表,一个deploy_form表。form存放动态表单json,deploy_form表建立流程模型部署信息与表单信息的关系。 流程模型挂载表单实际上就是往deply_form存放模型挂载的表单信息。 目的为了当通过模型启动流程实例的时候,将流程模型(部署id)对应的动态表单json取出来。
453 0
SpringBoot集成Flowable实践
下一篇
无影云桌面