工作流SDK接口使用说明

1.需求场景

在涉及到工作流相关的业务场景时,业务数据和流程数据最好是要做到相互隔离,互不影响。因此,数据和逻辑之间,耦合度越低越好。工作流引擎作为一个独立的模块,要方便业务数据调用。

2.接口说明

启动一个流程,需要插入业务数据,也需要插入流程数据(包括流程日志、流程任务)。为了方便整合流程,流程引擎提供SDK接口调用。

流程主要有2个接口:启动流程和提交流程,其他的为辅助接口。

所有的接口功能,都封装在FlowUtil类中,提供静态方法调用。

2.1.启动流程

启动流程,只需要调用FlowUtil.startFlowInstance(NoCodeFlowParam flowParam)方法即可,传入NoCodeFlowParam对象参数,返回NoCodeResult对象。方法自动处理流程数据,如果传入了业务数据SQL语句,也会处理业务数据。

NoCodeFlowParam定义如下:

public class NoCodeFlowParam {
	private int flowId;
	private int dataId;
	private int userId;
	private int actionType;                    //操作类型
	private int nodeId;		//当前操作节点
	private int backNodeId;	//回退、拒绝、驳回后的节点
	private String nextNodeIds;	//下一节点
	private String tableName;    //业务数据库表名称
	private boolean executeSQL;		//是否执行更新或插入业务数据SQL
	private String sqlBusiness;                    //业务数据SQL
	private Object[] sqlParam;            //业务数据SQL参数
	private NoCodeFlowNode flowNode;		//当前流程节点
	private NoCodeFlowProcess flowProcess;        //处理日志
	private List flowTaskList;    //要发布的任务列表
	private int remarkField;		//备注关联字段id
	private int attachmentField;	//附件关联字段id
	private String flowRemark;		//备注信息
	private String flowAttachment;	//相关附件
}

在调用启动流程时,并不需要传入所有参数。参数说明如下:

  1. flowId。流程Id,必填。当前启动的是哪个流程。引擎会根据该Id值查找配置项。
  2. dataId。业务数据Id,视情况而定。如果自己单独处理了业务数据(新增业务数据),则需要传递dataId,以便引擎更新该业务数据的流程状态。如果需要引擎处理业务数据,则不需要传值。
  3. userId。当前操作的用户id,必填。一般从session中取值,获取当前用户Id。如果是APP等无状态接口,则通过接口用户验证取到用户Id值。
  4. actionType。操作类型,不用填。启动流程时,不需要传值。内部会固定为NoCodeFlowNode.NODE_TYPE_START,其值为1。提交流程时,则根据实际是什么操作,就传递什么值。各种操作类型,在NoCodeFlowNode中有定义。
  5. nodeId。当前操作的节点Id,不用填。启用流程会固定查找启动节点。
  6. backNodeId。回退节点,不用填。启动流程时,不会回退。
  7. nextNodeIds。下一个节点Id列表,不用填。内部会自动获取。
  8. tableName。业务数据库表名称,必填。引擎需要去更新业务数据的流程启动人、流程节点、流程状态数据。
  9. executeSQL。是否执行业务数据SQL,必填。设置为true后,引擎会执行业务数据的SQL语句(sqlBusiness和sqlParam)。会自动判断是insert还是update。
  10. sqlBusiness。业务SQL语句,视情况而定。如果需要引擎执行业务数据,则传递SQL语句给引擎执行。支持insert和update。如果是insert,则会把新增的数据id值,返回到NoCodeResult的data属性中。
  11. sqlParam。业务SQL语句配套的参数,根据sqlBusiness而定。
  12. flowNode。当前流程节点,不用填。如果是启动流程,引擎会自动查找开启节点;如果是提交流程,引擎会根据nodeId
  13. flowProcess。流程日志对象,不用填。引擎会自动构造。
  14. flowTaskList。流程任务对象列表,不用填。引擎会自动构造。
  15. remarkField。关联节点的备注字段,不用填。自动根据节点设置项来读取。
  16. attachmentField。关联节点的附件字段,不用填。自动根据节点设置项来读取。
  17. flowRemark。备注说明内容,视情况而定。需要存储到流程日志中。如果有,就赋值。
  18. flowAttachment。相关附件内容,视情况而定。需要存储在流程日志中。如果有,就赋值。

 

