在Activiti中总共有三种表单,动态表单,普通表单和外置表单。本文介绍的是动态表单。
FormService
.getTaskFormCmd:查询Task表单。通过源码跟踪,查看如何获取Task表单
一、FormProperty
Task可以配置属性值,比如有一个审核的任务,对应的流程定义XML代码如下:
<userTask id="audit" name="审核">
<extensionElements>
<activiti:formProperty id="vendorCode" name="供应商" type="string" expression="1" variable="1" readable="false" required="true"/>
<activiti:formProperty id="date" name="时间" type="date" datePattern="MM-dd-yyyy hh:mm"/>
<activiti:formProperty id="amount" name="总数" type="long" writable="false" required="true"/>
<activiti:formProperty id="is_vip" name="是否会员" type="boolean" writable="false"/>
<activiti:formProperty id="approved" name="是否通过" type="enum" required="true">
<activiti:value id="1" name="通过"/>
<activiti:value id="2" name="驳回"/>
</activiti:formProperty>
</extensionElements>
</userTask>
其中activiti:formProperty用来定义Task的属性:
public interface FormProperty extends Serializable {
/** The key used to submit the property in {@link FormService#submitStartFormData(String, java.util.Map)}
* or {@link FormService#submitTaskFormData(String, java.util.Map)} */
String getId();
/** The display label */
String getName();
/** Type of the property. */
FormType getType();
/** Optional value that should be used to display in this property */
String getValue();
/** Is this property read to be displayed in the form and made accessible with the methods
* {@link FormService#getStartFormData(String)} and {@link FormService#getTaskFormData(String)}. */
boolean isReadable();
/** Is this property expected when a user submits the form? */
boolean isWritable();
/** Is this property a required input field */
boolean isRequired();
}
支持的表单属性有以下几种:
-
string
(org.activiti.engine.impl.form.StringFormType) -
long
(org.activiti.engine.impl.form.LongFormType) -
enum
(org.activiti.engine.impl.form.EnumFormType) -
date
(org.activiti.engine.impl.form.DateFormType) -
boolean
(org.activiti.engine.impl.form.BooleanFormType)
二、如何去获取在流程定义中定义的表单内容?
TaskFormDataImpl taskFormData = (TaskFormDataImpl) formService.getTaskFormData(taskId);
GetTaskFormCmd的execute方法:
public TaskFormData execute(CommandContext commandContext) {
TaskEntity task = commandContext
.getTaskEntityManager()
.findTaskById(taskId);
if (task == null) {
throw new ActivitiObjectNotFoundException("No task found for taskId '" + taskId +"'", Task.class);
}
if(task.getTaskDefinition() != null) {
TaskFormHandler taskFormHandler = task.getTaskDefinition().getTaskFormHandler();
if (taskFormHandler == null) {
throw new ActivitiException("No taskFormHandler specified for task '" + taskId +"'");
}
return taskFormHandler.createTaskForm(task);
} else {
// Standalone task, no TaskFormData available
return null;
}
}
核心代码再第9行task.getTaskDefinition()获取Task属性
public TaskDefinition getTaskDefinition() {
if (taskDefinition==null && taskDefinitionKey!=null) {
ProcessDefinitionEntity processDefinition = Context
.getProcessEngineConfiguration()
.getDeploymentManager()
.findDeployedProcessDefinitionById(processDefinitionId);
taskDefinition = processDefinition.getTaskDefinitions().get(taskDefinitionKey);
}
return taskDefinition;
}
第6行代码findDeployedProcessDefinitionById,根据processDefinitionId查询流程定义:
public ProcessDefinitionEntity findDeployedProcessDefinitionById(String processDefinitionId) {
if (processDefinitionId == null) {
throw new ActivitiIllegalArgumentException("Invalid process definition id : null");
}
// first try the cache
ProcessDefinitionEntity processDefinition = processDefinitionCache.get(processDefinitionId);
if (processDefinition == null) {
processDefinition = Context.getCommandContext()
.getProcessDefinitionEntityManager()
.findProcessDefinitionById(processDefinitionId);
if (processDefinition == null) {
throw new ActivitiObjectNotFoundException("no deployed process definition found with id '" + processDefinitionId + "'", ProcessDefinition.class);
}
processDefinition = resolveProcessDefinition(processDefinition);
}
return processDefinition;
}
第7行代码变量processDefinitionCache是一个DeploymentCache实例对象,在这里引申一下。
当初始化流程引擎的时候,会执行下面的方法
org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl
buildProcessEngine()--->init()--->initDeployers(),这时候processDefinitionCache会被初始化。那么processDefinitionCache什么时候赋值的呢?processDefinitionCache属于DeploymentCache对象,可以看出应该是在流程部署的时候进行赋值的。可以参考:Activiti源码跟踪之流程部署
接着往下看--》resolveProcessDefinition方法
public ProcessDefinitionEntity resolveProcessDefinition(ProcessDefinitionEntity processDefinition) {
String processDefinitionId = processDefinition.getId();
String deploymentId = processDefinition.getDeploymentId();
processDefinition = processDefinitionCache.get(processDefinitionId);
if (processDefinition==null) {
DeploymentEntity deployment = Context
.getCommandContext()
.getDeploymentEntityManager()
.findDeploymentById(deploymentId);
deployment.setNew(false);
deploy(deployment, null);
processDefinition = processDefinitionCache.get(processDefinitionId);
if (processDefinition==null) {
throw new ActivitiException("deployment '"+deploymentId+"' didn't put process definition '"+processDefinitionId+"' in the cache");
}
}
return processDefinition;
}
如果processDefinitionCache没有流程定义的话,重新部署流程:
deployment.setNew(false);
deploy(deployment, null);
因为部署会把流程定义放在缓存中,所以这个时候再去processDefinitionCache查询流程定义。
根据taskDefinitionKey就可以获取到TaskDefinition
三、如何解析TaskDefinition()
再看下GetTaskFormCmd的execute方法
TaskFormHandler taskFormHandler = task.getTaskDefinition().getTaskFormHandler();
taskFormHandler.createTaskForm(task);
DefaultTaskFormHandler.createTaskForm--->DefaultFormHandler.initializeFormProperties(taskFormData, task.getExecution())。循环DefaultFormHandler的formPropertyHandlers获取到FormProperty。
四:扩展:如何根据ProcessDefinitionId和TaskDefinitionKey获取到表单属性
1、根据processDefinitionId查询流程定义
ProcessDefinitionEntity processDefinition = Context.getProcessEngineConfiguration().getDeploymentManager()
.findDeployedProcessDefinitionById(processDefinitionId);
2、根据TaskDefinitionKey获取Task定义
TaskDefinition taskDefinition = processDefinition.getTaskDefinitions().get(taskDefinitionKey);
3、获取Task表单属性
因为DefaultTaskFormHandler有FormPropertyHandlers属性,所以可以直接从DefaultTaskFormHandler获取FormPropertyHandlers
DefaultTaskFormHandler taskFormHandler = (DefaultTaskFormHandler) taskDefinition.getTaskFormHandler();
public class FormPropertyHandler implements Serializable {
private static final long serialVersionUID = 1L;
protected String id;
protected String name;
protected AbstractFormType type;
protected boolean isReadable;
protected boolean isWritable;
protected boolean isRequired;
protected String variableName;
protected Expression variableExpression;
protected Expression defaultExpression;
......
}
然后获取表单属性:
formPropertyHandler.getId();
formPropertyHandler.getName();
formPropertyHandler.getType().getName()