版本:
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-jdbc,spring-boot-starter-jdbc会自动配置数据源DataSource,Activiti默认使用该数据源(完全不需要手动指定数据源)。详情请参考spring和activiti的官方文档说明。
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