Flowable開(kāi)發(fā)--流程審批(五)

一、流程審批后涉及到的表

表名 描述
act_fo_form_instance 存儲(chǔ)用戶(hù)填充后表單實(shí)例信息,F(xiàn)ORM_DEFINITION_ID_字段 2bb4ecac-cfb8-11e9-9f13-1a1dea14efe7
act_fo_form_resource NAME_字段 form-2bb4ecac-cfb8-11e9-9f13-1a1dea14efe7
act_hi_actinst 歷史的流程實(shí)例 插入多條數(shù)據(jù)
act_hi_identitylink 歷史的流程運(yùn)行過(guò)程中用戶(hù)關(guān)系 插入多條數(shù)據(jù)
act_hi_procinst 歷史的流程實(shí)例 REV_ 1未完成 2已完成
act_hi_taskinst 歷史的任務(wù)實(shí)例 REV_ 1待認(rèn)領(lǐng) 2等審批 3已審批
act_hi_varinst 歷史的流程運(yùn)行中的變量信息
act_ru_actinst 存儲(chǔ)運(yùn)行時(shí)節(jié)點(diǎn)信息 與act_hi_actinst同時(shí)存儲(chǔ)
act_ru_execution 執(zhí)行實(shí)例表和act_run_task表,一起控制了用戶(hù)任務(wù)的產(chǎn)生與完成等,當(dāng)在并行網(wǎng)關(guān)和會(huì)簽多實(shí)例時(shí),它是會(huì)產(chǎn)生多個(gè)執(zhí)行實(shí)例,IS_ACTIVE_這個(gè)字段的值都是為1,即激活狀態(tài),當(dāng)每完成一個(gè)執(zhí)行實(shí)例時(shí),它會(huì)把IS_ACTIVE設(shè)為0,非激活狀態(tài),當(dāng)所有執(zhí)行實(shí)例完成后,它才會(huì)轉(zhuǎn)移到歷史,把這個(gè)多實(shí)例自動(dòng)刪除
act_ru_identitylink 運(yùn)行時(shí)用戶(hù)關(guān)系
act_ru_task 運(yùn)行時(shí)任務(wù)表
act_ru_variable 運(yùn)行的流程中的變量信息

當(dāng)流程全部走完后,act_ru_表的數(shù)據(jù)清空了,全部移到了act_hi_

