整合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目录中。
- src/main/resources中的editor.html、stencilset.json、plugins.xml到项目源码的源码根目录,保证编译之后在classes根目录
 - 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();      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)后选择**流程管理**->**模型工作区**菜单项即可。的更多相关文章
- 两篇整合Activiti Modeler到业务系统
		
1. 无法进入editor. http://localhost:8080/YouPRJ/modeler/service/editor?id=2050,前提是这个id必需存在与act_re_model表 ...
 - 集成新版(5.17+)Activiti Modeler与Rest服务
		
声明: 此教程适合Activiti 5.17+版本. 本博客所涉及的内容均可在kft-activiti-demo中找到. 在线demo可以访问 http://demo.kafeitu.me:8080/ ...
 - 【Activiti学习之八】Spring整合Activiti
		
环境 JDK 1.8 MySQL 5.6 Tomcat 8 idea activiti 5.22 activiti-explorer是官方提供的一个演示项目,可以使用页面管理Activiti流程.ac ...
 - 运行带有Activiti modeler时,出现这样的报错:   java.rmi.AccessException: Cannot modify this registry
		
最近在做整合Activiti Modeler工作流在线设计器的工作,运行IDEA时,出现了这样一个错误信息: 原因及解决办法: Activiti默认打开了jmx功能,默认端口为1099,idea中 ...
 - 统一门户与业务系统的sso整合技术方案(单点登录)
		
一.单点登录(SSO,Single Sign On)整合目前计划接入统一门户的所有业务系统均为基于JavaEE技术的B/S架构系统.由于统一门户的单点登录技术选用的是JA-SIG组织开发的Cas Se ...
 - Activiti Modeler初探实践
		
以下内容对实践activiti很有用,不过我用的不是github下载的源码包编译出来的war包,不知道什么原因我打出来的包会有点问题.不过这不重要,换个地方下载来源就行,下载网址: http://dl ...
 - SSH框架集成Activiti Modeler在线设计器页面出现问号及乱码的解决办法
		
文·原创/朱季谦 工作流是一个针对企业用户.开发人员.系统管理员的轻量级工作流业务管理平台,其核心是使用Java开发的快速.稳定的BPMN2.0流程引擎.在我们日常开发当中,例如oa系统里的请假功能, ...
 - SSM整合activiti框架
		
一:WorkFlow简介 1:什么是工作流工作流(Workflow),指“业务过程的部分或整体在计算机应用环境下的自动化”.是对工作流程及其各操作步骤之间业务规则的抽象.概括描述.在计算机中,工作流属 ...
 - PowerDesigner 业务处理模型( BPM )
		
PowerDesigner 业务处理模型( BPM ) 说明 properties语言文档xmlvalidation数据库 目录(?)[+] 一. BPM 简介 业务处理模型(Busi ...
 
随机推荐
- Windows 异步IO操作
			
Windows提供了4种不同的方法来接收I/O请求已经完成的通知:触发设备内核对象.触发事件内核对象.可提醒I/O和I/O完成端口. Windows的异步I/O 当线程向设备发起一个I/O异步 ...
 - HttpServlet容器响应Web客户流程
			
HttpServlet容器响应Web客户请求流程如下: 1)Web客户向Servlet容器发出Http请求: 2)Servlet容器解析Web客户的Http请求: 3)Servlet容器创建一个Htt ...
 - SRM691 Sunnygraphs2
			
Problem Statement Hero has just constructed a very specific graph. He started with n isolated vertic ...
 - Gym 100531G Grave(水题)
			
题意:给定一个大矩形,再给定在一个小矩形,然后给定一个新矩形的长和高,问你能不能把这个新矩形放到大矩形里,并且不与小矩形相交. 析:直接判定小矩形的上下左右四个方向,能不能即可. 代码如下: #pra ...
 - SpringBoot项目以服务器方式启动
			
SpringBoot项目,如果未引入Web相关依赖,不会以服务器方式进行启动,会以应用的方式启动并结束 <dependency> <groupId>org.springfram ...
 - E20170521-ts
			
redirect vt. 使改寄,更改(信件等)姓名地址; 改变方向,改变线路; 重新寄送; teletype n. 电传打字机,电报交换机,打字电报通讯; descriptor n. 描述符; ...
 - 洛谷P1505 [国家集训队]旅游(树剖+线段树)
			
传送门 这该死的码农题…… 把每一条边变为它连接的两个点中深度较浅的那一个,然后就是一堆单点修改/路径查询,不讲了 这里就讲一下怎么搞路径取反,只要打一个标记就好了,然后把区间和取反,最大最小值交换然 ...
 - 图论算法->最短路
			
求最短路算法,有Floyd,dijkstra,Bellmanford,spfa等诸多高级算法.优化方法也是层出不穷. 我们不妨分析一下各算法的使用特点(可能不准确 1.Floyd算法 复杂度O(n³) ...
 - _bzoj2005 [Noi2010]能量采集
			
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=2005 令F(i)表示i | gcd(x, y)的对数,f(i)表示gcd(x, y) = i ...
 - 暴力 Codeforces Round #183 (Div. 2) A. Pythagorean Theorem II
			
题目传送门 /* 暴力:O (n^2) */ #include <cstdio> #include <algorithm> #include <cstring> # ...