Grails + Activiti + Activiti Modeler

                                                  Grails + Activiti + Activiti Modeler 整合詳解


 

  1. 本次整合使用 activiti 的版本爲5.22
  2. 需要下載的文件  war包  和  源碼
  3. 下載jar地址:https://github.com/Activiti/Activiti/releases/tag/activiti-5.22.0

  4. 下載完成後,將兩個zip文件解壓

activiti-5.22.0 目錄下找到 wars 裏面的兩個 war包,將它們放到 tomcat 的 webapp 目錄下,啓動tomcat ,啓動後,我們修改解壓後的db.db.properties 文件,文件所在目錄: activiti-explorer\WEB-INF\classes 下

訪問地址:http://localhost:8090/activiti-explorer/ 就可以看見它自身所帶的流程前端控制器

在你連接的數據中的 act_id_user 表中,選擇一個用戶進行登錄 就可以看到 它身的 前端流程控制器

 搭建屬於我們自己的前端流程控制器 grails + activiti 5.22

// https://mvnrepository.com/artifact/org.activiti/activiti-engine
    compile group: 'org.activiti', name: 'activiti-engine', version: '5.22.0'
    // https://mvnrepository.com/artifact/org.activiti/activiti-spring
    compile group: 'org.activiti', name: 'activiti-spring', version: '5.22.0'
    // https://mvnrepository.com/artifact/org.activiti/activiti-bpmn-model
    compile group: 'org.activiti', name: 'activiti-bpmn-model', version: '5.22.0'
    // https://mvnrepository.com/artifact/org.activiti/activiti-json-converter
    compile group: 'org.activiti', name: 'activiti-json-converter', version: '5.22.0'
    // https://mvnrepository.com/artifact/org.activiti/activiti-bpmn-layout
    compile group: 'org.activiti', name: 'activiti-bpmn-layout', version: '5.22.0'
    
    // https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-transcoder
    compile group: 'org.apache.xmlgraphics', name: 'batik-transcoder', version: '1.7'
    // https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-css
    compile group: 'org.apache.xmlgraphics', name: 'batik-css', version: '1.7'
    // https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-svg-dom
    compile group: 'org.apache.xmlgraphics', name: 'batik-svg-dom', version: '1.7'
    // https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-svggen
    compile group: 'org.apache.xmlgraphics', name: 'batik-svggen', version: '1.7'
    // https://mvnrepository.com/artifact/org.apache.xmlgraphics/batik-codec
    compile group: 'org.apache.xmlgraphics', name: 'batik-codec', version: '1.7'


    // https://mvnrepository.com/artifact/mysql/mysql-connector-java
    compile group: 'mysql', name: 'mysql-connector-java', version: '5.1.17'

     5.將 Activiti-activiti-5.22.0\modules\activiti-webapp-explorer2\src\main\webapp 目錄下的兩個目錄和一個個文件複製到 grails 的webapp 目錄下面

  1. idea 創建一個 grails 項目
  2. 到 maven 創庫中去導入所需要的 activiti 5.22 的 jar 
  3. maven 創庫地址:http://mvnrepository.com/
  4. 需要導入的  jar  (activi 工作流引擎的jar  以及 avg 生產圖片的 jar)

    6.將 Activiti-activiti-5.22.0\modules\activiti-webapp-explorer2\src\main\resources 下的 stencilset.json 複製到 conf 目錄下

  7.將 Activiti-activiti-5.22.0\modules\activiti-modeler\src\main\java\org\activiti\rest\editor 目錄下的 兩個目錄裏面的三個 java 文件取出來 

     StencilsetRestResource.java : 頁面顯示資源的獲取的接口 修改爲 groovy 語法格式

     ModelEditorJsonRestResource.java :流程模型資源的獲取的接口  修改爲groovy 語法格式

     ModelSaveRestResource.java  :流程模型獲取後修改編輯保存的接口 修改爲 groovy 語法格式

  8.修改後的代碼如下:

