目录

1.后台参考,spring boot,activiti7(虽然是7,因为用的shiro,没有使用spring security,新特性都没用,用过activiti5,6的话都不用多看,常用的区别不大)

2.前端参考,vue,bpmnjs(用的camunda解析器,和activiti有区别,问题主要集中在这)

效果

前端代码

后台代码

吐槽:


主要参考两位大佬的文章,代码直接拿着跑,然后集成(Ctrl+c+v)进了公司项目

如果需要表单,业务也明确,建议用外部表单,动态表单功能比较受限.

1.后台参考,spring boot,activiti7(虽然是7,因为用的shiro,没有使用spring security,新特性都没用,用过activiti5,6的话都不用多看,常用的区别不大)

2.前端参考,vue,bpmnjs(用的camunda解析器,和activiti有区别,问题主要集中在这)

如果是刚接触工作流,可以看看这两篇,很详细,都是直接上代码

camunda建议看官方文档,直接网页翻译对着看,说真的没找到特别好的文章,如果有好的希望好心人给我也发一份共同学习

一个小问题,Activiti7的M4版本缺失字段Bug,这是Oracle

貌似好多版本都有问题,不知道会不会变成Activiti的特色

alter table ACT_RE_DEPLOYMENT add PROJECT_RELEASE_VERSION_ varchar(255) DEFAULT NULL;
alter table ACT_RE_DEPLOYMENT add VERSION_ varchar(255) DEFAULT NULL;

效果

 

查询任务时可以编辑表单信息,保存表单数据是单独自定义的表,历史任务id和运行任务id一样,所以查一张表就行

前端代码

前端用的bpmnjs,其实搭配camunda比较合适

直接以字符串形式部署,把camunda标签,属性换成对应activiti了

async addByString() {
        try {
          const result = await this.bpmnModeler.saveXML({ format: true });
          const xml = result.xml;
          //xml转json,用json处理后在转xml
          const $x2js = new x2js();
          const jsonObj = $x2js.xml2js(xml);
          this.getFormProperty(jsonObj);
          let newXml = $x2js.js2xml(jsonObj);

          act1.addByString({
            xmlBPMN: newXml,
            deployName: 'addByString1'
          });
        } catch (err) {
          console.log(err);
        }
      },

 开始是直接字符串替换,最好不要只替换camunda,会把命名空间里面也替换

var newXml2 = xml.replace(/camunda:/ig, 'activiti:');
newXml2 = newXml2.replace(/FormField/ig, 'formProperty');
console.log(newXml2);

后面因为需要表单,用activiti没法解析,找到一个用json做转换的,参考bpmn camunda版转为activiti版

改了一下别人的方法,增加了activiti的属性(本来想在后台把这个方法重写一下,懒得动,先这样吧)

getFormProperty(json) {
        for (let e in json) {
          if (e == 'extensionElements' && json.extensionElements.formData && json.extensionElements.formData.formField) {
           
            let formProperty = JSON.parse(JSON.stringify(json.extensionElements.formData.formField));
            if (this.isArrayFn(formProperty)) {
              formProperty.forEach(x => {
                x.__prefix = 'activiti';
                //借用camunda属性 添加activiti的 不然activiti获取不到
                //对应activiti 表单 name
                x._name = x._label;
                //对应activiti 表单 defaultExpression
                if (x._defaultValue) {
                  x._default = x._defaultValue;
                }
              });
            } else {
              formProperty.__prefix = 'activiti';
              formProperty._name = formProperty._label;
              if (formProperty._defaultValue) {
                formProperty._default = formProperty._defaultValue;
              }
            }
            json.extensionElements.formProperty = formProperty;
            delete json.extensionElements.formData;
          } else if (e.includes('camunda:')) {
            let str = e.replace('camunda:', 'activiti:');
            json[str] = json[e];
            delete json[e];
          } else if (typeof json[e] == 'object') {
            this.getFormProperty(json[e]);
          }
        }
      },

后台代码

开始的时候activiti后台解析总是过不了,直接用xml字符串上传部署,比较方便调试 

 后台方法,这个disableSchemaValidation()方法不会检查Schema,标签或者属性有的是camunda的也不会报错(比如上面表单的label...)

@PostMapping("/addByString")
    public R addByString(
            @RequestParam("xmlBPMN") String xmlBPMN,
            @RequestParam("deployName") String deployName 
    ) {
        Deployment deployment = repositoryService.createDeployment()
                // 这里由于是 xml 的字符串没有资源名称
                .addString("xmlStr.bpmn", xmlBPMN)
                .disableSchemaValidation() //禁用架构验证
                .name(deployName)
                .deploy();
        return R.strData(deployment.getId());
    }

表单设置好了,查询任务时,根据taskId获取用户任务,activiti7没有了FormService,只能这样

