• 集成Activiti-Modeler流程设计器


    集成Activiti-Modeler流程设计器

    Activiti Modeler 是 Activiti 官方提供的一款在线流程设计的前端插件,可以方便流程设计与开发人员绘制流程图,保存流程模型,部署至流程定义等等。

    1、材料准备
    首先我们需要获取activiti-explorer.zip,这个是activiti-5.22.0才有的。

    链接:https://pan.baidu.com/s/1zZ8vcjR63_hgzcLl6soiDw
    提取码:1e8a

    2、集成
    2.1 集成静态资源

    在这里插入图片描述
    其中的editor-app就是编辑器,modeler.html是编辑器的入口页面。
    diagram-viewer是流程跟踪插件,虽然这次用不着,但之后会用到。

    还有一个界面组件文件,在resource下,名称叫stencilset.json。本身是英文的,可以通过替换它来达到汉化的效果。但现在还是先把它放到项目中去。
    在这里插入图片描述
    在editor-app/app-cfg.js中配置一下项目url。这个url是编辑器相关的后台服务的url。

    ACTIVITI.CONFIG = {
        'contextRoot' : '/service',
    };
    
    • 1
    • 2
    • 3

    我去掉了项目名。

    3.后端部分
    先引入两个activiti的模块,因为编辑器会用到这两个模块。

      <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-modeler</artifactId>
            <version>${activiti.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-diagram-rest</artifactId>
            <version>${activiti.version}</version>
        </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    其中需要将modeler模块的源代码放到src中,因为需要在其中做部分修改,主要是url的映射。

    源码:
    https://github.com/Activiti/Activiti/tree/master/modules/activiti-modeler

    其中有3个类,都是Controller:

    StencilsetRestResource #获取编辑器组件及配置项信息。
    ModelEditorJsonRestResource #根据modelId获取model的节点信息,编辑器根据返回的json进行绘图。
    ModelSaveRestResource #编辑器制图之后,将节点信息以json的形式提交给这个Controller,然后由其进行持久化操作。
    
    • 1
    • 2
    • 3

    需要修改的地方就三个,在每个Controller类上加上@RequestMapping注解,并指定值为"service"(对应前台app-cfg.js中配置的url)。

    ···
    @RequestMapping("service")
    public class StencilsetRestResource {
    ···
    
    • 1
    • 2
    • 3
    • 4
    ···
    @RequestMapping("service")
    public class ModelEditorJsonRestResource implements ModelDataJsonConstants {
    ···
    
    • 1
    • 2
    • 3
    • 4
    ···
    @RequestMapping("service")
    public class ModelSaveRestResource implements ModelDataJsonConstants {
    ···
    
    • 1
    • 2
    • 3
    • 4

    最后别忘了添加包扫描,扫描activiti提供的这些controller。

    @SpringBootApplication
    @ComponentScan({"org.activiti","com.jerryl"})
    public class SpringBootWithActivitiApplication {
    ···
    
    • 1
    • 2
    • 3
    • 4

    这样整合部分就基本结束了,此时编辑器已经可以使用了。

    至于界面的汉化,界面上各个组件,各个标签上的文字都是在resource下的stencilset.json文件中设置的,可以在网上找一个汉化后的stencilset.json文件替换掉,就能看到中文界面了。

    modeler相关方法的封装
    主要需要封装4个方法:1.新建一个空的模型;2.所有模型列表;3.发布模型;4.删除模型;(activiti已提供了保存和获取模型节点信息的方法,就是上面的那3个类)
    由于这里涉及前后端交互,实现方式随意,主要是activiti的api的调用。

    参考代码:

    /**
     * Created by liuruijie on 2017/2/21.
     * 模型管理
     */
    @RestController
    @RequestMapping("models")
    public class ModelerController {
    
        @Autowired
        ProcessEngine processEngine;
        @Autowired
        ObjectMapper objectMapper;
    
        /**
         * 新建一个空模型
         * @return
         * @throws UnsupportedEncodingException
         */
        @PostMapping
        public Object newModel() throws UnsupportedEncodingException {
            RepositoryService repositoryService = processEngine.getRepositoryService();
            //初始化一个空模型
            Model model = repositoryService.newModel();
    
            //设置一些默认信息
            String name = "new-process";
            String description = "";
            int revision = 1;
            String key = "process";
    
            ObjectNode modelNode = objectMapper.createObjectNode();
            modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision);
    
            model.setName(name);
            model.setKey(key);
            model.setMetaInfo(modelNode.toString());
    
            repositoryService.saveModel(model);
            String id = model.getId();
    
            //完善ModelEditorSource
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace",
                    "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);
            repositoryService.addModelEditorSource(id,editorNode.toString().getBytes("utf-8"));
            return ToWeb.buildResult().redirectUrl("/modeler.html?modelId="+id);
        }
    
        /**
         * 获取所有模型
         * @return
         */
        @GetMapping
        public Object modelList(){
            RepositoryService repositoryService = processEngine.getRepositoryService();
            List<Model> models = repositoryService.createModelQuery().list();
            return ToWeb.buildResult().putData("models", models);
        }
    
        /**
         * 删除模型
         * @param id
         * @return
         */
        @DeleteMapping("{id}")
        public Object deleteModel(@PathVariable("id")String id){
            RepositoryService repositoryService = processEngine.getRepositoryService();
            repositoryService.deleteModel(id);
            return ToWeb.buildResult().refresh();
        }
    
        /**
         * 发布模型为流程定义
         * @param id
         * @return
         * @throws Exception
         */
        @PostMapping("{id}/deployment")
        public Object deploy(@PathVariable("id")String id) throws Exception {
    
            //获取模型
            RepositoryService repositoryService = processEngine.getRepositoryService();
            Model modelData = repositoryService.getModel(id);
            byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
    
            if (bytes == null) {
                return ToWeb.buildResult().status(Config.FAIL)
                        .msg("模型数据为空,请先设计流程并成功保存,再进行发布。");
            }
    
            JsonNode modelNode = new ObjectMapper().readTree(bytes);
    
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            if(model.getProcesses().size()==0){
                return ToWeb.buildResult().status(Config.FAIL)
                        .msg("数据模型不符要求,请至少设计一条主线流程。");
            }
            byte[] bpmnBytes = new BpmnXMLConverter().convertToXML(model);
    
            //发布流程
            String processName = modelData.getName() + ".bpmn20.xml";
            Deployment deployment = repositoryService.createDeployment()
                    .name(modelData.getName())
                    .addString(processName, new String(bpmnBytes, "UTF-8"))
                    .deploy();
            modelData.setDeploymentId(deployment.getId());
            repositoryService.saveModel(modelData);
    
            return ToWeb.buildResult().refresh();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117

    springboot静态文件处理

    @Configuration
    public  class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry){
            registry.addResourceHandler("/html/**").addResourceLocations("classpath:/html/");
            registry.addResourceHandler("/diagram-viewer/**").addResourceLocations("classpath:/html/");
            registry.addResourceHandler("/editor-app/**").addResourceLocations("classpath:/html/");
            registry.addResourceHandler("/js/**").addResourceLocations("classpath:/js/");
            registry.addResourceHandler("/css/**").addResourceLocations("classpath:/css/");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    获取json数据的请求

    @RestController
    public class Test01Controller {
    
        @RequestMapping("/editor/stencilset")
        public String test01(){
            InputStream stream=this.getClass().getClassLoader().getResourceAsStream("stencilset.json");
            try{
                return IOUtils.toString(stream,"utf-8");
            }catch (Exception e){
    
            }
            return null;
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    在线设计流程新建model

    @Controller
    @RequestMapping("model")
    public class ModelTest {
    
        @RequestMapping("create")
        public void createModel(HttpServletRequest request, HttpServletResponse response){
            try{
                String modelName = "modelName6";
                String modelKey = "modelKey66";
                String description = "modelKey666";
    
                ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
    
                RepositoryService repositoryService = processEngine.getRepositoryService();
    
                ObjectMapper objectMapper = new ObjectMapper();
                ObjectNode editorNode = objectMapper.createObjectNode();
                editorNode.put("id", "canvas");
                editorNode.put("resourceId", "canvas");
                ObjectNode stencilSetNode = objectMapper.createObjectNode();
                stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
                editorNode.put("stencilset", stencilSetNode);
                Model modelData = repositoryService.newModel();
    
                ObjectNode modelObjectNode = objectMapper.createObjectNode();
                modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, modelName);
                modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
                modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
                modelData.setMetaInfo(modelObjectNode.toString());
                modelData.setName(modelName);
                modelData.setKey(modelKey);
    
                //保存模型
                repositoryService.saveModel(modelData);
                repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
                response.sendRedirect(request.getContextPath() + "/html/modeler.html?modelId=" + modelData.getId());
            }catch (Exception e){
            }
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    画流程图保存请求

    @RequestMapping("/model/{modelId}/save")
        @ResponseStatus(HttpStatus.OK)
        public void saveModel(@PathVariable String modelId, HttpServletRequest req, HttpServletResponse resp) {
            try {
                Model model = this.repositoryService.getModel(modelId);
                ObjectNode modelJson = (ObjectNode)this.objectMapper.readTree(model.getMetaInfo());
                modelJson.put("name", req.getParameter("name"));
                modelJson.put("description",req.getParameter("description"));
                model.setMetaInfo(modelJson.toString());
                model.setName(req.getParameter("name"));
                this.repositoryService.saveModel(model);
                this.repositoryService.addModelEditorSource(model.getId(), (req.getParameter("json_xml")).getBytes("utf-8"));
                InputStream svgStream = new ByteArrayInputStream((req.getParameter("svg_xml")).getBytes("utf-8"));
                TranscoderInput input = new TranscoderInput(svgStream);
                PNGTranscoder transcoder = new PNGTranscoder();
                ByteArrayOutputStream outStream = new ByteArrayOutputStream();
                TranscoderOutput output = new TranscoderOutput(outStream);
                transcoder.transcode(input, output);
                byte[] result = outStream.toByteArray();
                System.out.println(new String(result,"utf-8"));
                this.repositoryService.addModelEditorSourceExtra(model.getId(), result);
                outStream.close();
            } catch (Exception var11) {
                LOGGER.error("Error saving model", var11);
                throw new ActivitiException("Error saving model", var11);
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    流程图查看的请求

    @RequestMapping(
                value = {"/model/{modelId}/json"},
                method = {RequestMethod.GET},
                produces = {"application/json"}
        )
        public ObjectNode getEditorJson(@PathVariable String modelId) {
            ObjectNode modelNode = null;
            Model model = this.repositoryService.getModel(modelId);
            if (model != null) {
                try {
                    if (StringUtils.isNotEmpty(model.getMetaInfo())) {
                        modelNode = (ObjectNode)this.objectMapper.readTree(model.getMetaInfo());
                    } else {
                        modelNode = this.objectMapper.createObjectNode();
                        modelNode.put("name", model.getName());
                    }
    
                    modelNode.put("modelId", model.getId());
                    ObjectNode editorJsonNode = (ObjectNode)this.objectMapper.readTree(new String(this.repositoryService.getModelEditorSource(model.getId()), "utf-8"));
                    modelNode.put("model", editorJsonNode);
                } catch (Exception var5) {
                    LOGGER.error("Error creating model JSON", var5);
                    throw new ActivitiException("Error creating model JSON", var5);
                }
            }
    
            return modelNode;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    流程图保存成功以后ACT_RE_MODEL这张表会有数据

    在这里插入图片描述

    程图部署以后ACT_GE_BYTEARRAY会出现bomn结尾的文件
    在这里插入图片描述

    部署流程的请求,根据modelId

    @RequestMapping("/model/test02")
        public void test02(Object obj) throws Exception {
            Model modelData = repositoryService.getModel("40001");
            ObjectNode modelNode = (ObjectNode) new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
            byte[] bpmnBytes = null;
    
            BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
            bpmnBytes = new BpmnXMLConverter().convertToXML(model);
    
            String processName = modelData.getName() + ".bpmn";
    
            Deployment deployment = repositoryService.createDeployment()
                    .name(modelData.getName()).addString(processName, new String(bpmnBytes,"UTF-8"))
                    .deploy();
    
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    根据这个表的key进行流程启动,指定审批人
    在这里插入图片描述

  • 相关阅读:
    十进制转换成2进制
    【Mysql系列】03_系统设计
    芯源&立创EDA训练营——无刷电机驱动
    学习 C++ 编程,怎么才能找到合适的练手项目?
    在深度迁移学习中,什么是源域,什么是目标域?
    ubuntu20.04下锁屏快捷键super+L不能用的解决方法
    Echarts 配置项 series 中的 data 是多维度
    文心一言 VS 讯飞星火 VS chatgpt (104)-- 算法导论10.1 2题
    【AGC】引导用户购买提升用户留存率
    【Docker】docker网络
  • 原文地址:https://blog.csdn.net/weixin_45817985/article/details/132851789