整合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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM