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

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

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);

    }

  }

 

}

</model>

2.7 注意事项

如果使用Spring代理引擎,并且在项目中同时有activiti.cfg.xml文件(不管在main/resources还是test/resources目录),在activiti.cfg.xml里面的引擎中添加下面的配置参数,否则会导致打开Modeler的编辑页面时读取数据返回204状态码。

?


1

<property

name
="processEngineName"

value
="test"></property>

引擎默认名称为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中设计的流程包含奇数个中文时不能部署问题

4. 效果截图

在最新的kft-activiti-demo版本(1.7.0)中已经集成了Activiti Modeler,可以在线访问,也可以下载源码学习如何配置。

登录http://demo.kafeitu.me/kft-activiti-demo后选择流程管理->模型工作区菜单项即可。

时间: 2024-09-15 16:41:34

整合Activiti Modeler到业务系统(或BPM平台)的相关文章

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

声明: 此教程适合Activiti 5.17+版本. 本博客所涉及的内容均可在kft-activiti-demo中找到. 在线demo可以访问 http://demo.kafeitu.me:8080/kft-activiti-demo 菜单路径:管理模块 -> 流程管理 -> 模型工作区,可以『创建』或者『编辑』模型 1. 简介 上一篇介绍整合Activiti Modeler<整合Activiti Modeler到业务系统(或BPM平台)>已经有2年多时间了,自从Activiti

Activiti Modeler发布以及教程

1.新版Activiti Modeler简介 在Activiti 5.6版本之前把Activiti Modeler作为压缩包的一部分,但是后来不再这么做而是需要开发人员自己根据Signavio打包Activiti Modeler,我之前层写过一篇博文讲解如何打包:<如何使用Signavio打包Activiti Modeler>. 但是现在不需要自己打包了,官方已经基于Signavio开发了新版的Activiti Modeler,新版的特点如下: 完全针对Activiti定制开发,支持目前Act

3.2在Activiti Explorer中使用Activiti Modeler

3.2在Activiti Explorer中使用Activiti Modeler 从5.11版本开始官方提供的压缩包发生了较大变化(参考2.1.1节):把重新设计的Activiti Modeler整合到了Activiti Explorer中,可以直接创建新模型然后部署到引擎中,也可以根据已有的流程定义创建模型,修改后可以直接把最新的修改部署到引擎. 由于Activiti Modeler组件需要依赖REST服务,因此读者要了解如何把Activiti Modeler集成到自己的项目中,相关内容可参考

提供多业务系统无缝对接实现企业协同办公信息化

企业信息化管理软件正式进入云时代 本报讯 与同事相隔千里却需要进行协同办公和召开会议怎么办?企业和部门间使用的业务软件系统过多,不停地在诸如OA.ERP.CRM.EIM.行政审批.网站订单系统.客户故障处理系统等业务软件间进行频繁的切换不仅效率不高,而且极易出现疏漏和失误怎么办?企业对业务软件系统的管理.升级和维护跟不上怎么办?类似以上的这些问题,一直以来都直接影响着现代企业的发展步伐,也是企业管理人员心中一个长久无法解开的结. 近日,作为"广东省企业综合信息服务平台示范基地"的广东群

在线教育业务系统云上高可用部署架构设计

从2010年开始,国内新兴的在线教育公司已经越来越多选用公共云计算做为IT基础设施平台.在线教育公司使用云计算,一方面可以减少在IT基础设施方面设备及人力的投入,另一方面可以轻松获得可扩展的计算能力以及更加可靠的安全防护能力. 通过对多家在线教育公司IT部门的交流,由于在线教育公司大多处于业务发展期,IT部门的精力主要投入到支撑新业务的拓展,在应用的部署架构上考虑的不多,在高可用架构方面更是欠缺. 众所周知,云平台是一个及其复杂的综合系统,内外部的一些偶然因素可能导致其发生局部的故障,如果用户在

浙江联通开启云计算平台 承载多套业务系统

诗人徐志摩说:我挥一挥衣袖,不带走一片云彩.在还没有云计算的年代,这样的意境令人向往.而现在,世界即将进入移动互联网时代,在云计算技术的帮助下,人们将可以"挥一挥衣袖,把一切载上云端". 好消息是,不用等太久,我们真的可以这样潇洒自在了.为了适应以云计算为主要特征的移动互联网时代需求,浙江联通已经开始着手建设新业务快速部署平台,并且已承载多套云计算新业务系统. 什么是云计算?简单理解就是,相关公司提供服务器.应用程序.存储空间,用户通过网络远程登录服务器,按照需要使用这些存储空间和应用

《Power Designer系统分析与建模实战》——第3章 业务处理模型BPM

第3章 业务处理模型BPM 业务处理模型(Business Process Model,BPM)是一系列用于分析.设计.实现执行业务处理流程的术语或标准的集合.它使得业务分析师和管理员人员能够分析系统,使其合理化和优化.本章首先介绍BPM的概念以及图形分类,接着讲解如何在Power Designer中创建.编辑和管理BPM,以及BPM与其余模型的转换方法,最后通过"餐饮在线点评系统",使读者巩固BPM的相关知识和注意事项.

万户OA与SAP整合,全面集成重要业务信息!

随着信息化建设的推进,很多企业为了提高管理水平和业务流程,建设了多套IT系统,如ERP.CRM.OA.财务软件等等.伴随着系统应用的增多,信息孤岛现象难免会出现.企业迫切需要一个平台,理顺各个信息化系统中的数据关系,打破信息孤岛,实现数据的互享互通.如何实现系统间的无缝对接,更好的发挥系统应用价值,是很多用户关注的问题,而在这其中,实现OA与SAP的整合集成,又是很多大型企业关注的重点. 为什么要集成? SAP ERP系统是当今最强大的业务处理平台之一,它以业务流程为主线,对人.财.物等资源进行

邮储银行大数据平台一期上线 接入24个业务系统数据

日前,中国邮政储蓄银行大数据平台一期工程成功上线,这意味着邮储银行在推进大数据技术应用方面取得了重大进展. 据报道,邮储银行大数据平台工程于2013年10月通过方案评审,2014年7月完成立项,2015年全面启动,历经架构研究.应用探索.技术攻关.工程实施等阶段,截至目前,已完成3个hadoop集群93台x86服务器的部署和上线,完成176个节点数据仓库的建设和投产,总数据容量2.27pb,达到国内金融业的领先水平. 据悉,该平台已接入行内24个重要业务系统的数据,同时积极引入行外非结构化数据,