• 整合Activiti Modeler到业务系统(或BPM平台)


    http://www.kafeitu.me/activiti/2013/03/10/integrate-activiti-modeler.html

    1. 为什么要整合

    Activiti 5.10版本把原本独立的Activiti Modeler模块整合到了Activiti Explorer中,两者相结合使用起来很方便,通过Modeler设计的流程模型可以直接部署到引擎,也可以把已经部署的流程转换为Model从而在Modeler中编辑。

    在实际应用中也有这样的需求,把Modeler整合到业务系统中可以供管理员使用,或者作为BPM平台的一部分存在,很遗憾官方没有给出如何整合Modeler的文档。

    2. 整合工作

    2.1 下载源码

    首先需要从Github下载源码:https://github.com/Activiti/Activiti;可以直接用Git克隆,也可以下载zip格式的压缩包。

    2.2 复制文件

    复制的所有文件均在activiti-webapp-explorer2目录中。

    1. src/main/resources中的editor.html、stencilset.json、plugins.xml到项目源码的源码根目录,保证编译之后在classes根目录
    2. src/main/webapp中的api、editor、explorer、libs到项目的webapp目录(与WEB-INF目录同级)

    2.3 添加依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <dependency>
        <groupid>org.activiti</groupid>
        <artifactid>activiti-explorer</artifactid>
        <version>5.14</version>
        <exclusions>
            <exclusion>
                <artifactid>vaadin</artifactid>
                <groupid>com.vaadin</groupid>
            </exclusion>
            <exclusion>
                <artifactid>dcharts-widget</artifactid>
                <groupid>org.vaadin.addons</groupid>
            </exclusion>
            <exclusion>
                <artifactid>activiti-simple-workflow</artifactid>
                <groupid>org.activiti</groupid>
            </exclusion>
        </exclusions>
    </dependency>
    <dependency>
        <groupid>org.activiti</groupid>
        <artifactid>activiti-modeler</artifactid>
        <version>5.14</version>
    </dependency>

    2.4 添加Java类

    添加一个ExplorerRestApplication.java类保存到项目中,注册了一些REST路由。

    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
    package org.activiti.explorer.rest.application;
     
    import org.activiti.editor.rest.application.ModelerServicesInit;
    import org.activiti.rest.api.DefaultResource;
    import org.activiti.rest.application.ActivitiRestApplication;
    import org.activiti.rest.filter.JsonpFilter;
    import org.restlet.Restlet;
    import org.restlet.routing.Router;
     
    public class ExplorerRestApplication extends ActivitiRestApplication {
     
      public ExplorerRestApplication() {
        super();
      }
      /**
       * Creates a root Restlet that will receive all incoming calls.
       */
      @Override
      public synchronized Restlet createInboundRoot() {
        Router router = new Router(getContext());
        router.attachDefault(DefaultResource.class);
        ModelerServicesInit.attachResources(router);
        DiagramServicesInit.attachResources(router);
        JsonpFilter jsonpFilter = new JsonpFilter(getContext());
        jsonpFilter.setNext(router);
        return jsonpFilter;
      }
     
    }

    2.5 配置web.xml

    在web.xml文件中添加如下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <!-- Restlet adapter, used to expose modeler functionality through REST -->
    <servlet>
        <servlet-name>RestletServlet</servlet-name>
        <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
        <init-param>
            <!-- Application class name -->
            <param-name>org.restlet.application</param-name>
            <param-value>org.activiti.explorer.rest.application.ExplorerRestApplication</param-value>
        </init-param>
    </servlet>
     
    <!-- Catch all service requests -->
    <servlet-mapping>
        <servlet-name>RestletServlet</servlet-name>
        <url-pattern>/service/*</url-pattern>
    </servlet-mapping>

    2.6 控制器

    使用Spring MVC做了一个简单的封装,也可以使用其他的MVC实现。

    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
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    package me.kafeitu.demo.activiti.web.workflow;
     
    import java.io.ByteArrayInputStream;
    import java.util.List;
     
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
     
    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.RepositoryService;
    import org.activiti.engine.repository.Deployment;
    import org.activiti.engine.repository.Model;
    import org.apache.commons.io.IOUtils;
    import org.apache.commons.lang3.StringUtils;
    import org.codehaus.jackson.JsonNode;
    import org.codehaus.jackson.map.ObjectMapper;
    import org.codehaus.jackson.node.ObjectNode;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.PathVariable;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.servlet.ModelAndView;
    import org.springframework.web.servlet.mvc.support.RedirectAttributes;
     
    /**
     * 流程模型控制器
     *
     * @author henryyan
     */
    @Controller
    @RequestMapping(value = "/workflow/model")
    public class ModelController {
     
      protected Logger logger = LoggerFactory.getLogger(getClass());
     
      @Autowired
      RepositoryService repositoryService;
     
      /**
       * 模型列表
       */
      @RequestMapping(value = "list")
      public ModelAndView modelList() {
        ModelAndView mav = new ModelAndView("workflow/model-list");
        List<model> list = repositoryService.createModelQuery().list();
        mav.addObject("list", list);
        return mav;
      }
     
      /**
       * 创建模型
       */
      @RequestMapping(value = "create")
      public void create(@RequestParam("name") String name, @RequestParam("key") String key, @RequestParam("description") String description,
              HttpServletRequest request, HttpServletResponse response) {
        try {
          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, name);
          modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
          description = StringUtils.defaultString(description);
          modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
          modelData.setMetaInfo(modelObjectNode.toString());
          modelData.setName(name);
          modelData.setKey(StringUtils.defaultString(key));
     
          repositoryService.saveModel(modelData);
          repositoryService.addModelEditorSource(modelData.getId(), editorNode.toString().getBytes("utf-8"));
     
          response.sendRedirect(request.getContextPath() + "/service/editor?id=" + modelData.getId());
        } catch (Exception e) {
          logger.error("创建模型失败:", e);
        }
      }
     
      /**
       * 根据Model部署流程
       */
      @RequestMapping(value = "deploy/{modelId}")
      public String deploy(@PathVariable("modelId") String modelId, RedirectAttributes redirectAttributes) {
        try {
          Model modelData = repositoryService.getModel(modelId);
          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() + ".bpmn20.xml";
          Deployment deployment = repositoryService.createDeployment().name(modelData.getName()).addString(processName, new String(bpmnBytes)).deploy();
          redirectAttributes.addFlashAttribute("message", "部署成功,部署ID=" + deployment.getId());
        } catch (Exception e) {
          logger.error("根据模型部署流程失败:modelId={}", modelId, e);
        }
        return "redirect:/workflow/model/list";
      }
     
      /**
       * 导出model的xml文件
       */
      @RequestMapping(value = "export/{modelId}")
      public void export(@PathVariable("modelId") String modelId, HttpServletResponse response) {
        try {
          Model modelData = repositoryService.getModel(modelId);
          BpmnJsonConverter jsonConverter = new BpmnJsonConverter();
          JsonNode editorNode = new ObjectMapper().readTree(repositoryService.getModelEditorSource(modelData.getId()));
          BpmnModel bpmnModel = jsonConverter.convertToBpmnModel(editorNode);
          BpmnXMLConverter xmlConverter = new BpmnXMLConverter();
          byte[] bpmnBytes = xmlConverter.convertToXML(bpmnModel);
     
          ByteArrayInputStream in = new ByteArrayInputStream(bpmnBytes);
          IOUtils.copy(in, response.getOutputStream());
          String filename = bpmnModel.getMainProcess().getId() + ".bpmn20.xml";
          response.setHeader("Content-Disposition", "attachment; filename=" + filename);
          response.flushBuffer();
        } catch (Exception e) {
          logger.error("导出model的xml文件失败:modelId={}", modelId, e);
        }
      }
     
    }
    </pre>
     
    ### 2.7 注意事项
     
    如果使用Spring代理引擎,并且在项目中同时有activiti.cfg.xml文件(不管在main/resources还是test/resources目录),在activiti.cfg.xml里面的引擎中添加下面的配置参数,否则会导致打开Modeler的编辑页面时读取数据返回**204**状态码。
     
    <pre class="brush:xml"><property name="processEngineName" value="test"></property>
    </pre>
     
    引擎默认名称为default,ProcessEngines.getDefaultProcessEngine()查询时会先检索main/resources,然后再检索test/resources的activiti.cfg.xml和activiti-context.xml文件,所以当main/resources监测不到指定文件时就会导致该引擎被当做web应用的引擎对象,这样会导致有两个引擎,所以把引擎的名称改为非默认的“default”。
     
    ## 3. 中文乱码问题解决办法
     
    在JVM参数中添加参数:
     
    > -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8
     
    **参考**:[在Activiti Modeler中设计的流程包含奇数个中文时不能部署问题](http://forums.activiti-cn.org/forum.php?mod=viewthread&tid=50&fromuid=2)
     
    ## 4. 效果截图
     
    在最新的kft-activiti-demo版本(1.7.0)中已经集成了Activiti Modeler,可以在线访问,也可以下载源码学习如何配置。
     
    登录[http://demo.kafeitu.me/kft-activiti-demo](http://demo.kafeitu.me/kft-activiti-demo)后选择**流程管理**->**模型工作区**菜单项即可。
     
    ![kft-activiti-demo中的效果截图](/files/2013/03/kft-activiti-demo-model-workspace.png)
    ![kft-activiti-demo中的效果截图](/f
  • 相关阅读:
    嵌入式为什么要用Linux操作系统
    SPI 协议的理解
    跳转某指定地址、给某绝对地址赋值
    define 宏定义
    笔试--编程题
    spring 技巧集锦
    spring data jpa auditing
    spring security
    Python基础笔记
    调试EF源代码环境配置
  • 原文地址:https://www.cnblogs.com/telwanggs/p/7570704.html
Copyright © 2020-2023  润新知