SpringBoot2集成Activiti5.22及官方设计器

版本:
JDK:1.8
Spring Boot:2.6.7
Activiti:5.22.0
Idea:2020.3

Spring Boot集成activiti

Spring Boot集成activiti很简单,pom文件中添加如下依赖即可:

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter-basic</artifactId>
    <version>${activiti.version}</version>
</dependency>

下面是详细说明:

打开Idea,选择File -> New -> Project...

选择Spring Initializr,下一步

输入项目名activiti-demo,Java版本选择8以上,下一步:


选择项目所需依赖,这里我们选择MySQL数据库驱动和Spring Web(Activiti的依赖这里搜不到,一会儿我们手动加),继续下一步:


项目名称及存放路径,点完成:


创建项目后,打开pom.xml文件,添加上面说的Activiti依赖:


打开项目启动类ActivitiDemoApplication,修改@SpringBootApplication注释,添加exclude:

package com.example.activitidemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication(
        exclude = {
                //activiti-spring-boot-starter-basic中的配置类,里面依赖了spring-security,不排除这个启动会报错
                org.activiti.spring.boot.SecurityAutoConfiguration.class})
public class ActivitiDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(ActivitiDemoApplication.class, args);
    }

}

修改配置文件application.properties,添加以下配置:

# 端口号,默认8080
server.port=8081
# 项目访问根路径
server.servlet.context-path=/activiti-demo

spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activiti-demo?characterEncoding=UTF-8&useUnicode=true&serverTimezone=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456

# activiti验证自动部署(默认开启),activiti会自动部署processes目录下的任何BPMN 2.0流程定义
# 如果开启,需要在resources下创建processes文件夹,并在其中创建流程定义(例如:one-task-process.bpmn20.xml)
# 否则启动项目时会报错:class path resource [processes/] cannot be resolved to URL because it does not exist
spring.activiti.check-process-definitions=false

至此,代码部分均已完成,就是这么简单!

官方文档说明:只是在Spring Boot项目中添加依赖,就会在幕后发生很多事情:

  • 自动创建了内存数据库(如果没有配置spring.datasource.url的话),并传递给Activiti流程引擎配置
  • 创建并暴露了Activiti ProcessEngine bean(Activiti核心类)
  • 所有的Activiti服务都暴露为Spring bean(如RuntimeService、TaskService等)
  • 创建了Spring Job Executor

并且,processes目录下的任何BPMN 2.0流程定义都会被自动部署。

Activiti连接数据库

