一、流程審批后涉及到的表
| 表名 | 描述 |
|---|---|
| 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_表
二、流程示例
-
創(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>

流程圖
- 創(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"));
}
}
- 創(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è)試
- 提交采購(gòu)訂單的審批請(qǐng)求
http://localhost:7001/orderFlow/start/1/1
提交采購(gòu)訂單的審批請(qǐng)求
返回:
{
"msg": "3c6dc4b2-f30a-11e9-bc68-005056c00008:null",
"code": 0
}
- 獲取用戶(hù)的任務(wù)
http://localhost:7001/orderFlow/getTasks/1
獲取用戶(hù)的任務(wù)
返回:
{
"msg": "[Task[id=3c6dc4b2-f30a-11e9-bc68-005056c00008, name=訂單審批]]",
"code": 0
}
- 審批通過(guò)
http://localhost:7001/orderFlow/success/3c6dc4b2-f30a-11e9-bc68-005056c00008
審批通過(guò)
返回:
{
"msg": "流程審核通過(guò)!",
"code": 0
}
- 審批駁回
http://localhost:7001/orderFlow/fail/fac2256e-f30e-11e9-a987-005056c00008
任務(wù)ID: fac2256e-f30e-11e9-a987-005056c00008
審批駁回
返回:
{
"msg": "success",
"code": 0
}
- 生成流程圖
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)題
- "code":401,"error":"Unauthorized."
排除配置
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
- 流程文檔部署時(shí)沒(méi)生成流程圖片
如果流程文檔部署時(shí)沒(méi)生成流程圖片,且流程定義中包含必要的“圖形交換(diagram interchange)”信息,F(xiàn)lowable引擎會(huì)生成流程圖。
如果由于某種原因,不需要或不希望在部署時(shí)生成流程圖,可以在流程引擎配置中設(shè)置isCreateDiagramOnDeploy參數(shù):
<property name="createDiagramOnDeploy" value="false" />
- 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
- 沒(méi)有生成流程圖
bpmn 任務(wù)中沒(méi)有加入:
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://flowable.org/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>