构建表单

    @ApiOperation(value = "构建表单")
    @GetMapping("/getForm")
    public R getForm(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (!Optional.ofNullable(task).isPresent()) {
            throw new ReturnException("请更新任务");
        }

        //获取task对应的表单内容 需要TaskDefinitionKey
        UserTask userTask = (UserTask) repositoryService.getBpmnModel(task.getProcessDefinitionId())
                .getFlowElement(task.getTaskDefinitionKey());
        if (!Optional.ofNullable(userTask).isPresent()) {
            throw new ReturnException("非用户任务");
        }
        //外部表单
        //String formKey = userTask.getFormKey();

        List<FormProperty> formProperties = userTask.getFormProperties();

        if (CollectionUtils.isEmpty(formProperties)) {
            throw new ReturnException("无表单");
        }

        List<Map<String, Object>> collect = formProperties.stream().map(formProperty -> {
            return CreateMap.build()
                    .setAttribute("id", formProperty.getId())
                    .setAttribute("type", formProperty.getType())
                    //在camunda叫做label 前端转json加了一个name属性 不然取不到值
                    .setAttribute("name", formProperty.getName())
                    //在camunda叫做defaultValue activiti表单的default 前端转json加了一个default属性 后台对应defaultExpression
                    .setAttribute("defaultValue", formProperty.getDefaultExpression())
                    //type = enum  枚举类型会用
//                    .setAttribute("formValues", formProperty.getFormValues())
                    //下面没有值 camunda和activiti表单有区别
//                    .setAttribute("variable", formProperty.getVariable())
//                    .setAttribute("expression", formProperty.getExpression())
//                    .setAttribute("datePattern", formProperty.getDatePattern())
                    .build();
        }).collect(Collectors.toList());
        return R.okList(collect);
    }

 取出表单填写的值

    @ApiOperation(value = "构建表单,取出表单填写的值")
    @GetMapping("/getFormData")
    public R getFormData(String taskId) {
        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (!Optional.ofNullable(task).isPresent()) {
            throw new ReturnException("请更新任务");
        }

        //获取task对应的表单内容 需要TaskDefinitionKey
        UserTask userTask = (UserTask) repositoryService.getBpmnModel(task.getProcessDefinitionId())
                .getFlowElement(task.getTaskDefinitionKey());
        if (!Optional.ofNullable(userTask).isPresent()) {
            throw new ReturnException("非用户任务");
        }
        List<FormProperty> formProperties = userTask.getFormProperties();
        if (CollectionUtils.isEmpty(formProperties)) {
            throw new ReturnException("无表单");
        }

        //查询表单数据
        List<ActivitiFormdata> formdataList = activitiFormdataDao.findAllByTaskId(taskId);
        if (CollectionUtils.isEmpty(formdataList)) {
            //还没有保存表单
            formProperties.forEach(formProperty -> {

                ActivitiFormdata one = new ActivitiFormdata();
                one.setFormPropertyId(formProperty.getId());
                one.setType(formProperty.getType());
                if ("enum".equals(formProperty.getType())) {
                    Map<String, String> map = formProperty.getFormValues().stream()
                            .collect(Collectors.toMap(FormValue::getId, FormValue::getName));
                    one.setFormValues(map);
                }
                one.setName(formProperty.getName());
                one.setDefaultValue(formProperty.getDefaultExpression());
                one.setTaskId(taskId);
                formdataList.add(one);
            });
        } else {
            formProperties.forEach(formProperty -> {
                formdataList.stream()
                        .filter(one -> formProperty.getId().equals(one.getFormPropertyId()))
                        .forEach(one -> {
                            one.setFormPropertyId(formProperty.getId());
                            one.setType(formProperty.getType());
                            if ("enum".equals(formProperty.getType())) {
                                Map<String, String> map = formProperty.getFormValues().stream()
                                    .collect(Collectors.toMap(FormValue::getId, FormValue::getName));
                                one.setFormValues(map);
                            }
                            one.setName(formProperty.getName());
                            one.setDefaultValue(formProperty.getDefaultExpression());
                        });
            });
        }

        return R.okList(formdataList);
    }

填写表单,根据返回的表单类型判断渲染就行,自定义类型还没搞,不知道怎么用,貌似activiti没有自定义的这种

吐槽:

公司的开发4组之前买了一个工作流,集成到项目被客户否了,正好我们经理想给报表模块做个审核流程,然后任务分给了准备离职的我(天天写bug没意思,想去搞点别的),本来没想搞到公司项目(直接拿人家项目跑一下就行,要用的时候再说),经理要集成到他的报表项目,没法子只能先集成到我项目里了,也算是从头到尾搞了一遍,差不多两周时间,中间也弄了些其他的.

之所以后台用activiti,一个是之前接触过,二是没想到前端部分也叫我弄,前端没写过多少,不熟,还好别人都写好了,直接粘贴,看着改,对比camunda和activiti的xml花了比较久,如果是新项目,前端用bpmn的话,后台用camunda会方便一点吧,camunda是从activiti分出来的,很多地方都一样

第一次写博客,从毕业论文之后就没写过这种东西了

最后,言多必失,好好工作,写bug也得认真,吐槽的话就留给自己或者好友吧

轻喷


//                          _ooOoo_                               //
//                         o8888888o                              //
//                         88" . "88                              //
//                         (| ^_^ |)                              //
//                         O\  =  /O                              //
//                      ____/`---'\____                           //
//                    .'  \\|     |//  `.                         //
//                   /  \\|||  :  |||//  \                        //
//                  /  _||||| -:- |||||-  \                       //
//                  |   | \\\  -  /// |   |                       //
//                  | \_|  ''\---/''  |   |                       //
//                  \  .-\__  `-`  ___/-. /                       //
//                ___`. .'  /--.--\  `. . ___                     //
//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
//      ========`-.____`-.___\_____/___.-`____.-'========         //
//                           `=---='                              //
//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
//             佛祖保佑       永不宕机     永无BUG                  //

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