二、流程示例

  1. 創(chuàng)建流程圖
    創(chuàng)建OrderApproval.bpmn20.xml文件


    創(chuàng)建文件

    創(chuàng)建文件

    改更擴(kuò)展名

    流程圖設(shè)計(jì)
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:flowable="http://flowable.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.flowable.org/processdef">
    <!--訂單審批,必須定義ID-->
    <process id="OrderApproval" name="訂單審批" isExecutable="true">
        <!--開(kāi)始事件-->
        <startEvent id="startEvent" name="采購(gòu)訂單"></startEvent>
        <!--流程-->
        <sequenceFlow id="sequenceFlow-3" sourceRef="startEvent" targetRef="approveTask"></sequenceFlow>
        <!--定義任務(wù) flowable:assignee 指定用戶(hù)ID-->
        <userTask id="approveTask" name="訂單審批" flowable:assignee="${userId}">
            <extensionElements>
                <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
            </extensionElements>
        </userTask>
        <!--定義網(wǎng)關(guān)-->
        <exclusiveGateway id="decision"></exclusiveGateway>
        <!--定義流程條件-->
        <sequenceFlow id="sequenceFlow-9" sourceRef="decision" targetRef="fail">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${!approved}]]></conditionExpression>
        </sequenceFlow>
        <!--定義任務(wù)->同意-->
        <serviceTask id="success" name="通過(guò)" flowable:class="com.xtsz.workflow.delegate.ReviewApprove"></serviceTask>
        <!--定義結(jié)束事件-->
        <endEvent id="approveEnd"></endEvent>
        <endEvent id="rejectEnd"></endEvent>
        <sequenceFlow id="sequenceFlow-e" sourceRef="success" targetRef="approveEnd"></sequenceFlow>
        <sequenceFlow id="sequenceFlow-1" sourceRef="fail" targetRef="rejectEnd"></sequenceFlow>
        <!--定義任務(wù)->拒絕-->
        <serviceTask id="fail" name="拒絕" flowable:class="com.xtsz.workflow.delegate.ReviewNoApprove"></serviceTask>
        <sequenceFlow id="sequenceFlow-5" sourceRef="approveTask" targetRef="decision"></sequenceFlow>
        <sequenceFlow id="sequenceFlow-c" sourceRef="decision" targetRef="success">
            <conditionExpression xsi:type="tFormalExpression"><![CDATA[${approved}]]></conditionExpression>
        </sequenceFlow>
    </process>
    <bpmndi:BPMNDiagram id="BPMNDiagram_OrderApproval">
        <bpmndi:BPMNPlane bpmnElement="OrderApproval" id="BPMNPlane_OrderApproval">
            <bpmndi:BPMNShape bpmnElement="startEvent" id="BPMNShape_startEvent">
                <omgdc:Bounds height="30.0" width="30.0" x="0.0" y="95.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="approveTask" id="BPMNShape_approveTask">
                <omgdc:Bounds height="60.0" width="100.0" x="75.0" y="75.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="decision" id="BPMNShape_decision">
                <omgdc:Bounds height="40.0" width="40.0" x="230.0" y="90.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="success" id="BPMNShape_success">
                <omgdc:Bounds height="60.0" width="100.0" x="320.0" y="0.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="approveEnd" id="BPMNShape_approveEnd">
                <omgdc:Bounds height="28.0" width="28.0" x="620.0" y="16.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="rejectEnd" id="BPMNShape_rejectEnd">
                <omgdc:Bounds height="28.0" width="28.0" x="570.0" y="175.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNShape bpmnElement="fail" id="BPMNShape_false">
                <omgdc:Bounds height="60.0" width="100.0" x="315.0" y="150.0"></omgdc:Bounds>
            </bpmndi:BPMNShape>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-5" id="BPMNEdge_sequenceFlow-5">
                <omgdi:waypoint x="174.95" y="105.0"></omgdi:waypoint>
                <omgdi:waypoint x="202.5" y="105.0"></omgdi:waypoint>
                <omgdi:waypoint x="202.5" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="230.0" y="110.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-c" id="BPMNEdge_sequenceFlow-c">
                <omgdi:waypoint x="269.9189252336448" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="282.0" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="282.0" y="30.000000000000004"></omgdi:waypoint>
                <omgdi:waypoint x="319.999999999994" y="30.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-1" id="BPMNEdge_sequenceFlow-1">
                <omgdi:waypoint x="414.95000000000005" y="180.0"></omgdi:waypoint>
                <omgdi:waypoint x="460.0" y="180.0"></omgdi:waypoint>
                <omgdi:waypoint x="460.0" y="189.0"></omgdi:waypoint>
                <omgdi:waypoint x="570.0" y="189.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-e" id="BPMNEdge_sequenceFlow-e">
                <omgdi:waypoint x="419.94999999998697" y="30.0"></omgdi:waypoint>
                <omgdi:waypoint x="620.0" y="30.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-3" id="BPMNEdge_sequenceFlow-3">
                <omgdi:waypoint x="29.949987029268733" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="52.5" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="52.5" y="105.0"></omgdi:waypoint>
                <omgdi:waypoint x="74.99999999999241" y="105.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
            <bpmndi:BPMNEdge bpmnElement="sequenceFlow-9" id="BPMNEdge_sequenceFlow-9">
                <omgdi:waypoint x="269.9189252336448" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="282.0" y="110.0"></omgdi:waypoint>
                <omgdi:waypoint x="282.0" y="180.0"></omgdi:waypoint>
                <omgdi:waypoint x="314.9999999999916" y="180.0"></omgdi:waypoint>
            </bpmndi:BPMNEdge>
        </bpmndi:BPMNPlane>
    </bpmndi:BPMNDiagram>