2.2.提交流程

提交流程,调用接口FlowUtil.submitFlowInstance(NoCodeFlowParam flowParam)方法,参数与返回值,类似于启动流程。

要传递的参数,与启动流程的区别如下。

  1. nodeId。节点Id,必填。当前提交的是哪个流程节点,必填。
  2. dataId。业务数据Id,必填。提交流程时,必然是有关联的业务数据。
  3. actionType。操作类型,必填。提交流程时,必然是选择某种操作。
  4. backNodeId。如果是回退操作类型,还需要传递选择的回退节点Id。

3.调用样例

3.1.启动流程

如果由工作流引擎来处理业务数据,则需要将插入业务数据的SQL语句以及SQL参数,传递到接口方法中。如下代码所示。

	//提交发起流程表单。添加业务表单数据,发起流程。
	public NoCodeResult submitFlowStart(HttpSession httpSession, Map mapRequestParam, int flowId) {
		if (!baseValidate(httpSession, mapRequestParam, flowId)) {
			return mResult;
		}

		//获取发起流程节点字段列表
		mListField = FlowService.getFlowStartPageFieldList(flowId);

		//将request的数据,存入字段列表
		setFieldValueFromRequestForSave();

		//验证字段数据
		if (!validateFieldValueForSave()) {
			return mResult;
		}

		//从session中获取当前用户id
		int userId = StringUtil.convertToInt(httpSession.getAttribute(NoCodeUser.SESSION_USERID));

		//保存业务数据的SQL和参数
		List sqlParam = genSqlParamForInsert(mListField);
		String sqlSave = genSqlQueryForDataInsert();

		//获取节点信息
		NoCodeFlowNode startNode = FlowService.getFlowStartNode(flowId);
		if (startNode == null) {
			mResult.setFailureInfo("没有找到启动节点信息");
			return mResult;
		}

		NoCodeFlowParam flowParam = new NoCodeFlowParam();
		flowParam.setTableName(mPage.getTableName());
		flowParam.setFlowId(flowId);
		flowParam.setUserId(userId);
		flowParam.setExecuteSQL(true);
		flowParam.setSqlBusiness(sqlSave);
		flowParam.setSqlParam(sqlParam.toArray());
		flowParam.setFlowNode(startNode);

		//设置备注说明与相关附件字段
		setRemarkAndAttachmentField(startNode, flowParam, mapRequestParam);


		//暂存数据后,启动新流程。启动成功后,会将新的流程实例id赋值到data属性中
		return FlowUtil.startFlowInstance(flowParam);
	}
 
  

3.2.提交流程

提交流程与启动流程类似,只需要多传递几个参数即可。


//确认流程提交。已经创建了流程,进行业务数据更新,以及流程状态更新。
public NoCodeResult submitFlowAction(HttpSession httpSession, Map mapRequestParam, int flowId, int nodeId, int dataId) {
	if (!baseValidate(httpSession, mapRequestParam, flowId, dataId)) {
		return mResult;
	}

	//获取操作类型
	int actionType = StringUtil.convertToInt(StringUtil.convertStringArrayToString(mapRequestParam.get("actionType")));
	if (actionType <= 0) {
		mResult.setFailureInfo("请选择操作类型");
		return mResult;
	}

	int backNodeId = StringUtil.convertToInt(StringUtil.convertStringArrayToString(mapRequestParam.get("backNodeId")));
	if (actionType == NoCodeFlowNode.NODE_ACTION_BACK && backNodeId <= 0) {
		mResult.setFailureInfo("退回操作未选择回退节点");
		return mResult;
	}

	//TODO 需要对当前节点类型进行判断,如果是驳回修改的,那么需要更新原始表单。

	//从session中获取当前用户id
	int userId = StringUtil.convertToInt(httpSession.getAttribute(NoCodeUser.SESSION_USERID));

	//获取当前节点的字段列表
	mListField = FlowService.getFlowActionPageFieldList(flowId, nodeId);
	if (mListField == null || mListField.size() == 0) {
		mResult.setSuccessInfo("无字段需要保存");
		return mResult;
	}
	//将request的数据,存入字段列表
	setFieldValueFromRequestForSave();

	//验证字段数据
	if (!validateFieldValueForSave()) {
		return mResult;
	}

	//保存业务数据的SQL和参数
	List sqlParam = genSqlParamForUpdate(mListField);
	String sqlSave = genSqlQueryForDataUpdate();

	//获取节点信息
	NoCodeFlowNode flowNode = FlowService.getFlowNode(flowId, nodeId);
	if (flowNode == null) {
		mResult.setFailureInfo("没有找到节点信息");
		return mResult;
	}

	NoCodeFlowParam flowParam = new NoCodeFlowParam();
	flowParam.setFlowId(flowId);
	flowParam.setUserId(userId);
	flowParam.setTableName(mPage.getTableName());
	flowParam.setNodeId(nodeId);
	flowParam.setBackNodeId(backNodeId);
	flowParam.setExecuteSQL(true);
	flowParam.setSqlBusiness(sqlSave);
	flowParam.setSqlParam(sqlParam.toArray());
	flowParam.setFlowNode(flowNode);
	flowParam.setDataId(dataId);
	flowParam.setActionType(actionType);

	//备注说明、相关附件信息
	//设置备注说明与相关附件字段
	setRemarkAndAttachmentField(flowNode, flowParam, mapRequestParam);

	//调用流程提交
	return FlowUtil.submitFlowInstance(flowParam);
}
 
  

 

3.3.节点定义

对节点进行定义,包含节点类型、状态、操作类型。

public class NoCodeFlowNode {
	//region 流程节点类型
	public final static int NODE_TYPE_START = 1;        //开始节点
	public final static int NODE_TYPE_END = 2;        //结束节点
	public final static int NODE_TYPE_SERIAL = 3;        //串行节点
	public final static int NODE_TYPE_BRANCH = 4;        //分支节点
	public final static int NODE_TYPE_AND_SINGLE = 5;        //并行单审节点
	public final static int NODE_TYPE_AND_MULTI = 6;        //并行多审节点
	public final static int NODE_TYPE_AND_ALL = 7;        //会签节点
	//endregion

	//region 流程节点操作类型
	public static final int NODE_ACTION_SAVE = 0;        //暂存
	public static final int NODE_ACTION_SUBMIT = 1;        //提交
	public static final int NODE_ACTION_CANCEL = 2;        //撤回
	public static final int NODE_ACTION_REJECT = 8;        //驳回修改
	public static final int NODE_ACTION_REFUSE = 9;        //审核拒绝
	public static final int NODE_ACTION_APPROVE = 10;        //审核通过
	public static final int NODE_ACTION_READ = 11;        //阅读
	public static final int NODE_ACTION_FORWARD = 12;        //转发
	public static final int NODE_ACTION_BACK = 49;        //退回
	public static final int NODE_ACTION_FREEZE = 50;        //冻结
	public static final int NODE_ACTION_UNFREEZE = 51;        //解冻
	public static final int NODE_ACTION_DELETE = 98;        //删除
	public static final int NODE_ACTION_ABANDON = 99;        //作废
	public static final int NODE_ACTION_FINISH = 100;        //完结
	//endregion

	//region 流程节点状态
	public static final int NODE_STATE_NO_SUBMIT = 0;        //未提交
	public static final int NODE_STATE_HAS_SUBMIT = 1;        //已提交
	public static final int NODE_STATE_CANCEL = 2;        //已撤回
	public static final int NODE_STATE_REJECT = 8;        //驳回修改
	public static final int NODE_STATE_REFUSE = 9;        //审核拒绝
	public static final int NODE_STATE_APPROVE = 10;        //审核通过
	public static final int NODE_STATE_READ = 11;        //已阅读
	public static final int NODE_STATE_FORWARD = 12;        //已转发
	public static final int NODE_STATE_BACK = 49;        //退回
	public static final int NODE_STATE_FREEZE = 50;        //已冻结
	public static final int NODE_STATE_UNFREEZE = 51;        //已解冻
	public static final int NODE_STATE_DELETE = 98;        //已删除
	public static final int NODE_STATE_ABANDON = 99;        //已作废
	public static final int NODE_STATE_FINISHED = 100;        //已完结
	//endregion
}

