1.概述
在使用Activiti时,对于表单的应用应该是大家讨论的最多的话题之一了。Activiti自带了两种模式的表单:内置表单和外置表单。
内置表单在流程定义文件的XML中用activiti:formProperty
属性来定义;外置表单则使用activiti:formkey="form/test.form"
来定义,test.form
是一份单独的表单文件。
在流程发起时从request获取提交的表单数据,然后构建为map再通过formService.submitStartFormData(defId, map)
提交表单数据到Activiti中保存。
在实际的使用过程中,这两种模式的表单都不能很好的满足企业级表单应用的需求,例如:
- 表单只支持键值对的格式;
- 不支持在线可视化进行表单设计;
- 表单数据不能进行查询和统计分析;
- 表单数据和流程数据无法分库存储。
2.在线表单设计器
使用在线表单设计器设计时,流程与表单按照以下方式进行整合。
2.1流程绑定表单
在进行流程配置时,通过在流程定义的XML中添加如下Element
将表单与流程进行绑定。
<ext:globalForm>
<ext:form formValue="bxbd" name="报销表单"
parentFlowKey="local_" type="inner"/>
</ext:globalForm>
2.2表单数据的保存
在发起流程和审批待办任务时,通过表单Key可以从数据库中获取表单的html
内容从而展示为表单页面。在用户填写了表单数据以后,执行启动流程、审批任务的操作时,将表单数据以json
格式提交到后台,后台将数据保存到数据库中,同时将这份数据的主键作为businessKey
与该流程实例关联起来。
通过流程启动事件的监听器来处理表单数据的保存及businessKey
的关联。
@Service
@Transactional
public class BpmStartEventListener implements ApplicationListener<BpmStartEvent>, Ordered {
@Resource
BpmDefinitionAccessor bpmDefinitionAccessor;
@Resource
BpmProcessInstanceManager bpmProcessInstanceManager;
@Resource
BpmExeStackManager bpmExeStackManager;
@Resource(name="defaultBpmFormService")
BpmFormService bpmFormService;
@Override
public void onApplicationEvent(BpmStartEvent ev) {
BpmStartModel model = (BpmStartModel) ev.getSource();
//设置上下文。
setBuinessKey(model);
if (AopType.PREVIOUS.equals(model.getAopType())) {
try {
before(model);
} catch (Exception e) {
throw new WorkFlowException(e.getLocalizedMessage(), e);
}
} else {
try {
after(model);
} catch (Exception e) {
throw new WorkFlowException("", e);
}
}
}
private void before(BpmStartModel model) throws Exception {
// 执行前置处理器
executeHandler(model, true);
// 添加业务表的中间数据库表
addBusLink(model);
}
/**
* 执行节点处理器。
*
* @param model
* @param isBefore
* void
* @throws Exception
*/
private void executeHandler(BpmStartModel model, boolean isBefore) throws Exception {
BpmProcessInstance instance = model.getBpmProcessInstance();
ActionCmd cmd = model.getCmd();
// 获取发起节点获取不到则获取第一个节点。
NodeProperties properties = getStartProperties(instance);
BusDataUtil.executeHandler(properties, cmd, isBefore);
}
/**
* 添加关联数据
* @param model
* @throws Exception
*/
private void addBusLink(BpmStartModel model) throws Exception {
ActionCmd cmd = model.getCmd();
if (cmd instanceof ProcessInstCmd) {
DefaultBpmProcessInstance inst = (DefaultBpmProcessInstance) model.getBpmProcessInstance();
String dataMode=cmd.getDataMode();
// 设置数据模式。
inst.setDataMode(dataMode);
if(StringUtil.isNotEmpty(cmd.getSysCode())){
inst.setSysCode(cmd.getSysCode());
}
// bo数据处理
if (ActionCmd.DATA_MODE_BO.equals(dataMode)) {
BusDataUtil.handSaveBoData(model.getBpmProcessInstance(), cmd);
}
// 键名 键值。
else if (ActionCmd.DATA_MODE_PAIR.equals(dataMode)) {
BusDataUtil.handExt(cmd);
}
//主键模式。
else if (ActionCmd.DATA_MODE_PK.equals(dataMode)) {
String pk=cmd.getBusinessKey();
String pkInst=inst.getBizKey();
if(StringUtil.isNotEmpty(pk) && StringUtil.isEmpty(pkInst)){
inst.setBizKey(pk);
}
}
}
}
private void after(BpmStartModel model) throws Exception {
// 执行后置处理器
executeHandler(model, false);
// 记录流程实例表单
handleInstForm(model);
}
// 流程启动后, 记录每个节点的表单 pc端和手机端的表单, 当流程结束或者终止时, 删除相应记录
private void handleInstForm(BpmStartModel model) throws Exception {
BpmProcessInstance instance = model.getBpmProcessInstance();
bpmFormService.handleInstForm(instance.getId(), instance.getProcDefId(),false);
}
@Override
public int getOrder() {
return 1;
}
}
2.3审批时显示表单数据
在进行待办任务审批时,需要显示表单及表单数据,通过流程实例所关联的表单Key及businessKey
分别查询表单html
和对应的数据json
,在前端将html
和json
融合显示为审批内容。
if( FormCategory.INNER.value().equals(formModel.getType().value()) ){
List<ObjectNode> boDatas = boDataService.getDataByInst(bpmProcessInstance);
DefaultTaskFinishCmd cmd = new DefaultTaskFinishCmd();
cmd.setVariables(this.getTaskVars(taskId,null));
ContextThreadUtil.setActionCmd(cmd);
// BO数据前置处理
ObjectNode data =BoDataUtil.hanlerData(bpmProcessInstance,nodeId, boDatas);
// BO数据
taskDetailVo.setData(data);
//获取意见
ObjectNode opinionJson = boDataService.getFormOpinionJson(task.getProcInstId());
taskDetailVo.setOpinionList(opinionJson);
//流程定义的权限
ObjectNode formRestParams=JsonUtil.getMapper().createObjectNode();
formRestParams.put("formkey", formModel.getFormKey());
formRestParams.put("flowKey", task.getProcDefKey());
formRestParams.put("nodeId", formAndPermNodeId);
formRestParams.put("parentFlowKey", topDefKey);
String permission = formRestfulService.getPermission(formRestParams);
taskDetailVo.setPermission(permission);
}
以上即是activiti
整合自定义表单的大致思路,大家也可以访问以下地址试用EIP7系统来查看最终效果。