1、阅读说明
网络上有很多关于Activiti整合SpringBoot的文章,但是都不全面,按照那些文章的思路整合还得耗时良久,今天抽空写下这篇文章,以帮助大家进行傻瓜式整合,从0到1,完整呈现整合的全过程。
此文章为SpringBoot2整合Activiti6设计器形成基于Activiti6的web项目实例的指导文档,整合工具使用的idea。从零开始,详尽的罗列了每一步整合步骤。需要一定整合者要有一定的技术基础,需要了解maven、springboot、activiti、js前端及h5相关的基础技术。
2、准备资料
- activiti-6.0.0官方实例:Activiti6的官方代码实例,可从官网下载,也可从我的网盘下载,链接: https://pan.baidu.com/s/1Eh_jrM6nSJ2fEnNSRAmwOQ , 提取码: n822;
- activiti-5.22.0(官方):Activiti5.22.0的官方代码实例,由于官方从6.0开始就不再提供在线设计器,所以只能使用5.22版本的设计器代码。可从官网下载,也可从我的网盘下载,链接: https://pan.baidu.com/s/138oGBrpCsoTK7MNfU3kUPw , 提取码: wrfi;
- stencilset.json:Activiti汉化包,网上很多,直接搜索文件名就能找到,也可从我网盘下辖,链接: https://pan.baidu.com/s/1uDNe4R8aXdSXdf10UJJ9lw,提取码: 6q5c;
- bootstrap-3.3.7-dist.zip:bootstrap的类库,做页面时使用。可从官网下载,也可从我的网盘下载,链接: https://pan.baidu.com/s/1z-_PMPF8vBZCJZQhFlCVAw, 提取码: w6wk。
3、整合过程
3.1、创建数据库
解压 activiti-6.0.0官方实例 ,根据自己安装的数据库版本选择相应的activiti6数据库创建sql。解压后,sql存放路径:\activiti-6.0.0\database\create。创建完成后,会有28张表,我使用的数据库名称为“actbase”。
3.2、创建一个简单的SpringBoot项目
此步骤为创建SpringBoot项目,没有什么特殊,若熟悉springboot项目,此步可以略过。
3.3、整合设计器资源代码到项目
由于activiti官方在5.22.0以上版本不再提供在线设计器,所以,我们的在线设计器仍然使用5.22.0版本。并将activiti5.22.0官方示例中的actiti-explorer.war包中的diagram-viewer、editor-app、favicon.ico 放入springboot静态资源目录static中;
将modeler.html(工作流编辑器页面)放到templates目录下;
将汉化文件stencilset.json 放到 resources 目录下;
将bootstrap-3.3.7-dist 类及jquery库放入项目静态资源目录static的js目录下,以备前端页面使用。
整合后台代码:提取activiti-5.22.0\libs\activiti-modeler-5.22.0-sources.jar中的相关代码类,具体目录是:activiti-modeler-5.22.0-sources.jar\org\activiti\rest\editor\model\ModelEditorJsonRestResource.java(此类用于在线编辑器编辑工作流模型)、activiti-modeler-5.22.0-sources.jar\org\activiti\rest\editor\model\ModelSaveRestResource.java(此类用于保存工作流模型)、activiti-modeler-5.22.0-sources.jar\org\activiti\rest\editor\main\StencilsetRestResource.java(此类用于汉化在线编辑器)放到项目中。
至此,设计器所需的资源与代码整合完毕。
3.4、整合配置文件
pom.xml文件:主要引入Druid DataSource数据源、mysql、Activiti6.0及xml图形 这4中类库。
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>2.2.5.RELEASE</version>
- <relativePath/> <!-- lookup parent from repository -->
- </parent>
- <groupId>com.act</groupId>
- <artifactId>act</artifactId>
- <version>0.0.1-SNAPSHOT</version>
- <name>act</name>
- <description>act6-apringboot2 project</description>
- <properties>
- <java.version>1.8</java.version>
- <activiti.version>6.0.0</activiti.version>
- <xmlgraphics.version>1.7</xmlgraphics.version>
- <druid.version>1.1.10</druid.version>
- <mysqlconnector.version>5.1.44</mysqlconnector.version>
- </properties>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-thymeleaf</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-test</artifactId>
- <scope>test</scope>
- <exclusions>
- <exclusion>
- <groupId>org.junit.vintage</groupId>
- <artifactId>junit-vintage-engine</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
- <!-- Druid DataSource -->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid-spring-boot-starter</artifactId>
- <version>${druid.version}</version>
- </dependency>
- <!-- mysql -->
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-java</artifactId>
- <version>${mysqlconnector.version}</version>
- </dependency>
- <!-- Activiti6.0 相关类库 -->
- <dependency>
- <groupId>org.activiti</groupId>
- <artifactId>activiti-spring-boot-starter-basic</artifactId>
- <version>${activiti.version}</version>
- </dependency>
- <dependency>
- <groupId>org.activiti</groupId>
- <artifactId>activiti-json-converter</artifactId>
- <version>${activiti.version}</version>
- <exclusions>
- <exclusion>
- <groupId>org.activiti</groupId>
- <artifactId>activiti-bpmn-model</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
- <!-- xml 图像类库 -->
- <dependency>
- <groupId>org.apache.xmlgraphics</groupId>
- <artifactId>batik-codec</artifactId>
- <version>${xmlgraphics.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.xmlgraphics</groupId>
- <artifactId>batik-css</artifactId>
- <version>${xmlgraphics.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.xmlgraphics</groupId>
- <artifactId>batik-svg-dom</artifactId>
- <version>${xmlgraphics.version}</version>
- </dependency>
- <dependency>
- <groupId>org.apache.xmlgraphics</groupId>
- <artifactId>batik-svggen</artifactId>
- <version>${xmlgraphics.version}</version>
- </dependency>
- </dependencies>
- <build>
- <plugins>
- <plugin>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-maven-plugin</artifactId>
- <configuration>
- <executable>true</executable>
- </configuration>
- </plugin>
- </plugins>
- </build>
- </project>
application.yml文件:与普通springboot项目的yml文件基本相同,主要配置数据源及项目名。
- server:
- port: 80
- servlet:
- context-path: /act
- debug: false #设置开发及调试模式
- spring:
- thymeleaf:
- prefix: classpath:/templates/ #thymeleaf 所在路径
- suffix: .html #thymeleaf 后缀
- mode: HTML5 #thymeleaf 采用的标准
- encoding: UTF-8 #thymeleaf 编码格式
- http:
- encoding:
- charset: UTF-8
- mvc:
- date-format: yyyy-MM-dd #时间参数的格式化
- jackson:
- time-zone: GMT+8 #默认为格林尼治时间,设置为北京时间
- date-format: yyyy-MM-dd HH:mm:ss SSS #设置时间的json的格式
- profiles:
- active: loc #指定数据源
- datasource:
- type: com.alibaba.druid.pool.DruidDataSource
- activiti: #activiti rest 配置
- rest-api-enabled: true
- rest-api-servlet-name: activiti-swagger-document
- SpringProcessEngineConfiguration:
- activityFontName: 宋体
- labelFontName: 宋体
- dataSource: datasource
- ---
- #数据源
- spring:
- profiles: loc
- datasource:
- url: jdbc:mysql://localhost:3306/actbase?useUnicode=true&characterEncoding=utf-8&useSSL=false
- username: root
- password: 123456
3.5、修改代码
整合的设计器代码只是能够满足官方设计器的使用,如果要整合成我们自己的web项目进行使用,还得根据自己项目的情况进行部分代码的修改与增加。
- 加映射:为ModelEditorJsonRestResource.java、ModelSaveRestResource.java(此类用于保存工作流模型)、StencilsetRestResource.java(此类用于汉化在线编辑器)这三个类加入映射访问路径 @RequestMapping("service")。
- 修改ModelSaveRestResource参数:将“@RequestBody MultiValueMap<String, String> values”的传参方式改为单个参数传参。
- 加入默认工作流文件:系统启动时默认加载工作流文件,建立一个文件放进去即可。
- 修改app-cfg.js文件:系统启动时默认加载工作流文件,建立一个文件放进去即可。
- 修改modeler.html页面的js路径:根据自己的项目映射名称修改。
3.6、添加工作流控制器
添加工作流控制器ActivitiCtrl用于工作流的增删改查等操作,并与页面对接,作为操作工作流在线设计器的入口。
- package com.act.controller;
- import com.fasterxml.jackson.databind.JsonNode;
- import com.fasterxml.jackson.databind.ObjectMapper;
- import com.fasterxml.jackson.databind.node.ObjectNode;
- import org.activiti.bpmn.model.BpmnModel;
- import org.activiti.editor.constants.ModelDataJsonConstants;
- import org.activiti.editor.language.json.converter.BpmnJsonConverter;
- import org.activiti.engine.HistoryService;
- import org.activiti.engine.RepositoryService;
- import org.activiti.engine.RuntimeService;
- import org.activiti.engine.repository.Deployment;
- import org.activiti.engine.repository.Model;
- import org.activiti.engine.runtime.ProcessInstance;
- 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.GetMapping;
- import org.springframework.web.bind.annotation.RequestMapping;
- import org.springframework.web.bind.annotation.ResponseBody;
- import org.springframework.web.servlet.ModelAndView;
- import javax.servlet.http.HttpServletResponse;
- import java.io.IOException;
- import java.util.HashMap;
- import java.util.List;
- import java.util.Map;
- /**
- * 工作流操作类
- * @author yangyicai
- */
- @Controller
- public class ActititiCtrl {
- //日志
- private static final Logger logger = LoggerFactory.getLogger(ActititiCtrl.class);
- @Autowired
- //流程服务组件:用于流程定义和存取
- private RepositoryService repositoryService;
- @Autowired
- //历史服务组件:用于获取正在运行或已经完成的流程实例的信息
- private HistoryService historyService;
- @Autowired
- //运行时服务组件:提供了启动流程、查询流程实例、设置获取流程实例变量等功能。
- private RuntimeService runtimeService;
- @Autowired
- //数据模型转换
- private ObjectMapper objectMapper;
- /**
- * 首页控制器:获取工作流模型列表控制器
- *
- * @param modelAndView 页面对象
- * @return 返回页面对象
- */
- @RequestMapping("/")
- public ModelAndView index(ModelAndView modelAndView) {
- modelAndView.setViewName("index");
- //通过流程服务组件获取当前的工作流模型列表
- List<Model> actList = repositoryService.createModelQuery().list();
- modelAndView.addObject("actList", actList);
- return modelAndView;
- }
- /**
- * 跳转编辑器/编辑工作流页面
- *
- * @return
- */
- @GetMapping("/editor")
- public String editor() {
- return "modeler";
- }
- /**
- * 创建模型
- *
- * @param response
- */
- @RequestMapping("/create")
- public void create(HttpServletResponse response) throws IOException {
- //创建一个空模型
- Model model = repositoryService.newModel();
- //设置一下默认信息
- String modelName = "new-model";//模型名称
- String modelKey = "new-key";// 模型key
- String modelDescription = ""; //模型描述
- int modelVersion = 1; //默认版本号
- ObjectNode modelNode = objectMapper.createObjectNode();
- modelNode.put(ModelDataJsonConstants.MODEL_NAME, modelName);
- modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, modelDescription);
- modelNode.put(ModelDataJsonConstants.MODEL_REVISION, modelVersion);
- model.setName(modelName);
- model.setKey(modelKey);
- model.setMetaInfo(modelNode.toString());
- repositoryService.saveModel(model);
- createObjectNode(model.getId());
- response.sendRedirect("/act/editor?modelId=" + model.getId());
- logger.info("创建模型结束,返回模型ID:{}", model.getId());
- }
- /**
- * 创建模型时完善ModelEditorSource
- *
- * @param modelId
- */
- @SuppressWarnings("/deprecation")
- private void createObjectNode(String modelId) {
- logger.info("创建模型完善ModelEditorSource入参模型ID:{}", modelId);
- 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);
- try {
- repositoryService.addModelEditorSource(modelId, editorNode.toString().getBytes("utf-8"));
- } catch (Exception e) {
- logger.info("创建模型时完善ModelEditorSource服务异常:{}", e);
- }
- logger.info("创建模型完善ModelEditorSource结束");
- }
- /**
- * 发布流程
- *
- * @param modelId 模型ID
- * @return
- */
- @ResponseBody
- @RequestMapping("/publish")
- public Object publish(String modelId) {
- logger.info("流程部署入参modelId:{}", modelId);
- Map<String, String> map = new HashMap<String, String>();
- try {
- Model modelData = repositoryService.getModel(modelId);
- byte[] bytes = repositoryService.getModelEditorSource(modelData.getId());
- if (bytes == null) {
- logger.info("部署ID:{}的模型数据为空,请先设计流程并成功保存,再进行发布", modelId);
- map.put("code", "FAILURE");
- return map;
- }
- JsonNode modelNode = new ObjectMapper().readTree(bytes);
- BpmnModel model = new BpmnJsonConverter().convertToBpmnModel(modelNode);
- Deployment deployment = repositoryService.createDeployment()
- .name(modelData.getName())
- .addBpmnModel(modelData.getKey() + ".bpmn20.xml", model)
- .deploy();
- modelData.setDeploymentId(deployment.getId());
- repositoryService.saveModel(modelData);
- map.put("code", "SUCCESS");
- } catch (Exception e) {
- logger.info("部署modelId:{}模型服务异常:{}", modelId, e);
- map.put("code", "FAILURE");
- }
- logger.info("流程部署出参map:{}", map);
- return map;
- }
- /**
- * 撤销流程定义
- *
- * @param modelId 模型ID
- * @return
- */
- @ResponseBody
- @RequestMapping("/revokePublish")
- public Object revokePublish(String modelId) {
- logger.info("撤销发布流程入参modelId:{}", modelId);
- Map<String, String> map = new HashMap<String, String>();
- Model modelData = repositoryService.getModel(modelId);
- if (null != modelData) {
- try {
- /**
- * 参数不加true:为普通删除,如果当前规则下有正在执行的流程,则抛异常
- * 参数加true:为级联删除,会删除和当前规则相关的所有信息,包括历史
- */
- repositoryService.deleteDeployment(modelData.getDeploymentId(), true);
- map.put("code", "SUCCESS");
- } catch (Exception e) {
- logger.error("撤销已部署流程服务异常:{}", e);
- map.put("code", "FAILURE");
- }
- }
- logger.info("撤销发布流程出参map:{}", map);
- return map;
- }
- /**
- * 删除流程实例
- *
- * @param modelId 模型ID
- * @return
- */
- @ResponseBody
- @RequestMapping("/delete")
- public Object deleteProcessInstance(String modelId) {
- logger.info("删除流程实例入参modelId:{}", modelId);
- Map<String, String> map = new HashMap<String, String>();
- Model modelData = repositoryService.getModel(modelId);
- if (null != modelData) {
- try {
- //先删除流程实例,再删除工作流模型
- ProcessInstance pi = runtimeService.createProcessInstanceQuery().
- processDefinitionKey(modelData.getKey()).singleResult();
- if (null != pi) {
- runtimeService.deleteProcessInstance(pi.getId(), "");
- historyService.deleteHistoricProcessInstance(pi.getId());
- }
- //删除流程模型
- repositoryService.deleteModel(modelId);
- map.put("code", "SUCCESS");
- } catch (Exception e) {
- logger.error("删除流程实例服务异常:{}", e);
- map.put("code", "FAILURE");
- }
- }
- logger.info("删除流程实例出参map:{}", map);
- return map;
- }
- }
3.7、添加工作流操作页面
该页面(index.html)用于创建、部署、撤销、删除、编辑工作流的测试,此页面使用前端框架bootstrap-3.3.7-dist与模板引擎 Thymeleaf 编写(可根据自己的需求选择前端框架)。用于对接ActititiCtrl控制器。
- <!DOCTYPE html>
- <html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
- <head>
- <meta charset="UTF-8">
- <title>工作流模型列表</title>
- <link rel="stylesheet" href="/act/js/bootstrap-3.3.7-dist/bootstrap.min.css">
- <script src="/act/js/jquery-3.4.1.min.js"></script>
- <script src="/act/js/bootstrap-3.3.7-dist/bootstrap.min.js"></script>
- </head>
- <body>
- <div class="panel panel-default" style="margin: 10px" >
- <div class="panel-heading">工作流管理</div>
- <div class="panel-body">
- <a href="/act/create" target="_blank">
- <button type="button" class="btn btn-default" aria-label="Left Align">
- 创建模型
- </button>
- </a>
- </div>
- <table class="table">
- <thead>
- <tr>
- <th width="10%">模型编号</th>
- <th width="10%">版本</th>
- <th width="20%">模型key</th>
- <th width="30%">模型名称</th>
- <th width="30%">操作</th>
- </tr>
- </thead>
- <tbody>
- <tr th:each="actModel,actStat:${actList}">
- <th scope="row" th:text="${actModel.id}"></th>
- <td th:text="${actModel.version}"></td>
- <td th:text="${actModel.key}"></td>
- <td th:text="${actModel.name}"></td>
- <td>
- <a th:href="@{'/publish?modelId='+${actModel.id}}" >部署</a>
- <a th:href="@{'/revokePublish?modelId='+${actModel.id}}">撤销</a>
- <a th:href="@{'/editor?modelId='+${actModel.id}}">编辑</a>
- <a th:href="@{'/delete?modelId='+${actModel.id}}">删除</a>
- </td>
- </tr>
- </tbody>
- </table>
- </div>
- </body>
- </html>
4、整合效果展示
工作流列表页
创建工作流模型页面
编辑工作流模型页面