3.4.获取节点数据

辅助类FlowUtil中还封装了其他方法,以便方便的获取流程相关的数据。

主要就是获取流程节点类型、状态、操作类型的描述说明、显示样式颜色等。


public class FlowUtil {
	//region 节点状态、类型、动作,值与名称转换
	//获取节点值与名称的map表
	public static Map getNodeTypeMap() {
		Map mapNodeType = new LinkedHashMap<>();

		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_START, "开始节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_END, "结束节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_SERIAL, "串行节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_BRANCH, "分支节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_AND_SINGLE, "并行单审节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_AND_MULTI, "并行多审节点");
		mapNodeType.put(NoCodeFlowNode.NODE_TYPE_AND_ALL, "会签节点");

		return mapNodeType;
	}

	//根据节点类型值,获取节点名称
	public static String getNodeTypeName(int nodeType) {
		return getNodeTypeMap().get(nodeType);
	}

	//获取流程状态值与名称map表
	public static Map getNodeStateMap() {
		Map mapNodeState = new LinkedHashMap<>();

		mapNodeState.put(NoCodeFlowNode.NODE_STATE_NO_SUBMIT, "未提交");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_HAS_SUBMIT, "已提交");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_APPROVE, "已通过");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_REFUSE, "已拒绝");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_REJECT, "已驳回");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_CANCEL, "已撤回");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_READ, "已阅读");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_FORWARD, "已转发");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_BACK, "已退回");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_FREEZE, "已冻结");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_UNFREEZE, "已解冻");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_DELETE, "已删除");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_ABANDON, "已作废");
		mapNodeState.put(NoCodeFlowNode.NODE_STATE_FINISHED, "已完结");

		return mapNodeState;
	}

	//根据节点状态值,获取节点状态名称
	public static String getNodeStateName(int nodeState) {
		return getNodeStateMap().get(nodeState);
	}

	//获取操作类型值与名称map表
	public static Map getNodeActionMap() {
		Map mapNodeState = new LinkedHashMap<>();

		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_SAVE, " 暂存");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_SUBMIT, "提交");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_CANCEL, "撤回");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_APPROVE, "审核通过");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_REFUSE, "审核拒绝");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_REJECT, "驳回修改");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_FORWARD, "转发");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_READ, "阅读");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_BACK, "退回");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_FREEZE, "冻结");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_UNFREEZE, "解冻");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_DELETE, "删除");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_ABANDON, "作废");
		mapNodeState.put(NoCodeFlowNode.NODE_ACTION_FINISH, "完结");

		return mapNodeState;
	}

	//根据节点操作类型值,获取操作类型名称
	public static String getNodeActionName(int nodeAction) {
		return getNodeActionMap().get(nodeAction);
	}

	//根据节点动作,获取节点状态
	public static int getNodeStateByAction(int nodeAction) {
		switch (nodeAction) {
			case NoCodeFlowNode.NODE_ACTION_SAVE:    //暂存
				return NoCodeFlowNode.NODE_STATE_NO_SUBMIT;            //未提交
			case NoCodeFlowNode.NODE_ACTION_SUBMIT:    //提交
				return NoCodeFlowNode.NODE_STATE_HAS_SUBMIT;        //已提交
			case NoCodeFlowNode.NODE_ACTION_CANCEL:    //撤回
				return NoCodeFlowNode.NODE_STATE_CANCEL;            //已撤回
			case NoCodeFlowNode.NODE_ACTION_APPROVE:    //审核通过
				return NoCodeFlowNode.NODE_STATE_APPROVE;            //已审核通过
			case NoCodeFlowNode.NODE_ACTION_REFUSE:        //审核拒绝
				return NoCodeFlowNode.NODE_STATE_REFUSE;            //已审核拒绝
			case NoCodeFlowNode.NODE_ACTION_REJECT:        //驳回修改
				return NoCodeFlowNode.NODE_STATE_REJECT;            //已驳回修改
			case NoCodeFlowNode.NODE_ACTION_FORWARD:    //转发
				return NoCodeFlowNode.NODE_STATE_FORWARD;            //已转发
			case NoCodeFlowNode.NODE_ACTION_READ:        //阅读
				return NoCodeFlowNode.NODE_STATE_READ;                //已阅读
			case NoCodeFlowNode.NODE_ACTION_BACK:        //退回
				return NoCodeFlowNode.NODE_STATE_BACK;                //已退回
			case NoCodeFlowNode.NODE_ACTION_FREEZE:        //冻结
				return NoCodeFlowNode.NODE_STATE_FREEZE;            //已冻结
			case NoCodeFlowNode.NODE_ACTION_UNFREEZE:    //解冻
				return NoCodeFlowNode.NODE_STATE_UNFREEZE;            //已解冻
			case NoCodeFlowNode.NODE_ACTION_DELETE:        //删除
				return NoCodeFlowNode.NODE_STATE_DELETE;            //已删除
			case NoCodeFlowNode.NODE_ACTION_ABANDON:    //作废
				return NoCodeFlowNode.NODE_STATE_ABANDON;            //已作废
			case NoCodeFlowNode.NODE_ACTION_FINISH:    //完结
				return NoCodeFlowNode.NODE_STATE_FINISHED;            //已完结
		}

		return NoCodeFlowNode.NODE_STATE_NO_SUBMIT;
	}
	//endregion

	//region 节点状态、动作、类型,文字颜色样式
	//获取节点值与名称的map表
	public static Map getNodeTypeCssMap() {
		Map mapNodeTypeCss = new LinkedHashMap<>();

		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_START, "text-info");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_END, "text-muted");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_SERIAL, "text-success");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_BRANCH, "text-warning");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_AND_SINGLE, "text-danger");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_AND_MULTI, "text-danger");
		mapNodeTypeCss.put(NoCodeFlowNode.NODE_TYPE_AND_ALL, "text-danger");

		return mapNodeTypeCss;
	}

	//根据节点类型获取文字样式名称
	public static String getNodeTypeCss(int nodeType) {
		return getNodeTypeCssMap().get(nodeType);
	}

	//获取流程状态值与名称map表
	public static Map getNodeStateCssMap() {
		Map mapNodeStateCss = new LinkedHashMap<>();

		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_NO_SUBMIT, "");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_HAS_SUBMIT, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_APPROVE, "text-info");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_REFUSE, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_REJECT, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_CANCEL, "text-warning");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_READ, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_FORWARD, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_BACK, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_FREEZE, "text-warning");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_UNFREEZE, "text-info");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_DELETE, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_ABANDON, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_STATE_FINISHED, "text-muted");

		return mapNodeStateCss;
	}

	//根据节点状态获取文字样式名称
	public static String getNodeStateCss(int nodeState) {
		return getNodeStateCssMap().get(nodeState);
	}

	//获取操作类型值与名称map表
	public static Map getNodeActionCssMap() {
		Map mapNodeStateCss = new LinkedHashMap<>();

		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_SAVE, "");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_SUBMIT, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_CANCEL, "text-warning");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_APPROVE, "text-info");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_REFUSE, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_REJECT, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_FORWARD, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_READ, "text-success");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_BACK, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_FREEZE, "text-warning");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_UNFREEZE, "text-info");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_DELETE, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_ABANDON, "text-danger");
		mapNodeStateCss.put(NoCodeFlowNode.NODE_ACTION_FINISH, "text-muted");

		return mapNodeStateCss;
	}

	//根据节点类型获取文字样式名称
	public static String getNodeActionCss(int nodeAction) {
		return getNodeActionCssMap().get(nodeAction);
	}

	//endregion
}

 

你可能感兴趣的:(太极开发框架)