本文通过申请发工资的业务场景来介绍使用工作流的全流程,包括画流程图,设置属性,以及代码编写
使用工作流大致分为四步
第一步:根据自己的业务画好流程图
第二步:设置流程图的属性和变量,保存模型
第三步:部署画好的流程图(发布)
第四步:根据业务和流程图写一些服务和监听器
这里主要介绍以下几个任务的使用
1.用户任务的分配和提交
2.服务任务的使用
3.中间信号捕捉事件的触发
4.排他网关的使用
5.通过设置流程变量,实现流程的不同流转
设置流程的唯一标识为payrollApplication也就是模型KEY,后续部署和启动都会用到
设置通过的流转条件为${approval==‘pass’}其中approval为变量名称,pass为变量值,工作流会自动解析表达式进行判断
设置不通过的流转条件为${approval==‘notPass’}
设置打款成功的流转条件为${payment == ‘success’}
设置打款失败的流转条件为${payment == ‘fail’}
主要用于接收银行打款处理通知,未通知会一直停留在中间信号接收事件节点上
设置信号引用为方才设置的信号定义
设置审批人为${Assignee},通过设置变量Assignee,动态设置审批人
启动流程实例并跟业务ID关联,并设置流程变量
1.processDefinitionKey 要启动的流程模型KEY (本次演示场景为payrollApplication)
2.businessKey 业务标识,跟流程进行关联,不需要可不填
3.variables 流程变量,启动流程时设置的变量,类型为Map
/**
* 启动流程实例并跟业务ID关联,并设置流程变量
* @param processDefinitionKey 流程模型KEY
* @param businessKey 业务ID跟流程进行关联
* @param variables 流程变量
* @return 流程实例ID
*/
public string startProcessByBusinessKey(String processDefinitionKey, String businessKey , Map<String,Object> variables) {
// 启动流程实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey, variables);
logger.debug("流程实例ID:{},流程定义ID:{},业务标识:{}", instance.getId(), instance.getProcessDefinitionId(), businessKey);
return instance.getId();
}
businessKey为启动时设置的业务标识,不需要可不填
userId为启动流程时设置的流程变量Assignee的值
approval为审批结果值为pass或者notPass
/**
* 提交用户任务
* @param businessKey 业务ID
* @param userId 用户任务处理人ID
* @param approval 审批结果
* @return
*/
public String completeTaskByUserIdAndBusinessKey(String businessKey, String userId, String approval) {
// 获取流程实例ID
String processInstanceId = null;
// 需要处理的任务ID
String taskId = null;
// 查询该用户的所有任务
List<Task> taskList = taskService.createTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
if (null == taskList || taskList.isEmpty()) {
return "该用户没有分配任务!";
}
if (StringUtils.isBlank(businessKey)) {
// 有可能存在多个任务,实际需要根据业务特殊处理
taskId = taskList.get(0).getId();
// 获取流程实例ID
processInstanceId = taskList.get(0).getProcessInstanceId();
}else {
// 根据业务ID查找任务ID
for (Task task : taskList) {
// 获取流程实例ID
processInstanceId = task.getProcessInstanceId();
if (StringUtils.isNotBlank(processInstanceId)) {
// 获取流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
// 流程实例
if (null == processInstance) {
return "未查询到正在运行的流程实例!";
}
// 流程实例关联的业务ID
String processInstanceBusinessKey = processInstance.getBusinessKey();
// 流程实例关联的业务ID和该用户的业务ID
if (StringUtils.isNotBlank(processInstanceBusinessKey) && StringUtils.equals(processInstanceBusinessKey, businessKey)) {
taskId = task.getId();
break;
}
}
}
}
if (StringUtils.isBlank(taskId)) {
return "未查询到关联该业务的任务!";
}
// 设置变量 设置流条件,告诉工作流下一步的流转节点 审批通过或未通过
JSONObject variables = new JSONObject();
variables.put("approval", approval);
runtimeService.setVariables(processInstanceId, variables);
// 提交任务
taskService.complete(taskId, null);
return "提交任务成功";
}
BankPaymentTask 实现类必须实现JavaDelegate接口,工作流才会识别到
public class BankPaymentTask implements JavaDelegate, Serializable {
@Autowired
public RuntimeService runtimeService;
public static BankPaymentTask bankPaymentTask;
@PostConstruct //通过@PostConstruct实现初始化bean之前进行的操作
public void init() {
bankPaymentTask= this;
bankPaymentTask.runtimeService = this.runtimeService;
}
@Override
public void execute(DelegateExecution execution) {
// 获取流程实例变量
Map<String, Object> variables = runtimeService.getVariables(execution.getProcessInstanceId());
if (variables == null || variables.isEmpty()) {
log.error("variables不能为空!");
return;
}
if (variables.get("businessKey") == null) {
log.error("businessKey不能为空!");
return;
}
// 配合流程变量,使用http调用其他服务完成银行转账的操作
// JSONObject result = RestTemplateUtil.postForObject(paymentUrl, params, JSONObject.class);
// 设置流程变量
JSONObject variables = new JSONObject();
variables.put("xxx", "xxx");
runtimeService.setVariables(execution.getProcessInstanceId(), variables);
}
工作流执行到当前节点会暂停,待银行打款操作结果回调之后,触发中间信号捕获事件信号,根据打款结果设置流程变量值,完成流程流转
/**
* 发送触发信号并设置变量
* @param businessKey 业务ID
* @param signaler 信号
* @param payment 银行操作结果
* @return
*/
public String callback(String businessKey, String signaler, String payment) {
// 根据业务标识查询正在运行的流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
if (processInstance == null) {
return "没有正在进行的任务!";
}
// 流程实例ID
String processInstanceId = processInstance.getId();
// 查找是否有等待触发的信号
// 流程执行流 流程执行流和流程实例的关系:流程执行流表示流程实例中具体地执行路径,流程实例是一次工作流业务的数据实体
Execution executions = runtimeService.createExecutionQuery().processInstanceId(processInstanceId)
.signalEventSubscriptionName(signaler).singleResult();
if (executions == null) {
return "未查询到该信号事件!";
}
logger.debug("executionsId:{},processInstanceId:{}", executions.getId(), processInstanceId);
// 设置变量 设置流条件,告诉工作流下一步的流转节点
JSONObject variables = new JSONObject();
// payment为success或者fail
variables.put("payment", payment);
runtimeService.setVariables(processInstanceId, variables);
// 发送触发信号
runtimeService.signalEventReceived(signaler, executions.getId());
return "触发信号接收成功";
}