</definitions>
流程圖
  1. 創(chuàng)建委托
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;

/**
 * 批準(zhǔn)委托類(lèi)
 */
@Slf4j
public class ReviewApprove implements JavaDelegate {

    @Override
    public void execute(DelegateExecution delegateExecution) {
        //可以發(fā)送消息給某人
        log.info("通過(guò),userId是:{}",delegateExecution.getVariable("userId"));
    }
}

import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;

/**
 * 駁回委托類(lèi)
 */
@Slf4j
public class ReviewNoApprove implements JavaDelegate {
    @Override
    public void execute(DelegateExecution delegateExecution) {
        //可以發(fā)送消息給某人
        log.info("拒絕,userId是:{}",delegateExecution.getVariable("userId"));
    }
}


  1. 創(chuàng)建控制器
@RestController
@RequestMapping("/orderFlow")
@Slf4j
public class OrderFlowController {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private RuntimeService runtimeService;
    @Autowired
    private TaskService taskService;
    @Autowired
    private HistoryService historyService;
    @Resource
    private ProcessEngine processEngine;

    /**
     * 1.提交采購(gòu)訂單的審批請(qǐng)求
     *
     * @param userId 用戶(hù)id
     */
    @PostMapping("/start/{userId}/{purchaseOrderId}")
    public Result startFlow(@PathVariable String userId, @PathVariable String purchaseOrderId) {
        HashMap<String, Object> map = new HashMap<>();
        map.put("userId", userId);
        map.put("purchaseOrderId", purchaseOrderId);
        // 流程ID->OrderApproval
        ProcessInstance processInstance =
                runtimeService.startProcessInstanceByKey("OrderApproval", map);
        String processId = processInstance.getId();
        // 名稱(chēng)由布署時(shí)指定
        String name = processInstance.getName();
        log.info(processId + ":" + name);
        return Result.ok(processId + ":" + name);
    }

    /**
     * 2.獲取用戶(hù)的任務(wù)
     *
     * @param userId 用戶(hù)id
     */
    @GetMapping("/getTasks/{userId}")
    public Result getTasks(@PathVariable String userId) {
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
        return Result.ok(tasks.toString());
    }

    /**
     * 3.審批通過(guò)
     */
    @PostMapping("/success/{taskId}")
    public Result success(@PathVariable String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return Result.error("流程不存在");
        }
        //通過(guò)審核
        HashMap<String, Object> map = new HashMap<>();
        // 在流程圖中獲取進(jìn)行處理
        map.put("approved", true);
        taskService.complete(taskId, map);
        return Result.ok("流程審核通過(guò)!");
    }

    /**
     * 4.審批不通過(guò)
     */
    @PostMapping("/fail/{taskId}")
    public Result fail(@PathVariable String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return Result.error("流程不存在");
        }
        //通過(guò)審核
        HashMap<String, Object> map = new HashMap<>();
        // 在流程圖中獲取進(jìn)行處理
        map.put("approved", false);
        taskService.complete(taskId, map);
        return Result.ok();
    }

    /**
     * 5. 生成流程圖
     *
     * @param httpServletResponse
     * @param processId
     * @throws Exception
     */
    @PostMapping(value = "processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) {
        /**
         * 獲得當(dāng)前活動(dòng)的節(jié)點(diǎn)
         */
        String processDefinitionId = "";
        boolean isFinish = historyService.createHistoricProcessInstanceQuery().finished()
                .processInstanceId(processId).count() > 0;
        if (isFinish) {// 如果流程已經(jīng)結(jié)束,則得到結(jié)束節(jié)點(diǎn)
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {// 如果流程沒(méi)有結(jié)束,則取當(dāng)前活動(dòng)節(jié)點(diǎn)
            // 根據(jù)流程實(shí)例ID獲得當(dāng)前處于活動(dòng)狀態(tài)的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        List<String> highLightedActivitis = new ArrayList<String>();

        /**
         * 獲得活動(dòng)的節(jié)點(diǎn)
         */
        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<>();
        //獲取流程圖
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();

        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        // 注意:如果是PNG格式那么輸出的是背景色是黑色,如果連接線上有字不容易看清楚??梢允褂胋mp
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png", 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) {
            log.error("操作異常", e);
        } finally {
            IOUtils.closeQuietly(out);
            IOUtils.closeQuietly(in);
        }
    }
}

三、運(yùn)行測(cè)試

  1. 提交采購(gòu)訂單的審批請(qǐng)求
    http://localhost:7001/orderFlow/start/1/1
    提交采購(gòu)訂單的審批請(qǐng)求

    返回:
{
    "msg": "3c6dc4b2-f30a-11e9-bc68-005056c00008:null",
    "code": 0
}
  1. 獲取用戶(hù)的任務(wù)
    http://localhost:7001/orderFlow/getTasks/1
    獲取用戶(hù)的任務(wù)

    返回:
{
    "msg": "[Task[id=3c6dc4b2-f30a-11e9-bc68-005056c00008, name=訂單審批]]",
    "code": 0
}
  1. 審批通過(guò)
    http://localhost:7001/orderFlow/success/3c6dc4b2-f30a-11e9-bc68-005056c00008
    審批通過(guò)

    返回:
{
    "msg": "流程審核通過(guò)!",
    "code": 0
}
  1. 審批駁回
    http://localhost:7001/orderFlow/fail/fac2256e-f30e-11e9-a987-005056c00008
    任務(wù)ID: fac2256e-f30e-11e9-a987-005056c00008
    審批駁回

    返回:
{
    "msg": "success",
    "code": 0
}
  1. 生成流程圖
    http://localhost:7001/orderFlow/processDiagram?processId=4fdcbade-f311-11e9-acac-005056c00008
    processId: 為流程實(shí)例ID
    生成流程圖

四、事件監(jiān)聽(tīng)器實(shí)現(xiàn)

事件監(jiān)聽(tīng)器的唯一要求是實(shí)現(xiàn)org.flowable.engine.delegate.event.FlowableEventListener。
一個(gè)事件偵聽(tīng)器基類(lèi),可用于偵聽(tīng)特定類(lèi)型的實(shí)體或所有實(shí)體的實(shí)體相關(guān)事件。它隱藏掉類(lèi)型檢查,并提供4種方法應(yīng)覆蓋:onCreate(..),onUpdate(..)并onDelete(..)創(chuàng)建實(shí)體時(shí),更新或刪除。

五、常見(jiàn)問(wèn)題

  1. "code":401,"error":"Unauthorized."
    排除配置
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
  1. 流程文檔部署時(shí)沒(méi)生成流程圖片
    如果流程文檔部署時(shí)沒(méi)生成流程圖片,且流程定義中包含必要的“圖形交換(diagram interchange)”信息,F(xiàn)lowable引擎會(huì)生成流程圖。
    如果由于某種原因,不需要或不希望在部署時(shí)生成流程圖,可以在流程引擎配置中設(shè)置isCreateDiagramOnDeploy參數(shù):
<property name="createDiagramOnDeploy" value="false" />
  1. Waiting for changelog lock....
    數(shù)據(jù)庫(kù)中執(zhí)行:
SELECT `LOCKED` FROM workflow_flowable.ACT_DMN_DATABASECHANGELOGLOCK WHERE ID=1

UPDATE workflow_flowable.ACT_DMN_DATABASECHANGELOGLOCK 
SET locked=0 WHERE ID=1
  1. 沒(méi)有生成流程圖
    bpmn 任務(wù)中沒(méi)有加入:
  <extensionElements>
      <modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
 </extensionElements>
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容