Spring Boot2 + Activiti6 集成在線流程設計器 Activiti modoler(3)

前言

上篇文章介紹瞭如何在Spring Boot2集成activiti6

接下來,小編會一步一步的介紹如何集成在線設計器

Activiti Modoler 介紹

什麼是 Activiti Modoler 呢,簡單的說就是一個在線畫流程圖功能模塊,它是 Activiti 實現的

雖然說可以通過eclipse、idea等插件去設計畫流程圖

但是有時候是需要客戶動態創建並設計流程圖,所以這裏就需要把在線設計器集成進自己項目中

所以說,我們要做的就是把 Activiti Modoler 相關模塊集成到自己項目中

注意,Activiti 並沒有提供接口,這裏我們只能通過源碼去一步一步集成進來,廢話不多說,下面開始

引入文件

首先,maven需要引入新的包(多了很多)

		<dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter-actuator</artifactId>
            <version>6.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-modeler</artifactId>
            <version>5.23.0</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-json-converter</artifactId>
            <version>6.0.0</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-diagram-rest</artifactId>
            <version>5.23.0</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-rest</artifactId>
            <version>5.23.0</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-codec</artifactId>
            <version>1.12</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-io</artifactId>
                    <groupId>commons-io</groupId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-css</artifactId>
            <version>1.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-svg-dom</artifactId>
            <version>1.12</version>
        </dependency>

        <dependency>
            <groupId>org.apache.xmlgraphics</groupId>
            <artifactId>batik-svggen</artifactId>
            <version>1.12</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-explorer</artifactId>
            <version>5.23.0</version>
        </dependency>

        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-simple-workflow</artifactId>
            <version>5.23.0</version>
        </dependency>

然後,我們需要下載 Activiti 開源包

github:地址https://github.com/Activiti/Activiti/tree/5.x.

下載完解壓後,第一步先引入前端文件,位置分別在

\modules\activiti-webapp-explorer2\src\main\webapp
\modules\activiti-webapp-explorer2\src\main\resources

在這裏插入圖片描述在這裏插入圖片描述
圈中的都複製到項目中:
在這裏插入圖片描述


第二步開始引入後端文件,位置分別在

\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\model
\modules\activiti-modeler\src\main\java\org\activiti\rest\editor\main

在這裏插入圖片描述

也都複製到項目中:
在這裏插入圖片描述

代碼編寫

首先修改前端的代碼,找到 \editor-app\app-cfg.js 文件,把 contextRoot 對應屬性路徑刪了變成空字符

var ACTIVITI = ACTIVITI || {};

ACTIVITI.CONFIG = {
	'contextRoot' : '',
};

編寫控制層類跳轉方法,由於在線流程設計器需要 Model 才能初始化,所以在跳轉到該頁面去需要創建 Model,代碼如下:

ModelerController.java

package com.ssactiviti.activiti.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Controller
@RequestMapping("/modeler")
public class ModelerController {

    @Resource
    private RepositoryService repositoryService;

    @Resource
    private ObjectMapper objectMapper;

    /**
     * 添加模型
     */
    @GetMapping("/save")
    public void save(HttpServletResponse response) throws IOException {

        //創建模型
        Model modelData = repositoryService.newModel();

        ObjectNode modelObjectNode = objectMapper.createObjectNode();
        //模型名稱
        modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, "請假");
        //模型版本
        modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
        //模型詳情
        modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, "請假詳情");
        //以字符串信息存儲進信息屬性中
        modelData.setMetaInfo(modelObjectNode.toString());
        //模型名稱
        modelData.setName("請假");
        //模型key
        modelData.setKey("leave");

        //完善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.set("stencilset", stencilSetNode);

        //添加模型
        repositoryService.saveModel(modelData);
        repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes(StandardCharsets.UTF_8));

        response.sendRedirect("/static/activiti/modeler.html?modelId=" + modelData.getId());
    }

}

這裏因爲 Springmvc 會攔截靜態資源,所以需要配置靜態資源不攔截

MvcConfig.java

package com.ssactiviti.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
@EnableWebMvc
class MvcConfig implements WebMvcConfigurer {