package com.activiti
import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.node.ObjectNode
import grails.converters.JSON
import grails.io.IOUtils
import org.activiti.bpmn.converter.BpmnXMLConverter
import org.activiti.bpmn.model.BpmnModel
import org.activiti.editor.constants.ModelDataJsonConstants
import org.activiti.editor.language.json.converter.BpmnJsonConverter
import org.activiti.engine.ActivitiException
import org.activiti.engine.ProcessEngine
import org.activiti.engine.ProcessEngines
import org.activiti.engine.RepositoryService
import org.activiti.engine.repository.Deployment
import org.activiti.engine.repository.Model
import org.activiti.engine.runtime.ProcessInstance
import org.apache.batik.transcoder.TranscoderInput
import org.apache.batik.transcoder.TranscoderOutput
import org.apache.batik.transcoder.image.PNGTranscoder
import org.apache.commons.lang.StringUtils
class ActivitController {
    def index() {

    }
    ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine()
    RepositoryService repositoryService = processEngine.getRepositoryService()
    ObjectMapper objectMapper = new ObjectMapper()
    /**根據Id獲取創建的模板信息*/
    def getEditorJson(){
        def record = request.JSON ?: params
        ObjectNode modelNode = null
        Model model = repositoryService.getModel(record.id)
        if (model != null) {
            try {
                if (StringUtils.isNotEmpty(model.getMetaInfo())) {
                    modelNode = (ObjectNode) objectMapper.readTree(model.getMetaInfo())
                } else {
                    modelNode = objectMapper.createObjectNode()
                    modelNode.put("name", model.getName())
                }
                modelNode.put("modelId", model.getId())
                ObjectNode editorJsonNode = (ObjectNode) objectMapper.readTree(new String(repositoryService.getModelEditorSource(model.getId()), "utf-8"))
                modelNode.put("model",editorJsonNode)

            } catch (Exception e) {
                throw new ActivitiException("Error creating model JSON", e)
            }
        }
        render modelNode
    }
  /**保存修改的模型*/
  def saveModel() {
        def record =  params
        try {
            Model model = repositoryService.getModel(record.id)
            ObjectNode modelJson = (ObjectNode) objectMapper.readTree(model.getMetaInfo())
            modelJson.put("name", record.name);
            modelJson.put("description", record.description)
            model.setMetaInfo(modelJson.toString())
            model.setName(record.name)
            repositoryService.saveModel(model)
            repositoryService.addModelEditorSource(model.getId(), record.json_xml.getBytes("utf-8"))
            InputStream svgStream = new ByteArrayInputStream(record.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)
            final byte[] result = outStream.toByteArray()
            repositoryService.addModelEditorSourceExtra(model.getId(), result)
            outStream.close()
        } catch(Exception e){
                throw new ActivitiException("Error saving model", e)
        }
      render true

    }
    def getStencilset() {
        InputStream stencilsetStream = this.getClass().getClassLoader().getResourceAsStream("stencilset.json")
        try {
            render IOUtils.toString(stencilsetStream, "utf-8")
        } catch (Exception e) {
            throw new ActivitiException("Error while loading stencil set", e)
        }
    }
    /** 新建一個空模型 */
    def newModel(){
        def record = request.JSON ?: params
        def modelId = []
        RepositoryService repositoryService = processEngine.getRepositoryService()
        //初始化一個空模型
         Model model = repositoryService.newModel()
        //設置一些默認信息
        int revision = 1
        String key = "process"
        ObjectNode modelNode = objectMapper.createObjectNode()
        modelNode.put(ModelDataJsonConstants.MODEL_NAME, record.name)
        modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, record.description)
        modelNode.put(ModelDataJsonConstants.MODEL_REVISION, revision)
        model.setName(record.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"))
        modelId.add(id)
        render modelId
    }
    /** 獲取所有模型 */
    def modelList(){
        RepositoryService repositoryService = processEngine.getRepositoryService()
        render repositoryService.createModelQuery().list() as JSON
    }
    /** 發佈模型爲流程定義 */
    def deploy(){
        def record = request.JSON ?: params
        //獲取模型
        Model modelData = repositoryService.getModel(record.id)
        byte[] bytes = repositoryService.getModelEditorSource(modelData.getId())
        if (bytes == null) {
            render "模型數據爲空,請先設計流程併成功保存,再進行發佈"
        }
        JsonNode modelNode = new ObjectMapper().readTree(bytes)
        BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode)
        if(model.getProcesses().size()==0){
            render "數據模型不符要求,請至少設計一條主線流程"
        }
        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)
        render true
    }
    /**啓動流程*/
    def startProcess() {
        def record = request.JSON ?: params
        ProcessInstance process = processEngine.getRuntimeService().startProcessInstanceByKey(record.keyName)
        render process.getId() + " : " + process.getProcessDefinitionId()
    }
}

    9.編輯 訪問路徑

設置  UrlMappings 訪問路徑

package activitimodeler

class UrlMappings {

    static mappings = {
        "/$controller/$action?/$id?(.$format)?"{
            constraints {
                // apply constraints here
            }
        }
        get  "/$controller/$id(.$format)?/json"(action:"getEditorJson")
        put  "/$controller/$id(.$format)?/save"(action:"saveModel")
        get  "/$controller/editor/stencilset"(action: "getStencilset")
        post "/$controller/create"(action: "newModel")
        get  "/$controller/modelList"(action: "modelList")
        get  "/$controller/deploy"(action: "deploy")
        get  "/$controller/start"(action: "startProcess")
        "500"(view:'/error')
        "404"(view:'/notFound')
    }
}

修改前端訪問接口的路徑

editor-app目錄下的app-cfg.js 文件 'contextRoot' : '/Activit', 設置訪問後臺接口路徑的前綴

editor-app——>configuration——>url-config.js 設置訪問路徑 接口的路徑

editor-app ——>enitor——>oryx.debug.js 設置訪問 獲取 stencilset.json(前臺資源文件) 的路徑

最後將 stencilset.json 文件 以及 editor-app\i18n\en.json 文件 變爲 中文解釋

當這一切都準備好了之後,啓動 grails ,啓動完成後 訪問地址:http://localhost:8080/modeler.html   就可以看到 頁面上的信息

代碼中的功能涉及:模板創建、獲取所有模板、獲取單個模板、修改模板、保存修改的模板、發佈模型爲流程定義、啓動流程

 

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