接下来,我们在看看动态表单

我们先来了解下动态表单

动态表单就是不需要前端定制开发的界面,由用户拖拉拽,自己定义好的内容

然后和流程图进行绑定,在流程过程中,展示这些表单的内容

springboot MyApps表单设计器 springboot动态表单_java

 创建完表单act_de_model 流程模型部署对象表  表里面就有数据了

springboot MyApps表单设计器 springboot动态表单_数据_02

springboot MyApps表单设计器 springboot动态表单_表单_03

springboot MyApps表单设计器 springboot动态表单_表单_04

 

springboot MyApps表单设计器 springboot动态表单_数据_05

springboot MyApps表单设计器 springboot动态表单_intellij-idea_06

 我们可以在结果这里定制分支条件

success 这里表示通过

reject 表示驳回

 然后点击保存

springboot MyApps表单设计器 springboot动态表单_spring boot_07

 

springboot MyApps表单设计器 springboot动态表单_java_08

然后我们吧这一个json数据打开看一看,就是这样的

springboot MyApps表单设计器 springboot动态表单_java_09

然后我们在创建一个流程图

springboot MyApps表单设计器 springboot动态表单_数据_10

springboot MyApps表单设计器 springboot动态表单_java_11

然后在绑定表单引用

springboot MyApps表单设计器 springboot动态表单_表单_12

springboot MyApps表单设计器 springboot动态表单_数据_13

所有任务节点,都要绑定表单引用

我们在给他设置outcome的表达式,命名规则,form_动态表单key_outcome

${form_rsbd_outcome=='reject'}  经理驳回到提交

springboot MyApps表单设计器 springboot动态表单_表单_14

 这根线通过 

${form_rsbd_outcome=='success'}

springboot MyApps表单设计器 springboot动态表单_spring boot_15

保存流程图  然后部署流程,好了之后

我们在代码里面部署一下表单

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后缀

springboot MyApps表单设计器 springboot动态表单_表单_16

springboot MyApps表单设计器 springboot动态表单_表单_17

 在ParsedDeploymentBuilder这个类中isFormResource方法

里面判断我们的后缀是部署form结尾的,

如果是返回true,回到55行可以添加到表单定义实体里面数据。

如果是返回false,那么不会添加到表单定义实体里面数据。

所以我们不用传.form文件,只要后缀包含form,我们可以传字符串来部署表单

这样act_fo_form_definition就有了数据

我们来看下结果

http://localhost:8080/deployDynamicForm

{

    "modelKey":"rsbd"

}

springboot MyApps表单设计器 springboot动态表单_intellij-idea_18

act_fo_form_resource (动态表单资源表)

act_fo_form_deployment(动态表单部署表)

act_fo_form_definition(动态表单定义表)就有数据了

 

springboot MyApps表单设计器 springboot动态表单_数据_19

springboot MyApps表单设计器 springboot动态表单_数据_20

springboot MyApps表单设计器 springboot动态表单_表单_21

 注意 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"

}

springboot MyApps表单设计器 springboot动态表单_数据_22

 启动成功后,任务就走到下一个流程了

springboot MyApps表单设计器 springboot动态表单_数据_23

springboot MyApps表单设计器 springboot动态表单_intellij-idea_24

 我们可以看到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"

}

springboot MyApps表单设计器 springboot动态表单_数据_25

springboot MyApps表单设计器 springboot动态表单_intellij-idea_26

 我们先进行审批一下,先驳回

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"

}

springboot MyApps表单设计器 springboot动态表单_表单_27

springboot MyApps表单设计器 springboot动态表单_数据_28

 可以看到又回到了提交这里,接下来我们在进行审批通过

{

    "processInstanceId":"44c7f067-7166-11ed-bc44-005056c00008",

    "account":"zhangsan",

    "outcome":"success"

}

可以看到经理审批通过之后,到了总经理这里

springboot MyApps表单设计器 springboot动态表单_数据_29

 我们再次查看下当前的表单数据

springboot MyApps表单设计器 springboot动态表单_表单_30

 可以看到已经发生了变化

springboot MyApps表单设计器 springboot动态表单_intellij-idea_31

 我们只要吧这个表单的数据,返回给前端,让前端来渲染数据,就可以了

success 可以在前端界面展示通过按钮

reject 可以在前端界面展示拒绝按钮

怎么定义由你来控制

如果不想使用flowable-ui来设置动态表单,那么可以使用

Form Designer

来设计动态表单,然后自己新建一个表单表

在每一次任务和formkey进行绑定,这样就能看到对应的数据了