	@Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        //定義一個convert轉換消息的對象
        FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
        //添加fastjson的配置信息
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        fastJsonConfig.setCharset(StandardCharsets.UTF_8);
        fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);

        //處理中文亂碼問題
        List<MediaType> fastMediaTypes = new ArrayList<>();
        fastMediaTypes.add(MediaType.APPLICATION_JSON);

        //在convert中添加配置信息.
        fastConverter.setSupportedMediaTypes(fastMediaTypes);
        fastConverter.setFastJsonConfig(fastJsonConfig);
        //將convert添加到converters中
        converters.add(fastConverter);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
        registry.addResourceHandler("/templates/**").addResourceLocations("classpath:/templates/");
    }

	/**
     * 接收PUT、DELETE等請求參數
     * @return
     */
    @Bean
    public FormContentFilter formContentFilter() {
        return new FormContentFilter();
    }
    
}

開始運行程序,訪問 http://127.0.0.1:8080/modeler/save,彈出該頁面證明整合成功:

在這裏插入圖片描述

踩坑記

坑點1: js前臺報這個錯

TypeError: Cannot read property ‘namespace’ of undefined

在這裏插入圖片描述
小編第一次也踩過這個坑,網上相關描述也非常少

這裏Spring Boot2默認採用jackson,當項目使用fastjson的時候,就會出現json轉換異常的問題

也就是 ModelEditorJsonRestResource.java 裏面的 getEditorJson() 方法返回了字符串,而不是 json 格式的數據導致的

解決辦法就是把返回結果轉換成 json 返回,方法返回改成Object,這裏小編用的是 fastjson,所以對應方法是:

return JSONObject.parseObject(modelNode.toString());

坑點2: js前臺報這個錯

TypeError: Cannot read property ‘split’ of undefined

在這裏插入圖片描述
小編也踩過這個坑…導致這個坑的原因有兩個

第一檢查是否引入了 stencilset.json 文件,並且文件路徑是否正確,默認存放resources下級目錄
在這裏插入圖片描述

第二和坑點一同理,只需要在 StencilsetRestResource.java 裏面的 getStencilset() 方法返回轉成 json 即可

return JSONObject.parseObject(IOUtils.toString(stencilsetStream, "utf-8"));

坑點3: 保存模型的時候報錯:

org.springframework.web.HttpMediaTypeNotSupportedException: Content type ‘application/x-www-form-urlencoded;charset=UTF-8’ not supported

這裏只需要在ModelSaveRestResource.java裏面,把方法參數改成如下即可:

@RequestMapping(value="/model/{modelId}/save", method = RequestMethod.PUT)
  @ResponseStatus(value = HttpStatus.OK)
  public void saveModel(@PathVariable String modelId, String name, String description, String json_xml, String svg_xml) {
    try {
      
      Model model = repositoryService.getModel(modelId);
      
      ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo());
      
      modelJson.put(MODEL_NAME, name);
      modelJson.put(MODEL_DESCRIPTION, description);
      model.setMetaInfo(modelJson.toString());
      model.setName(name);
      
      repositoryService.saveModel(model);
      
      repositoryService.addModelEditorSource(model.getId(), json_xml.getBytes("utf-8"));
      
      InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
      TranscoderInput input = new TranscoderInput(svgStream);
      
      PNGTranscoder transcoder = new PNGTranscoder();
      // Setup output
      ByteArrayOutputStream outStream = new ByteArrayOutputStream();
      TranscoderOutput output = new TranscoderOutput(outStream);
      
      // Do the transformation
      transcoder.transcode(input, output);
      final byte[] result = outStream.toByteArray();
      repositoryService.addModelEditorSourceExtra(model.getId(), result);
      outStream.close();
      
    } catch (Exception e) {
      LOGGER.error("Error saving model", e);
      throw new ActivitiException("Error saving model", e);
    }
  }

這幾個問題出現的比較多,一般解決了就基本沒有問題了


漢化

漢化的過程非常簡單,只需要分別用中文版的 stencilset.json 和 en.json 替換下即可:
在這裏插入圖片描述
漢化之後的效果:
在這裏插入圖片描述
那麼基本代碼和效果也演示完畢了

demo也已經放到碼雲上,獲取方式在文章的Spring Boot2 + Activiti6 系列搭建教程開頭篇(1) 結尾處

謝謝大家~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章