接下来,创建数据库,我们只用到了Activiti提供的25张表。从官网(或我的百度云
下载Activiti项目,下载后解压,目录是这样的:

新建activiti-demo数据库(mysql),然后执行activiti-5.22.0/database/create/下的三个sql文件(activiti.mysql.create.engine.sql、activiti.mysql.create.history.sql、activiti.mysql.create.identity.sql),如果你用的别的数据库找对应数据库的sql文件,执行后得到下面25张表:

现在,就可以启动代码试试了!

activiti-spring-boot-starter-basic中依赖了spring-boot-starter-jdbcspring-boot-starter-jdbc会自动配置数据源DataSource,Activiti默认使用该数据源(完全不需要手动指定数据源)。详情请参考springactiviti的官方文档说明。

spring-boot-starter-jdbc会检查是否配置了spring.datasource.url,如果没有配置将使用内存数据库,具体使用哪种数据库取决于classpath中的数据库驱动。数据库连接池默认使用HikariCP

Activiti修改配置

添加配置类ActivitiConfig,实现ProcessEngineConfigurationConfigurer接口,注意要加注释@Component,否则Activiti找不到。

ProcessEngineConfigurationConfigurer源码释义:接口的实现类可以对SpringProcessEngineConfiguration(Activiti的配置类)进行一些额外的配置,如果定义了这样的实现类,流程引擎配置创建且设置了默认值后将会调用它。

可以在这里设置数据源、事务管理器、全局事件监听器等配置信息。例如,我们可以添加如下配置避免流程图出现中文乱码:

package com.example.activitidemo.config;

import org.activiti.spring.SpringProcessEngineConfiguration;
import org.activiti.spring.boot.ProcessEngineConfigurationConfigurer;
import org.springframework.stereotype.Component;

@Component
public class ActivitiConfig implements ProcessEngineConfigurationConfigurer {

    @Override
    public void configure(SpringProcessEngineConfiguration processEngineConfiguration) {
        processEngineConfiguration.setActivityFontName("宋体");
        processEngineConfiguration.setLabelFontName("宋体");
        processEngineConfiguration.setAnnotationFontName("宋体");
    }
}

引入官方流程设计器

其实Activiti已经为我们开发了一个web项目Activiti Explorer,里面包含了流程设计器、部署、任务管理等功能,我们要做的,就是把Activiti Explorer里流程设计器的相关代码引到自己的项目中来。

找到activiti-5.22.0/wars/activiti-explorer.war项目并解压,在resources下新建文件夹static/activiti,然后将activiti-explorer中的相关文件夹拷到static/activiti/下:


点击这里下载汉化包,放到static/activiti/下

然后需要修改app-cfg.js文件中的contextRoot:


找到activiti-5.22.0/libs/activiti-modeler-5.22.0-sources.jar并解压,将其中的三个类拷到项目中:

  • org.activiti.rest.editor.main.StencilsetRestResource.java 获取stencilset.json(流程设计器标签)
  • org.activiti.rest.editor.model.ModelEditorJsonRestResource.java 获取模型json数据
  • org.activiti.rest.editor.model.ModelSaveRestResource.java 保存模型

修改StencilsetRestResource:

修改ModelSaveRestResource:

用@RequestBody MultiValueMap<String, String> values来接会报错:Required request body is missing,我也不知道为啥,渴望哪位大佬路过来说下~~

pom.xml中添加activiti-modeler依赖:

activiti-modeler:Activiti建模组件:提供了保存模型、解析模型为json、获取stencilset.json(流程设计器标签)三个接口,已经把这三个类挪到demo项目中了(因为要改一些东西),但是没挪其它依赖,所以这里还是要把它放到pom中

<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-modeler</artifactId>
    <version>${activiti.version}</version>
</dependency>

启动类上还要排除一下org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class这个类,不排除的话,打开设计器时会跳转到spring-security登录界面:

添加ModelController类,写一个创建模型并打开流程设计器的接口:

package com.example.activitidemo.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Model;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@RestController
@RequestMapping("/model")
public class ModelController {

    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;

    /**
     * 创建模型后,打开流程设计器
     * @param request
     * @param response
     */
    @GetMapping("/create")
    public void create(HttpServletRequest request, HttpServletResponse response) {
        try {
            //初始化一个空模型
            Model model = repositoryService.newModel();
            //设置一些默认信息
            String name = request.getParameter("name");
            String description = request.getParameter("description");
            String key = request.getParameter("key");
            if (name == null || name == ""){
                name = "";
            }
            if (description == null || description == ""){
                description = "";
            }
            if (key == null || key == ""){
                key = "";
            }

            ObjectNode modelNode = objectMapper.createObjectNode();
            modelNode.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            modelNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);

            model.setName(name);
            model.setKey(key);
            model.setMetaInfo(modelNode.toString());

            // 保存模型
            repositoryService.saveModel(model);
            String id = model.getId();

            //完善ModelEditorSource
            ObjectNode editorNode = objectMapper.createObjectNode();
            editorNode.put("id", "canvas");
            editorNode.put("resourceId", "canvas");

            // 属性
            ObjectNode propertiesNode = objectMapper.createObjectNode();
            propertiesNode.put("process_id", model.getKey());
            propertiesNode.put("name", model.getName());
            editorNode.set("properties", propertiesNode);

             // 模板
            ObjectNode stencilSetNode = objectMapper.createObjectNode();
            stencilSetNode.put("namespace", "http://b3mn.org/stencilset/bpmn2.0#");
            editorNode.put("stencilset", stencilSetNode);

            //添加模型编辑器资源 act_ge_bytearray表会新增一条数据
            repositoryService.addModelEditorSource(id, editorNode.toString().getBytes("utf-8"));

            // 重定向到设计器界面
            response.sendRedirect(request.getContextPath() + "/activiti/modeler.html?modelId=" + id);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

ok,大功告成,启动项目并在浏览器上访问http://localhost:8081/activiti-demo/model/create?name=cs出现下面界面就对啦(新建了一个名称为cs的模型):

最后,附上项目结构:

image-20220429141357397.png

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容