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

转载于:https://www.cnblogs.com/telwanggs/p/7570704.html

整合Activiti Modeler到业务系统(或BPM平台)相关推荐

  1. 灵活高效可支撑复杂业务系统的BPM平台

    单据开发过程示例: 以上从数据模型到基本单据生成,10分钟之内即可完成,提供在线所见即所得的单据格式设计器以及单据事件编写器. 审批流相关 OA表单示例 审批待办的微信实时推送 待办事项 手机单据联查 ...

  2. 集成新版(5.17+)Activiti Modeler与Rest服务

    声明: 此教程适合Activiti 5.17+版本. 本博客所涉及的内容均可在kft-activiti-demo中找到. 在线demo可以访问 http://demo.kafeitu.me:8080/ ...

  3. GlobalAuthenticationConfigurerAdapter.class 整合activiti 工作流报错

    package com.byd; import org.springframework.boot.SpringApplication; import org.springframework.boot. ...

  4. 不同业务场景Cas客户端(Java业务系统)接入

    概述 场景一.网站部分文章需要Cas认证(登录平台)通过后才能访问 1.通过拦截器,把文章访问路径进行拦截,判断当前文章是否需要cas认证 2.如果需要认证,那么调用CAS服务端进行认证,成功后回调地 ...

  5. 商业智能 BI 跟业务系统的思维差异

    我们在跟企业的沟通过程中经常发现,很多企业还是分不清商业智能 BI 跟一般的业务信息化系统定位.用户.思维层面上的差异.因为在企业的IT信息化规划中,基础的业务系统建设一定是走在前面的,有了这些系统基 ...

  6. 中国建设银行综合前端业务系统典型应用案例

    项目背景 中国建设银行成立于1954年10月1日,是中国四大国有股份制商业银行之一.中国建设银行为客户提供全面的商业银行产品与服务,业务领域包括公司银行业务.个人银行业务和资金业务,尤其以中长期信贷业 ...

  7. 业务系统如何集成工作流系统?_K2 BPM集成能力讲解

    在云计算和互联网时代,共享和开放是一个不断演进的话题.单枪匹马地完成所有事,不再成为企业运营的主流思维.全业务链端到端的业务,必然是从企业内延伸到企业外,必然会与外部的系统接轨.于是,集成成为了一个重 ...

  8. BPM平台在企业业务系统中使用的价值讨论

    1. 企业应用系统的分类以及BPM这种平台分别在这两种不同类型系统中的作用 因为在系统建设之前,我们要分清楚,准备建设的系统属于那一类 ,目前企业应用系统大体我觉得可以分以下几类 A)  垂直的业务系 ...

  9. 统一门户与业务系统的sso整合技术方案(单点登录)

    一.单点登录(SSO,Single Sign On)整合 目前计划接入统一门户的所有业务系统均为基于JavaEE技术的B/S架构系统.由于统一门户的单点登录技术选用的是JA-SIG组织开发的Cas S ...

最新文章

  1. 算法:不同二叉搜索树||
  2. FPGA---多按键消抖检测
  3. 智能优化算法:磷虾群算法-附代码
  4. Centos7二进制安装Mysql8.0.20
  5. 苍井空是如何勾搭上社交电商的? - 案例 - i黑马网
  6. rtl8111gr服务器系统,6款主板板载网卡对比
  7. php调用API支付接口 可个人使用,无需营业执照(使用第三方接口,调用的天工接口。)...
  8. awd的批量脚本 pwn_记一次AWD反杀之旅
  9. 【Unity2D】实现人物死亡动画+代码
  10. PTA每日一题-Python-身份证校验
  11. C语言的函数是什么?
  12. 灰色关联度矩阵--基于Matlab
  13. 函数的信息传递(C语言实践)
  14. 三:Lambda表达式
  15. 大数据-NoSQL数据库:HBase【基于Zookeeper/HDFS的分布式、高并发、可扩展的NoSQL数据库;支持“十亿行”ד百万列”海量数据的实时随机读写;仅支持单表查询;不擅长数据分析】
  16. Visiom Transformer 代码实现--ViT
  17. 北邮通信土著--非技术路线备忘录
  18. eth_clockgen.v
  19. C++ 农夫过河问题
  20. 爱立信软件测试英语笔试题,爱立信测试平台(dallas)开发岗位offer咨询

热门文章

  1. HBase数据读取流程解析
  2. (4)ISE14.7 ChipScope使用流程(FPGA不积跬步101)
  3. (132)FPGA面试题-Verilog实现格雷码转二进制
  4. (42)Xilinx FIFO IP核配置(三)(第9天)
  5. (03)FPGA与CPLD区别
  6. 计算时间间隔分钟_九个小技巧,玩转Excel的时间计算
  7. 图像的频率谱和功率谱代表什么_使用 FastAI 和即时频率变换进行音频分类
  8. arm交叉编译jsoncpp
  9. 网络协议栈深入分析(四)--套接字内核初始化和创建过程
  10. 【LeetCode】剑指 Offer 58 - I. 翻转单词顺序