一、流程审批后涉及到的表
表名 | 描述 |
---|---|
act_fo_form_instance | 存储用户填充后表单实例信息,FORM_DEFINITION_ID_字段 2bb4ecac-cfb8-11e9-9f13-1a1dea14efe7 |
act_fo_form_resource | NAME_字段 form-2bb4ecac-cfb8-11e9-9f13-1a1dea14efe7 |
act_hi_actinst | 历史的流程实例 插入多条数据 |
act_hi_identitylink | 历史的流程运行过程中用户关系 插入多条数据 |
act_hi_procinst | 历史的流程实例 REV_ 1未完成 2已完成 |
act_hi_taskinst | 历史的任务实例 REV_ 1待认领 2等审批 3已审批 |
act_hi_varinst | 历史的流程运行中的变量信息 |
act_ru_actinst | 存储运行时节点信息 与act_hi_actinst同时存储 |
act_ru_execution | 执行实例表和act_run_task表,一起控制了用户任务的产生与完成等,当在并行网关和会签多实例时,它是会产生多个执行实例,IS_ACTIVE_这个字段的值都是为1,即激活状态,当每完成一个执行实例时,它会把IS_ACTIVE设为0,非激活状态,当所有执行实例完成后,它才会转移到历史,把这个多实例自动删除 |
act_ru_identitylink | 运行时用户关系 |
act_ru_task | 运行时任务表 |
act_ru_variable | 运行的流程中的变量信息 |
当流程全部走完后,act_ru_表的数据清空了,全部移到了act_hi_表
二、流程示例
-
创建流程图
创建OrderApproval.bpmn20.xml文件
- 创建委托
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
/**
* 批准委托类
*/
@Slf4j
public class ReviewApprove implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
//可以发送消息给某人
log.info("通过,userId是:{}",delegateExecution.getVariable("userId"));
}
}
import lombok.extern.slf4j.Slf4j;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.delegate.JavaDelegate;
/**
* 驳回委托类
*/
@Slf4j
public class ReviewNoApprove implements JavaDelegate {
@Override
public void execute(DelegateExecution delegateExecution) {
//可以发送消息给某人
log.info("拒绝,userId是:{}",delegateExecution.getVariable("userId"));
}
}
- 创建控制器
@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.提交采购订单的审批请求
*
* @param userId 用户id
*/
@PostMapping("/start/{userId}/{purchaseOrderId}")
public Result startFlow(@PathVariable String userId, @PathVariable String purchaseOrderId) {
HashMap map = new HashMap<>();
map.put("userId", userId);
map.put("purchaseOrderId", purchaseOrderId);
// 流程ID->OrderApproval
ProcessInstance processInstance =
runtimeService.startProcessInstanceByKey("OrderApproval", map);
String processId = processInstance.getId();
// 名称由布署时指定
String name = processInstance.getName();
log.info(processId + ":" + name);
return Result.ok(processId + ":" + name);
}
/**
* 2.获取用户的任务
*
* @param userId 用户id
*/
@GetMapping("/getTasks/{userId}")
public Result getTasks(@PathVariable String userId) {
List tasks = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
return Result.ok(tasks.toString());
}
/**
* 3.审批通过
*/
@PostMapping("/success/{taskId}")
public Result success(@PathVariable String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
return Result.error("流程不存在");
}
//通过审核
HashMap map = new HashMap<>();
// 在流程图中获取进行处理
map.put("approved", true);
taskService.complete(taskId, map);
return Result.ok("流程审核通过!");
}
/**
* 4.审批不通过
*/
@PostMapping("/fail/{taskId}")
public Result fail(@PathVariable String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
if (task == null) {
return Result.error("流程不存在");
}
//通过审核
HashMap map = new HashMap<>();
// 在流程图中获取进行处理
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) {
/**
* 获得当前活动的节点
*/
String processDefinitionId = "";
boolean isFinish = historyService.createHistoricProcessInstanceQuery().finished()
.processInstanceId(processId).count() > 0;
if (isFinish) {// 如果流程已经结束,则得到结束节点
HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery()
.processInstanceId(processId).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
} else {// 如果流程没有结束,则取当前活动节点
// 根据流程实例ID获得当前处于活动状态的ActivityId合集
ProcessInstance pi = runtimeService.createProcessInstanceQuery()
.processInstanceId(processId).singleResult();
processDefinitionId = pi.getProcessDefinitionId();
}
List highLightedActivitis = new ArrayList();
/**
* 获得活动的节点
*/
List highLightedActivitList = historyService.createHistoricActivityInstanceQuery().processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
for (HistoricActivityInstance tempActivity : highLightedActivitList) {
String activityId = tempActivity.getActivityId();
highLightedActivitis.add(activityId);
}
List flows = new ArrayList<>();
//获取流程图
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
// 注意:如果是PNG格式那么输出的是背景色是黑色,如果连接线上有字不容易看清楚。可以使用bmp
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);
}
}
}
三、运行测试
- 提交采购订单的审批请求
http://localhost:7001/orderFlow/start/1/1
返回:
{
"msg": "3c6dc4b2-f30a-11e9-bc68-005056c00008:null",
"code": 0
}
- 获取用户的任务
http://localhost:7001/orderFlow/getTasks/1
返回:
{
"msg": "[Task[id=3c6dc4b2-f30a-11e9-bc68-005056c00008, name=订单审批]]",
"code": 0
}
- 审批通过
http://localhost:7001/orderFlow/success/3c6dc4b2-f30a-11e9-bc68-005056c00008
返回:
{
"msg": "流程审核通过!",
"code": 0
}
- 审批驳回
http://localhost:7001/orderFlow/fail/fac2256e-f30e-11e9-a987-005056c00008
任务ID: fac2256e-f30e-11e9-a987-005056c00008
返回:
{
"msg": "success",
"code": 0
}
- 生成流程图
http://localhost:7001/orderFlow/processDiagram?processId=4fdcbade-f311-11e9-acac-005056c00008
processId: 为流程实例ID
四、事件监听器实现
事件监听器的唯一要求是实现org.flowable.engine.delegate.event.FlowableEventListener。
一个事件侦听器基类,可用于侦听特定类型的实体或所有实体的实体相关事件。它隐藏掉类型检查,并提供4种方法应覆盖:onCreate(..),onUpdate(..)并onDelete(..)创建实体时,更新或删除。
五、常见问题
- "code":401,"error":"Unauthorized."
排除配置
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
- 流程文档部署时没生成流程图片
如果流程文档部署时没生成流程图片,且流程定义中包含必要的“图形交换(diagram interchange)”信息,Flowable引擎会生成流程图。
如果由于某种原因,不需要或不希望在部署时生成流程图,可以在流程引擎配置中设置isCreateDiagramOnDeploy参数:
- Waiting for changelog lock....
数据库中执行:
SELECT `LOCKED` FROM workflow_flowable.ACT_DMN_DATABASECHANGELOGLOCK WHERE ID=1
UPDATE workflow_flowable.ACT_DMN_DATABASECHANGELOGLOCK
SET locked=0 WHERE ID=1
- 没有生成流程图
bpmn 任务中没有加入: