一、表单生命周期、定义方式
表单使用两种方式
FormService
:
表单定义支持的节点:
二、外置表单
<bpmn:startEvent id="StartEvent_1" camunda:formKey="start.html">
<bpmn:outgoing>Flow_0ycrxbl</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0ycrxbl" sourceRef="StartEvent_1" targetRef="Activity_0dhhxgy" />
<bpmn:userTask id="Activity_0dhhxgy" name="请假申请" camunda:formKey="1.html">
<bpmn:incoming>Flow_0ycrxbl</bpmn:incoming>
<bpmn:outgoing>Flow_0b9puvz</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0b9puvz" sourceRef="Activity_0dhhxgy" targetRef="Activity_1c6jr4q" />
<bpmn:userTask id="Activity_1c6jr4q" name="【总经理】审批" camunda:formKey="2.html">
start.html
:
开始节点
${startUserId} 发起了 ${category} 类型的流程
1.html
:
第一个任务节点,【请假申请】
${startUserId} 提交了 ${category} 类型的流程
2.html
:
第二个任务节点,【总经理审批】
${startUserId} 提交了 ${category} 类型的流程
@Test
public void createDeployment() {
DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
Deployment deployment = deploymentBuilder
.name("外置表单测试")
.source("本地测试")
.tenantId("a")
.addClasspathResource("com.demo/ch18/form.bpmn")
.addClasspathResource("com.demo/ch18/start.html")
.addClasspathResource("com.demo/ch18/1.html")
.addClasspathResource("com.demo/ch18/2.html")
.deploy();
System.out.println(deploymentBuilder);
System.out.println(deployment);
}
查询启动节点的key
@Test
public void getStartFormKey() {
String processDefinitionId="form:1:5106";
String startFormKey = formService.getStartFormKey(processDefinitionId);
System.out.println(startFormKey);
}
查询任务节点的Key
@Test
public void getTaskFormKey() {
String processDefinitionId = "form:1:5106";
String taskDefinitionKey = "Activity_0dhhxgy";
String startFormKey = formService.getTaskFormKey(processDefinitionId, taskDefinitionKey);
System.out.println(startFormKey);
}
@Test
public void getTaskFormKey2() {
String processDefinitionId = "form:1:5106";
String taskDefinitionKey = "Activity_1c6jr4q";
String startFormKey = formService.getTaskFormKey(processDefinitionId, taskDefinitionKey);
System.out.println(startFormKey);
}
三、外置表单常见问题以及解决
查询节点表单渲染内容信息
/**
* select * from ACT_GE_BYTEARRAY where DEPLOYMENT_ID_ = ? and NAME_ = ?
* 5101(String), start.html(String)
*/
@Test
public void getRenderedStartForm() {
String processDefinitionId = "form:1:5106";
Object renderedStartForm = formService.getRenderedStartForm(processDefinitionId, "juel");
System.out.println(renderedStartForm);
}
报错2021-03-10 17:31:21.295 [main] ERROR org.camunda.bpm.engine.context [BaseLogger.java : 156] - ENGINE-16004 Exception while closing command context: Form with formKey 'start.html' does not exist: resourceStream is null
通过查看SQL,start.html
可以发现与数据库com.demo/ch18/start.html
不一致
故这里需要改一下名称,重新部署
<bpmn:startEvent id="StartEvent_1" camunda:formKey="com.demo/ch18/start.html">
<bpmn:outgoing>Flow_0ycrxbl</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0ycrxbl" sourceRef="StartEvent_1" targetRef="Activity_0dhhxgy" />
<bpmn:userTask id="Activity_0dhhxgy" name="请假申请" camunda:formKey="com.demo/ch18/1.html">
<bpmn:incoming>Flow_0ycrxbl</bpmn:incoming>
<bpmn:outgoing>Flow_0b9puvz</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0b9puvz" sourceRef="Activity_0dhhxgy" targetRef="Activity_1c6jr4q" />
<bpmn:userTask id="Activity_1c6jr4q" name="【总经理】审批" camunda:formKey="com.demo/ch18/2.html">
<bpmn:incoming>Flow_0b9puvz</bpmn:incoming>
<bpmn:outgoing>Flow_08xz0y7</bpmn:outgoing>
</bpmn:userTask>
再次查询为空
@Test
public void getRenderedStartForm() {
String processDefinitionId = "form:1:5106";
Object renderedStartForm = formService.getRenderedStartForm(processDefinitionId, "juel");
System.out.println(renderedStartForm);
}
debug跟踪到org.camunda.bpm.engine.impl.form.engine.JuelFormEngine
protected Object executeScript(String scriptSrc, VariableScope scope) {
ProcessEngineConfigurationImpl processEngineConfiguration = Context.getProcessEngineConfiguration();
ScriptFactory scriptFactory = processEngineConfiguration.getScriptFactory();
ExecutableScript script = scriptFactory.createScriptFromSource("juel", scriptSrc);
ScriptInvocation invocation = new ScriptInvocation(script, scope);
try {
processEngineConfiguration.getDelegateInterceptor().handleInvocation(invocation);
} catch (RuntimeException var8) {
throw var8;
} catch (Exception var9) {
throw new ProcessEngineException(var9);
}
return invocation.getInvocationResult();
}
说明了开始节点,不能有表达式变量,故去掉startUserId
等变量
start.html
:
开始节点
重新部署
@Test
public void getRenderedStartForm() {
String processDefinitionId = "form:3:5306";
Object renderedStartForm = formService.getRenderedStartForm(processDefinitionId, "juel");
System.out.println(renderedStartForm);
}
org.camunda.bpm.engine.impl.form.engine.JuelFormEngine
中有return null
`
public Object renderStartForm(StartFormData startForm) {
if (startForm.getFormKey() == null) {
return null;
} else {
String formTemplateString = this.getFormTemplateString(startForm, startForm.getFormKey());
return this.executeScript(formTemplateString, (VariableScope)null);
}
}
四、外置表单StartFormData获取
@Test
public void getStartFormData() {
String processDefinitionId = "form:3:5306";
StartFormData startFormData = formService.getStartFormData(processDefinitionId);
System.out.println("############");
System.out.println(startFormData.getDeploymentId());
System.out.println(startFormData.getProcessDefinition());
System.out.println(startFormData.getFormKey());
List<FormProperty> formProperties = startFormData.getFormProperties();
System.out.println(formProperties);
List<FormField> formFields = startFormData.getFormFields();
System.out.println(formFields);
System.out.println("############");
}
五、外置表单查询渲染内容并提交任务
启动表单实例:
@Test
public void submitStartForm() {
String processDefinitionId = "form:3:5306";
VariableMap variableMap = Variables.createVariables()
.putValue("days", 10)
.putValue("reason", "请假三天")
.putValue("startUserId", "张三")
.putValue("category", "年假");
ProcessInstance processInstance = formService.submitStartForm(processDefinitionId, variableMap);
System.out.println(processInstance);
}
startUserId
、category
必须传递,因为1.html
、2.html
中的juel表达式会用到
获取并渲染任务节点的表单内容:
@Test
public void getTaskFormData() {
Task task = taskService.createTaskQuery().taskId("5411").singleResult();
System.out.println(task.getId());
TaskFormData taskFormData = formService.getTaskFormData(task.getId());
System.out.println("############");
System.out.println(taskFormData.getDeploymentId());
System.out.println(taskFormData.getTask());
System.out.println(taskFormData.getFormKey());
List<FormProperty> formProperties = taskFormData.getFormProperties();
System.out.println(formProperties);
List<FormField> formFields = taskFormData.getFormFields();
System.out.println(formFields);
System.out.println("############");
}
@Test
public void getRenderedTaskForm() {
Object renderedTaskForm = formService.getRenderedTaskForm("5411", "juel");
System.out.println("############");
System.out.println(renderedTaskForm);
System.out.println("############");
}
提交任务节点并保存表单:
@Test
public void submitTaskForm() {
VariableMap variableMap = Variables.createVariables()
.putValue("startUserId", "王五")
.putValue("category", "年假");
formService.submitTaskForm("5411", variableMap);
}
六、动态表单定义及信息获取
<bpmn:startEvent id="StartEvent_1">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="days" label="请假天数" type="long" defaultValue="3">
<camunda:properties>
<camunda:property id="aa" value="aa" />
</camunda:properties>
</camunda:formField>
<camunda:formField id="reason" label="请假原因" type="string" />
<camunda:formField id="start_time" label="请假开始时间" type="date" />
<camunda:formField id="end_time" label="请假结束时间" type="date" />
<camunda:formField id="enums" type="enum">
<camunda:value id="a" name="a" />
<camunda:value id="b" name="b" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:outgoing>Flow_0ycrxbl</bpmn:outgoing>
</bpmn:startEvent>
<bpmn:sequenceFlow id="Flow_0ycrxbl" sourceRef="StartEvent_1" targetRef="Activity_0dhhxgy" />
<bpmn:userTask id="Activity_0dhhxgy" name="请假申请">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="days" label="请假天数" type="long" defaultValue="3" />
<camunda:formField id="reason" label="请假原因" type="string" />
<camunda:formField id="start_time" label="请假开始时间" type="date" />
<camunda:formField id="end_time" label="请假结束时间" type="date" />
<camunda:formField id="enums" type="enum">
<camunda:value id="a" name="a" />
<camunda:value id="b" name="b" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0ycrxbl</bpmn:incoming>
<bpmn:outgoing>Flow_0b9puvz</bpmn:outgoing>
</bpmn:userTask>
<bpmn:sequenceFlow id="Flow_0b9puvz" sourceRef="Activity_0dhhxgy" targetRef="Activity_1c6jr4q" />
<bpmn:userTask id="Activity_1c6jr4q" name="【总经理】审批">
<bpmn:extensionElements>
<camunda:formData>
<camunda:formField id="days" label="请假天数" type="long" defaultValue="3" />
<camunda:formField id="reason" label="请假原因" type="string" />
<camunda:formField id="start_time" label="请假开始时间" type="date" />
<camunda:formField id="end_time" label="请假结束时间" type="date" />
<camunda:formField id="enums" type="enum">
<camunda:value id="a" name="a" />
<camunda:value id="b" name="b" />
</camunda:formField>
</camunda:formData>
</bpmn:extensionElements>
<bpmn:incoming>Flow_0b9puvz</bpmn:incoming>
<bpmn:outgoing>Flow_08xz0y7</bpmn:outgoing>
</bpmn:userTask>
动态表单开始节点字段获取:
@Test
public void getStartFormData() {
String processDefinitionId = "form2:3:5903";
StartFormData startFormData = formService.getStartFormData(processDefinitionId);
List<FormField> formFields = startFormData.getFormFields();
for (FormField formField : formFields) {
System.out.println("############");
System.out.println(formField.getId());
System.out.println(formField.getValue());
System.out.println(formField.getType());
System.out.println(formField.getTypeName());
System.out.println(formField.getLabel());
System.out.println(formField.getDefaultValue());
System.out.println("############");
}
}
动态表单字段附属获取:
@Test
public void getStartFormData2() {
String processDefinitionId = "form2:4:6003";
StartFormData startFormData = formService.getStartFormData(processDefinitionId);
List<FormField> formFields = startFormData.getFormFields();
for (FormField formField : formFields) {
System.out.println("############");
FormType formType = formField.getType();
if (formType instanceof DateFormType) {
DateFormType dateFormType = (DateFormType) formType;
Object information = dateFormType.getInformation("datePattern");
System.out.println("information:" + information);
}
if (formType instanceof EnumFormType) {
EnumFormType enumFormType = (EnumFormType) formType;
Object information = enumFormType .getInformation("values");
System.out.println("information:" + information);
}
System.out.println("############");
}
}
七、自定义表单引擎思路
formKey
及其defaultValue
可以使用变量,外置表单内容可以使用变量,再使用juel引擎渲染
类org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl
protected void initFormEngines() {
if (this.formEngines == null) {
this.formEngines = new HashMap();
FormEngine defaultFormEngine = new HtmlFormEngine();
this.formEngines.put((Object)null, defaultFormEngine);
this.formEngines.put(defaultFormEngine.getName(), defaultFormEngine);
FormEngine juelFormEngine = new JuelFormEngine();
this.formEngines.put(juelFormEngine.getName(), juelFormEngine);
}
if (this.customFormEngines != null) {
Iterator var3 = this.customFormEngines.iterator();
while(var3.hasNext()) {
FormEngine formEngine = (FormEngine)var3.next();
this.formEngines.put(formEngine.getName(), formEngine);
}
}
}
自定义渲染类
public class MyFormEngine implements FormEngine {
@Override
public String getName() {
return null;
}
@Override
public Object renderStartForm(StartFormData startFormData) {
return null;
}
@Override
public Object renderTaskForm(TaskFormData taskFormData) {
return null;
}
}
也可以直接继承JuelFormEngine
public class MyFormEngine extends JuelFormEngine {
@Override
public String getName() {
return "peng";
}
@Override
public Object renderStartForm(StartFormData startFormData) {
return super.renderStartForm(startFormData);
}
@Override
public Object renderTaskForm(TaskFormData taskFormData) {
return super.renderTaskForm(taskFormData);
}
}
<bean id="processEngineConfiguration"
class="org.camunda.bpm.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1/camunda"/>
<property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>
<property name="jdbcUsername" value="root"/>
<property name="jdbcPassword" value="123456"/>
<property name="databaseSchemaUpdate" value="false"/>
<property name="dbHistoryUsed" value="true"/>
<!--关闭租户校验-->
<property name="tenantCheckEnabled" value="false"/>
<!--自定义表单渲染-->
<property name="customFormEngines">
<list>
<bean class="com.demo.ch18.MyFormEngine"/>
</list>
</property>
</bean>
@Test
public void getRenderedStartForm() {
Object juel = formService.getRenderedTaskForm("6209", "peng");
System.out.println(juel);
}
代码参考:https://github.com/zhoupengwa/ProcessEngineDemo
学习来源:腾讯课堂