接下来,我们在看看动态表单
我们先来了解下动态表单
动态表单就是不需要前端定制开发的界面,由用户拖拉拽,自己定义好的内容
然后和流程图进行绑定,在流程过程中,展示这些表单的内容
创建完表单act_de_model 流程模型部署对象表 表里面就有数据了
我们可以在结果这里定制分支条件
success 这里表示通过
reject 表示驳回
然后点击保存
然后我们吧这一个json数据打开看一看,就是这样的
然后我们在创建一个流程图
然后在绑定表单引用
所有任务节点,都要绑定表单引用
我们在给他设置outcome的表达式,命名规则,form_动态表单key_outcome
${form_rsbd_outcome=='reject'} 经理驳回到提交
这根线通过
${form_rsbd_outcome=='success'}
保存流程图 然后部署流程,好了之后
我们在代码里面部署一下表单
package com.dmg.service;
public interface MyFormService {
public String deployDynamicForm(String modelKey);
}
package com.dmg.service.impl;
@Service
public class MyFormServiceImpl extends FlowServiceFactory implements MyFormService {
@Autowired
private QjMapper qjMapper;
/**
* 部署动态表单
* @param modelKey rsbd
* @return
*/
@Transactional(rollbackFor = Exception.class)
@Override
public String deployDynamicForm(String modelKey) {
//根据模型key 获取表单json数据 从act_de_model表 根据model_key 查询model_editor_json数据
String json = qjMapper.getJson(modelKey);
if(StringUtils.isEmpty(json)){
throw new RuntimeException("表单数据不存在");
}
//解析json数据
JSONObject jsonObject=JSONObject.parseObject(json);
String key=jsonObject.get("key").toString();
String name=jsonObject.get("name").toString();
//部署外部表单 act_fo_form_deployment和act_fo_form_resource和act_fo_form_definition表
FormDeployment formDeployment = formRepositoryService.createDeployment()
.name(name)
//这里必须加form的后缀 否则不会插入到act_fo_form_definition 表中
.addString(key+"form",json)
.deploy();
return formDeployment.getId();
}
}
在部署表单的时候通常都是部署.form文件,但是我不想部署这个文件,该怎么弄呢?
package com.dmg.mapper;
public interface QjMapper extends BaseMapper<Qj> {
/**
* 根据模型key 获取表单json数据
* @param modelKey
* @return
*/
String getJson(@Param("modelKey") String modelKey);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.dmg.mapper.QjMapper">
<!--根据模型key 获取表单json数据-->
<select id="getJson" resultType="String">
SELECT model_editor_json from act_de_model
WHERE model_key=#{modelKey}
</select>
</mapper>
package com.dmg.controller;
@RestController
public class FormController {
@Autowired
private MyFormService myFormService;
/**
* 部署动态表单
* @return
*/
@PostMapping("/deployDynamicForm")
public Result deployDynamicForm(@RequestBody FlowReq flowReq){
return Result.success(myFormService.deployDynamicForm(flowReq.getModelKey()));
}
}
package com.dmg.vo.req;
import lombok.Data;
import java.util.List;
@Data
public class FlowReq extends PageReq{
/**
* 流程定义名称
*/
private String processDefinitionName;
/**
* 流程定义key
*/
private String processDefinitionKey;
/**
* 任务id
*/
private String taskId;
/**
* 当前人账号
*/
private String account;
/**
* 流程定义id
*/
private String processDefinitionId;
/**
* 流程实例id
*/
private String processInstanceId;
/**
* 部署id
*/
private String deploymentId;
/**
* 如果为true 已经启动的流程关联的数据也一并删除 历史流程也会删除
* 如果为false 只删除运行 并且没有任务的流程信息
*/
private Boolean cascade;
/**
* 任务节点id集合
*/
List<String> activityIds;
/**
* 模型key act_de_model表的model_key
*/
private String modelKey;
/**
* 分支条件
*/
private String outcome;
}
package com.dmg.service;
/**
* 工作流服务的工厂类 被其他类 所继承
* 这里使用受保护的 就是可以被所继承的类使用
*/
@Component
public class FlowServiceFactory {
@Autowired
protected IdentityService identityService;
@Autowired
protected ManagementService managementService;
@Autowired
protected TaskService taskService;
@Autowired
protected ProcessEngine processEngine;
@Autowired
protected RuntimeService runtimeService;
@Autowired
protected RepositoryService repositoryService;
@Autowired
protected HistoryService historyService;
@Autowired
protected FormRepositoryService formRepositoryService;
@Autowired
protected FormService formService;
}
接下来我们先来看下源码,为啥要使用form后缀
在ParsedDeploymentBuilder这个类中isFormResource方法
里面判断我们的后缀是部署form结尾的,
如果是返回true,回到55行可以添加到表单定义实体里面数据。
如果是返回false,那么不会添加到表单定义实体里面数据。
所以我们不用传.form文件,只要后缀包含form,我们可以传字符串来部署表单
这样act_fo_form_definition就有了数据
我们来看下结果
http://localhost:8080/deployDynamicForm
{
"modelKey":"rsbd"
}
act_fo_form_resource (动态表单资源表)
act_fo_form_deployment(动态表单部署表)
act_fo_form_definition(动态表单定义表)就有数据了
注意 3张一定要有数据,否则无法启动流程实例
接下来我们在启动下表单的流程实例
package com.dmg.controller;
@RestController
public class FormController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private FormService formService;
@Autowired
private MyFormService myFormService;
/**
* 启动流程实例 带有表单的数据
* @param req
*/
@PostMapping("/startTheFormProcess")
public Result startTheFormProcess(@RequestBody FlowReq req){
return Result.success(myFormService.startTheFormProcess(req));
}
}
package com.dmg.service;
public interface MyFormService {
public String startTheFormProcess(FlowReq flowReq);
}
package com.dmg.service.impl;
@Service
public class MyFormServiceImpl extends FlowServiceFactory implements MyFormService {
@Autowired
private QjMapper qjMapper;
/**
* 启动流程实例 带有表单的数据
* 表单的提交和完成 是不一样的方法 要注意
* @param req
*/
@Transactional(rollbackFor = Exception.class)
@Override
public String startTheFormProcess(FlowReq req) {
//内容由前端传过来 我这里就写死了 参数就是动态表单的字段
Map<String,Object> map=new HashMap<>();
map.put("name","我是一个人事申请单");
map.put("desc","这是一个描述");
//分支条件
String outcome="success";
ProcessInstance processInstance = runtimeService.startProcessInstanceWithForm(req.getProcessDefinitionId(), outcome, map, "我是一个流程实例名称");
if(processInstance==null){
throw new RuntimeException("启动流程实例动态表单失败");
}
//表单和任务绑定后任务表的formkey就有数据了
//根据流程实例id 查询任务
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId())
.singleResult();
if(task==null){
throw new RuntimeException("任务不存在");
}
//得到表单数据
FormInfo formInfo=taskService.getTaskFormModel(task.getId());
if(formInfo==null){
throw new RuntimeException("表单数据不存在");
}
//先认领任务
taskService.claim(task.getId(),req.getAccount());
//完成提交任务
taskService.completeTaskWithForm(task.getId(),formInfo.getId(),outcome,map);
return processInstance.getId();
}
}
我们来看下结果
http://localhost:8080/startTheFormProcess
{
"processDefinitionId":"rs:1:10b652a5-70bc-11ed-8d34-005056c00008",
"account":"zhangsan"
}
启动成功后,任务就走到下一个流程了
我们可以看到formkey已经有数据了,这样我们就能查询动态表单的数据了
接下来我们在看下当前动态表单的数据
package com.dmg.controller;
@RestController
public class FormController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private FormService formService;
@Autowired
private MyFormService myFormService;
/**
* 查看任务表单数据
*/
@PostMapping("/getTaskFormModel")
public Result getTaskFormModel(@RequestBody FlowReq req){
Task task = taskService.createTaskQuery()
.processInstanceId(req.getProcessInstanceId())
.taskAssignee(req.getAccount())
.singleResult();
if(task==null){
throw new RuntimeException("任务不存在");
}
//获取任务表单模型
FormInfo formInfo=taskService.getTaskFormModel(task.getId());
System.out.println(formInfo.getId());
System.out.println(formInfo.getName());
System.out.println(formInfo.getKey());
System.out.println("------------------------------------------------");
//formmodel具体信息
SimpleFormModel simpleFormModel=(SimpleFormModel) formInfo.getFormModel();
List<FormField> fields = simpleFormModel.getFields();
for (FormField field : fields) {
System.out.println(field.getId());
System.out.println(field.getName());
System.out.println(field.getValue());
System.out.println("================");
}
return Result.success();
}
}
我们来看下结果
http://localhost:8080/getTaskFormModel
{
"processInstanceId":"44c7f067-7166-11ed-bc44-005056c00008",
"account":"lisi"
}
我们先进行审批一下,先驳回
package com.dmg.controller;
@RestController
public class FormController {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Autowired
private RepositoryService repositoryService;
@Autowired
private FormService formService;
@Autowired
private MyFormService myFormService;
/**
* 完成表单任务
* @param req
* @return
*/
@PostMapping("/completeTaskWithForm")
public Result completeTaskWithForm(@RequestBody FlowReq req){
Task task = taskService.createTaskQuery()
.processInstanceId(req.getProcessInstanceId())
.taskAssignee(req.getAccount())
.singleResult();
if(task==null){
throw new RuntimeException("任务不存在");
}
//得到表单数据
FormInfo formInfo=taskService.getTaskFormModel(task.getId());
if(formInfo==null){
throw new RuntimeException("表单数据不存在");
}
Map<String,Object> map = new HashMap<>();
//在这里 还可以修改数据
map.put("name","我叫新的申请单");
map.put("desc","这是新的描述");
taskService.completeTaskWithForm(task.getId(),formInfo.getId(),req.getOutcome(),map);
return Result.success();
}
}
这里的outcome要和我们在动态表单设置的字段一样
我们来看下结果
http://localhost:8080/completeTaskWithForm
{
"processInstanceId":"44c7f067-7166-11ed-bc44-005056c00008",
"account":"lisi",
"outcome":"reject"
}
可以看到又回到了提交这里,接下来我们在进行审批通过
{
"processInstanceId":"44c7f067-7166-11ed-bc44-005056c00008",
"account":"zhangsan",
"outcome":"success"
}
可以看到经理审批通过之后,到了总经理这里
我们再次查看下当前的表单数据
可以看到已经发生了变化
我们只要吧这个表单的数据,返回给前端,让前端来渲染数据,就可以了
success 可以在前端界面展示通过按钮
reject 可以在前端界面展示拒绝按钮
怎么定义由你来控制
如果不想使用flowable-ui来设置动态表单,那么可以使用
Form Designer
来设计动态表单,然后自己新建一个表单表
在每一次任务和formkey进行绑定,这样就能看到对应的数据了