Spring Boot+Activiti7入坑指南初阶版

介绍 

Activiti 是一个轻量级工作流程和业务流程管理 (BPM) 平台,面向业务人员、开发人员和系统管理员。其核心是一个超快且坚如磐石的 Java BPMN 2 流程引擎。它是开源的,并根据 Apache 许可证分发。Activiti 可以在任何 Java 应用程序、服务器、集群或云中运行。它与 Spring 完美集成,非常轻量级并且基于简单的概念。

官网地址:
Open Source Business Automation | Activiti

guithub地址:
GitHub – Activiti/Activiti: Activiti is a light-weight workflow and Business Process Management (BPM) Platform targeted at business people, developers and system admins. Its core is a super-fast and rock-solid BPMN 2 process engine for Java. It's open-source and distributed under the Apache license. Activiti runs in any Java application, on a server, on a cluster or in the cloud. It integrates perfectly with Spring, it is extremely lightweight and based on simple concepts.Activiti is a light-weight workflow and Business Process Management (BPM) Platform targeted at business people, developers and system admins. Its core is a super-fast and rock-solid BPMN 2 process engine for Java. It's open-source and distributed under the Apache license. Activiti runs in any Java application, on a server, on a cluster or in the cloud. It integrates perfectly with Spring, it is extremely lightweight and based on simple concepts. – GitHub – Activiti/Activiti: Activiti is a light-weight workflow and Business Process Management (BPM) Platform targeted at business people, developers and system admins. Its core is a super-fast and rock-solid BPMN 2 process engine for Java. It's open-source and distributed under the Apache license. Activiti runs in any Java application, on a server, on a cluster or in the cloud. It integrates perfectly with Spring, it is extremely lightweight and based on simple concepts.https://github.com/Activiti/Activiti?tab=readme-ov-file

插件安装

在idea插件中安装绘图插件

解决中文乱码

在IDEA中将File–>Settings–>Editor–>File Encodings修改为UTF-8
在IDEA的Help–>Edit Custom VM Options中末尾添加-Dfile.encoding=UTF-8
在IDEA的安装目录的bin目录下将idea.exe.vmoptions和idea64.exe.vmoptions两个文件末尾添加-Dfile.encoding=UTF-8
重启idea

Activiti7使用

创建Spring Boot项目

使用IDE中的Spring Boot项目创建向导,创建一个新的Spring Boot项目。

添加依赖

<?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.1.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>oa-activiti-workflow</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>oa-activiti-workflow</name>
    <description>oa-activiti-workflow</description>
    <url/>
    <licenses>
        <license/>
    </licenses>
    <developers>
        <developer/>
    </developers>
    <scm>
        <connection/>
        <developerConnection/>
        <tag/>
        <url/>
    </scm>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>8</java.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <activiti-dependencies.version>7.1.0.M3.1</activiti-dependencies.version>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.activiti.dependencies</groupId>
                <artifactId>activiti-dependencies</artifactId>
                <version>${activiti-dependencies.version}</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <artifactId>junit-jupiter</artifactId>
                    <groupId>org.junit.jupiter</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--activiti 7.x依赖 -->
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
            <!-- 由于activiti7是使用mybatis作为orm框架,我这里整合mybatis-plus,所以需要排除mybatis -->
            <exclusions>
                <exclusion>
                    <groupId>org.mybatis</groupId>
                    <artifactId>mybatis</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version> <!-- 或最新版本 -->
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus</artifactId>
            <version>3.1.0</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

配置数据库和Activiti配置

spring.application.name=oa-activiti-workflow
server.port=18080
# 数据库链接信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=root
spring.datasource.password=rootroot

# 配置mybatis plus打印sql日志
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl

# activiti配置
## 检测历史表是否存在 activiti7默认没有开启数据库历史记录 启动数据库历史记录
spring.activiti.db-history-used=true
# 记录历史等级 可配置的历史级别有none, activity, audit, full
## none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
## activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
## audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
## full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等
spring.activiti.history-level=full
## 1.false:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
## 2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
## 3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
## 4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
spring.activiti.database-schema-update=true
# 校验流程文件,默认校验resources下的processes文件夹里的流程文件
spring.activiti.check-process-definitions=false

启动类

package com.example.oaactivitiworkflow;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.JndiDataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.XADataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;

@SpringBootApplication(exclude = {
        //activiti 默认整合security,屏蔽Security认证
        SecurityAutoConfiguration.class,
        ManagementWebSecurityAutoConfiguration.class,
        JndiDataSourceAutoConfiguration.class,
        XADataSourceAutoConfiguration.class
})
public class OaActivitiWorkflowApplication {

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

}

注意事项

spring.activiti.database-schema-update=true配置完启动测试后,发现发生了报错无法自动创建表。报错内容如下

Caused by: org.activiti.engine.ActivitiException: Could not update Activiti database schema: unknown version from database: '8.1.0'

该错误是由于 
Activiti引擎版本与数据库架构版本不匹配 导致的。具体表现为:

数据库中记录的Activiti架构版本(schema.version)为8.1.0,但当前项目使用的Activiti依赖版本无法识别该版本号。
常见原因包括:

项目依赖的Activiti版本低于数据库中的架构版本。
数据库版本信息被手动修改或未正确初始化。
依赖冲突导致实际加载的Activiti版本与预期不符。

解决办法:

手动下载创建表的sql,地址:

Activiti/activiti-core/activiti-engine/src/main/resources/org/activiti/db/create at develop · Activiti/Activiti · GitHubActiviti is a light-weight workflow and Business Process Management (BPM) Platform targeted at business people, developers and system admins. Its core is a super-fast and rock-solid BPMN 2 process engine for Java. It's open-source and distributed under the Apache license. Activiti runs in any Java application, on a server, on a cluster or in the cloud. It integrates perfectly with Spring, it is extremely lightweight and based on simple concepts. – Activiti/activiti-core/activiti-engine/src/main/resources/org/activiti/db/create at develop · Activiti/Activitihttps://github.com/Activiti/Activiti/tree/develop/activiti-core/activiti-engine/src/main/resources/org/activiti/db/create

在数据库中执行创建:

修改版本信息,因为我使用的Activiti版本是7.1.0对应的scheme.version为7.0.0.0:

UPDATE ACT_GE_PROPERTY SET VALUE_ = '7.0.0.0' WHERE NAME_ = 'schema.version';

修改后启动build正常。

Activiti表介绍

Activiti 的表都以 ACT_ 开头。

Activiti 使用到的表都是 ACT_ 开头的。表名的第二部分用两个字母表明表的用途。

ACT_GE_ (GE) 表示 general 全局通用数据及设置,各种情况都使用的数据。
ACT_HI_ (HI) 表示 history 历史数据表,包含着程执行的历史相关数据,如结束的流程实例,变量,任务,等等
ACT_ID_ (ID) 表示 identity 组织机构,用户记录,流程中使用到的用户和组。这些表包含标识的信息,如用户,用户组,等等。
ACT_RE_ (RE) 表示 repository 存储,包含的是静态信息,如,流程定义,流程的资源(图片,规则等)。
ACT_RU_ (RU) 表示 runtime 运行时,运行时的流程变量,用户任务,变量,职责(job)等运行时的数据。Activiti 只存储实例执行期间的运行时数据,当流程实例结束时,将删除这些记录。这就保证了这些运行时的表小且快。

数据表介绍

一般数据

表名 说明
ACT_GE_BYTEARRAY 存储通用的流程定义和流程资源的二进制数据表
ACT_GE_PROPERTY 系统属性表,存储流程引擎级别的数据,初始化时会默认插入三条记录

流程历史记录

表名 说明
ACT_HI_ACTINST 历史节点表
ACT_HI_ATTACHMENT 历史附件表
ACT_HI_COMMENT 历史说明信息表
ACT_HI_DETAIL 记录流程运行中的历史细节信息
ACT_HI_IDENTITYLINK 存储流程运行中的历史用户关系
ACT_HI_PROCINST 历史流程实例表
ACT_HI_TASKINST 历史任务实例表
ACT_HI_VARINST 记录流程运行中的历史变量信息

流程定义表

表名 说明
ACT_RE_DEPLOYMENT 部署单元信息表
ACT_RE_MODEL 模型信息表
ACT_RE_PROCDEF 已部署的流程定义表

运行实例表

表名 说明
ACT_RU_EVENT_SUBSCR 运行时事件表
ACT_RU_EXECUTION 运行时流程执行实例表
ACT_RU_IDENTITYLINK 存储任务节点与参与者关系的运行时用户信息表
ACT_RU_JOB 运行时作业表
ACT_RU_TASK 运行时任务表
ACT_RU_VARIABLE 运行时变量表

表说明

act_ge_bytearray

二进制数据表,存储通用的流程定义和流程资源

字段名 字段描述 数据类型 主键 允许空 取值说明
ID_ 主键ID nvarchar(64) Y N 表的主键标识
REV_ 乐观锁版本号 int N Y 用于实现乐观锁控制的版本字段
NAME_ 部署文件名称 nvarchar(255) N Y 流程定义文件名称,如: leave.bpmn.png
DEPLOYMENT_ID_ 部署ID nvarchar(64) N Y 关联部署表的ID
BYTES_ 文件内容 varbinary(max) N Y 存储部署文件的二进制数据
GENERATED_ 文件生成来源标识 tinyint N Y 0表示用户生成,1表示系统自动生成

act_ge_property

属性数据表:属性数据表。存储整个流程引擎级别的数据。

字段名 字段描述 数据类型 主键 允许为空 取值说明
NAME_ 名称 nvarchar(64)
VALUE_ nvarchar(300) 5.create(5.)
REV_ 乐观锁 int version

act_hi_actinst

历史节点表:历史活动信息。这里记录流程流转过的所有节点,与HI_TASKINST不同的是,taskinst只记录usertask内容

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID标识 nvarchar(64)
PROC_DEF_ID_ 流程定义ID nvarchar(64)
PROC_INST_ID_ 流程实例ID nvarchar(64)
EXECUTION_ID_ 执行实例ID nvarchar(64)
ACT_ID_ 节点ID nvarchar(225) 节点定义ID
TASK_ID_ 任务实例ID nvarchar(64) 任务实例ID(其他节点类型实例ID为空)
CALL_PROC_INST_ID_ 外部调用流程实例ID nvarchar(64) 外部调用流程的实例ID
ACT_NAME_ 节点名称 nvarchar(225) 节点定义名称
ACT_TYPE_ 节点类型 nvarchar(225) 如startEvent、userTask
ASSIGNEE_ 签收人 nvarchar(64) 节点签收人
START_TIME_ 开始时间 datetime
END_TIME_ 结束时间 datetime
DURATION_ 耗时 numeric(19,0) 毫秒值
DELETE_REASON_ 删除原因 nvarchar(4000)
TENANT_ID_ 租户ID nvarchar(225)

act_hi_attachment

历史附件表

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ 主键标识 nvarchar(64) 主键ID
REV_ 乐观锁版本 integer 版本号
USER_ID_ 用户标识 nvarchar(255) 用户ID
NAME_ 附件名称 nvarchar(255) 附件名称
DESCRIPTION_ 描述信息 nvarchar(4000) 描述内容
TYPE_ 附件类型 nvarchar(255) 附件类型
TASK_ID_ 任务实例标识 nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例标识 nvarchar(64) 流程实例ID
URL_ 附件地址 nvarchar(4000) 附件URL地址
CONTENT_ID_ 字节表标识 nvarchar(64) ACT_GE_BYTEARRAY表ID
TIME_ 时间记录 datetime 操作时间

act_hi_comment

历史意见表

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ ID标识 nvarchar(64) 主键ID
TYPE_ 类型 nvarchar(255) 类型:event(事件)comment(意见)
TIME_ 时间 datetime 记录时间
USER_ID_ 用户ID nvarchar(64) 操作人ID
TASK_ID_ 节点任务ID nvarchar(64) 节点实例ID
PROC_INST_ID_ 流程实例ID nvarchar(255) 流程实例ID
ACTION_ 行为类型 nvarchar(64) 具体说明见备注1
MESSAGE_ 基本信息 nvarchar(4000) 存储流程生成信息,如审批意见
FULL_MSG_ 完整内容 varbinary(max) 附件存储地址

act_hi_detail 

历史详情表:流程中产生的变量详细,包括控制流程流转的变量,业务表单中填写的流程需要用到的变量等。

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 主键ID nvarchar(64) 主键标识
TYPE_ 类型标识 nvarchar(255) 详见备注2
PROC_INST_ID_ 流程实例ID nvarchar(64) 关联流程实例
EXECUTION_ID_ 执行实例ID nvarchar(64) 关联执行实例
TASK_ID_ 任务实例ID nvarchar(64) 关联任务实例
ACT_INST_ID_ 节点实例ID nvarchar(64) 关联ACT_HI_ACTINST表记录
NAME_ 名称 nvarchar(255) 变量名称
VAR_TYPE_ 参数类型 nvarchar(255) 详见备注3
REV_ 乐观锁版本 int 版本控制
TIME_ 创建时间 datetime 记录创建时间戳
BYTEARRAY_ID_ 二进制数据ID nvarchar 关联ACT_GE_BYTEARRAY表
DOUBLE_ 双精度数值 double precision 存储Double类型变量
LONG_ 长整型数值 numeric 存储Long类型变量
TEXT_ 文本值 nvarchar 存储String类型变量
TEXT2_ 对象ID nvarchar 仅JPA持久化对象时使用

act_ru_identitylink 

历史流程人员表:任务参与者数据表。主要存储历史节点参与者的信息

字段名称 描述 数据类型 主键 允许为空 取值说明
ID_ ID nvarchar(64) 唯一标识符
GROUP_ID_ 组ID nvarchar(255) 关联组ID
TYPE_ 类型 nvarchar(255) 备注信息
USER_ID_ 用户ID nvarchar(255) 关联用户ID
TASK_ID_ 节点实例ID nvarchar(64) 流程节点ID
PROC_INST_ID_ 流程实例ID nvarchar(64) 业务流程ID

act_hi_procinst

历史流程实例表

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ 主键ID nvarchar(64) 记录唯一标识
PROC_INST_ID_ 流程实例ID nvarchar(64) 关联的流程实例标识
BUSINESS_KEY_ 业务主键 nvarchar(255) 关联业务数据的标识
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程模板标识
START_TIME_ 开始时间 datetime 流程实例启动时间
END_TIME_ 结束时间 datetime 流程实例完成时间
DURATION_ 耗时 Numeric(19) 流程执行时长(毫秒)
START_USER_ID_ 起草人 nvarchar(255) 流程发起人ID
START_ACT_ID_ 开始节点ID nvarchar(255) 起始环节标识
END_ACT_ID_ 结束节点ID nvarchar(255) 终止环节标识
SUPER_PROCESS_INSTANCE_ID_ 父流程实例ID nvarchar(64) 上级流程实例标识
DELETE_REASON_ 删除原因 nvarchar(4000) 流程删除说明
TENANT_ID_ 租户ID nvarchar(255) 多租户隔离标识
NAME_ 名称 nvarchar(255) 流程实例显示名称

act_hi_taskinst

历史任务实例表

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 主键ID nvarchar(64) 记录唯一标识
PROC_DEF_ID_ 流程定义ID nvarchar(64) 关联的流程定义标识
TASK_DEF_KEY_ 节点定义ID nvarchar(255) 任务节点定义标识
PROC_INST_ID_ 流程实例ID nvarchar(64) 所属流程实例标识
EXECUTION_ID_ 执行实例ID nvarchar(64) 关联的执行实例标识
NAME_ 任务名称 varchar(255) 任务显示名称
PARENT_TASK_ID_ 父节点实例ID nvarchar(64) 父任务实例标识
DESCRIPTION_ 任务描述 nvarchar(400) 任务详细说明
OWNER_ 任务拥有者 nvarchar(255) 实际签收人(委托时才有值)
ASSIGNEE_ 当前处理人 nvarchar(255) 签收人或被委托人
START_TIME_ 开始时间 datetime 任务启动时间
CLAIM_TIME_ 签收时间 datetime 任务被签收时间
END_TIME_ 结束时间 datetime 任务完成时间
DURATION_ 耗时 numeric(19) 任务执行时长(毫秒)
DELETE_REASON_ 删除原因 nvarchar(4000) 任务终止原因(completed/deleted)
PRIORITY_ 优先级 int 任务处理优先级
DUE_DATE_ 截止时间 datetime 任务预期完成时间
FORM_KEY_ 表单标识 nvarchar(255) 设计器定义的form_key属性
CATEGORY_ 分类 varchar(255) 任务分类标识
TENANT_ID_ 租户标识 varchar(255) 多租户隔离标识

act_hi_varinst

历史变量表

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 唯一标识符 nvarchar(64)
PROC_INST_ID_ 流程实例ID nvarchar(64)
EXECUTION_ID_ 执行实例ID nvarchar(255)
TASK_ID_ 任务实例ID nvarchar(64)
NAME_ 参数名称(英文) nvarchar(64)
VAR_TYPE_ 参数类型 varchar(255)
REV_ 乐观锁版本号 nvarchar(64)
BYTEARRAY_ID_ 字节表关联ID nvarchar(400) 关联ACT_GE_BYTEARRAY表主键
DOUBLE_ 双精度数值 nvarchar(255) 存储DoubleType类型数据
LONG_ 长整型数值 nvarchar(255) 存储LongType类型数据
TEXT_ 文本内容 datetime
TEXT2_ 对象ID datetime JPA持久化对象时使用
CREATE_TIME_ 创建时间 datetime
LAST_UPDATED_TIME_ 最后更新时间 datetime

act_re_deployment 

部署信息表:部署流程定义时需要被持久化保存下来的信息。

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 主键ID nvarchar(64) 唯一标识符
NAME_ 部署文件名 nvarchar(255) 部署名称
CATEGORY_ 类别 nvarchar(255) 分类信息
KEY_
TENANT_ID_
DEPLOY_TIME_ 部署时间 datetime 记录部署时间戳
ENGINE_VERSION_

act_re_model

流程设计模型部署表:流程设计器设计流程后,保存数据到该表。

字段名称 字段描述 数据类型 是否主键 允许为空 取值说明
ID_ 唯一标识 nvarchar(64)
REV_ 乐观锁版本号 int 用于乐观锁控制
NAME_ 流程名称 nvarchar(255)
KEY_ 流程key nvarchar(255)
CATEGORY_ 流程分类 nvarchar(255)
CREATE_TIME_ 创建时间 datetime
LAST_UPDATE_TIME_ 最后修改时间 datetime
VERSION_ 版本号 int
META_INFO_ 元数据信息 nvarchar(255) JSON格式的流程定义信息
DEPLOYMENT_ID_ 关联的部署ID varchar(64)
EDITOR_SOURCE_VALUE_ID_ 编辑器资源ID varchar(64)
EDITOR_SOURCE_EXTRA_VALUE_ID_ 编辑器额外资源ID varchar(64)
TENANT_ID_ 租户ID varchar(255)

act_re_procdef 

流程定义数据表:业务流程定义数据表。此表和 ACT_RE_DEPLOYMENT 是多对一的关系,即,一个部署的bar包里可能包含多个流程定义文件,每个流程定义文件都会有一条记录在 ACT_REPROCDEF 表内,每个流程定义的数据,都会对于 ACT_GE_BYTEARRAY 表内的一个资源文件和 PNG 图片文件。和 ACT_GE_BYTEARRAY 的关联是通过程序用ACT_GE_BYTEARRAY.NAME 与 ACT_RE_PROCDEF.NAME 完成的,在数据库表结构中没有体现。

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ ID标识 nvarchar(64) 唯一标识符
REV_ 乐观锁版本号 int 用于乐观锁控制的版本号
CATEGORY_ 分类 nvarchar(255) 流程定义的Namespace即为类别
NAME_ 名称 nvarchar(255) 流程定义名称
KEY_ 流程定义ID nvarchar(255) 流程定义的唯一标识
VERSION_ 版本号 int 流程定义的版本信息
DEPLOYMENT_ID_ 部署表关联ID nvarchar(64) 关联部署表的ID
RESOURCE_NAME_ BPMN文件名称 nvarchar(4000) 流程BPMN定义文件名称
DGRM_RESOURCE_NAME_ 流程图PNG文件名称 nvarchar(4000) 流程图形化表示文件名称
DESCRIPTION_ 描述信息 nvarchar(4000) 流程定义的详细描述
HAS_START_FORM_KEY 起始节点表单标识 tinyint 标识起始节点是否存在表单Key(0否1是)
SUSPENSION_STATE_ 挂起状态 tinyint 流程状态(1激活/2挂起)
HAS_GRAPHICAL_NOTATION_ 图形化标识 tinyint 是否具有图形化表示
TENANT_ID_ 租户ID varchar(255) 多租户环境标识
ENGINE_VERSION_ 引擎版本 varchar(255) 使用的流程引擎版本信息

act_ru_deadletter_job

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 唯一标识符 varchar(64)
REV_ 版本号 int
TYPE_ 类型 varchar(255)
EXCLUSIVE_ 是否独占 tinyint(1)
EXECUTION_ID_ 执行ID varchar(64)
PROCESS_INSTANCE_ID_ 流程实例ID varchar(64)
PROC_DEF_ID_ 流程定义ID varchar(64)
EXCEPTION_STACK_ID_ 异常堆栈ID varchar(64)
EXCEPTION_MSG_ 异常信息 varchar(4000)
DUEDATE_ 到期时间 timestamp
REPEAT_ 重复设置 varchar(255)
HANDLER_TYPE_ 处理器类型 varchar(255)
HANDLER_CFG_ 处理器配置 varchar(4000)
TENANT_ID_ 租户ID varchar(255)

act_ru_event_subscr

字段名称

字段描述

数据类型

主键

为空

取值说明

ID_

事件ID

nvarchar(64)

事件ID

REV_

版本

int

乐观锁Version

EVENT_TYPE_

事件类型

nvarchar(255)

事件类型

EVENT_NAME_

事件名称

nvarchar(255)

事件名称

EXECUTION_ID_

执行实例ID

nvarchar(64)

执行实例ID

PROC_INST_ID_

流程实例ID

nvarchar(64)

流程实例ID

ACTIVITY_ID_

活动实例ID

nvarchar(64)

活动实例ID

CONFIGURATION_

配置

nvarchar(255)

配置

CREATED_

是否创建

datetime

默认值 当前系统时间戳CURRENT_TIMESTAMP

PROC_DEF_ID_

varchar(64)

TENANT_ID_

varchar(255)

act_ru_execution

运行时流程执行实例表

字段名称

字段描述

数据类型

主键

为空

取值说明

ID_

事件ID

nvarchar(64)

事件ID

REV_

版本

int

乐观锁Version

EVENT_TYPE_

事件类型

nvarchar(255)

事件类型

EVENT_NAME_

事件名称

nvarchar(255)

事件名称

EXECUTION_ID_

执行实例ID

nvarchar(64)

执行实例ID

PROC_INST_ID_

流程实例ID

nvarchar(64)

流程实例ID

ACTIVITY_ID_

活动实例ID

nvarchar(64)

活动实例ID

CONFIGURATION_

配置

nvarchar(255)

配置

CREATED_

是否创建

datetime

默认值 当前系统时间戳CURRENT_TIMESTAMP

PROC_DEF_ID_

varchar(64)

TENANT_ID_

varchar(255)

act_ru_identitylink

运行时流程人员表:任务参与者数据表。主要存储当前节点参与者的信息。

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ 唯一标识符 nvarchar(64)
REV_ 乐观锁版本号 int 用于并发控制
GROUP_ID_ 用户组ID nvarchar(64)
TYPE_ 类型标识 nvarchar(255) 类型说明
USER_ID_ 用户ID nvarchar(64)
TASK_ID_ 节点实例ID nvarchar(64) 关联任务节点
PROC_INST_ID_ 流程实例ID nvarchar(64) 关联流程实例
PROC_DEF_ID_ 流程定义ID nvarchar(255) 关联流程定义

act_ru_integration

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ varchar(64)
EXECUTION_ID_ varchar(64)
PROCESS_INSTANCE_ID_ varchar(64)
PROC_DEF_ID_ varchar(64)
FLOW_NODE_ID_ varchar(64)
CREATED_DATE_ timestamp

act_ru_job

运行时定时任务数据表( act_ru_job )

字段名称 描述 数据类型 主键 允许为空 取值说明
ID_ 唯一标识 nvarchar(64) 标识符
REV_ 版本号 int 版本信息
TYPE_ 类型 nvarchar(255) 作业类型
LOCK_EXP_TIME_ 锁定到期时间 datetime 锁定释放时间
LOCK_OWNER_ 锁定所有者 nvarchar(255) 挂起者信息
EXCLUSIVE_ 独占标识 bit
EXECUTION_ID_ 执行实例ID nvarchar(64) 执行实例标识
PROCESS_INSTANCE_ID_ 流程实例ID nvarchar(64) 流程实例标识
PROC_DEF_ID_ 流程定义ID nvarchar(64) 流程定义标识
RETRIES_ 重试次数 int
EXCEPTION_STACK_ID_ 异常堆栈ID varchar(64) 异常信息标识
EXCEPTION_MSG_ 异常消息 nvarchar(4000) 异常详细信息
DUEDATE_ 到期时间 datetime 作业截止时间
REPEAT_ 重复标识 nvarchar(255) 重复设置
HANDLER_TYPE_ 处理器类型 nvarchar(255) 处理类型
HANDLER_CFG_ 处理器配置 nvarchar(4000) 配置信息
TENANT_ID_ 租户ID nvarchar(255)

act_ru_suspended_job

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ VARCHAR(64)
REV_ INT
TYPE_ VARCHAR(255)
EXCLUSIVE_ TINYINT(1)
EXECUTION_ID_ VARCHAR(64)
PROCESS_INSTANCE_ID_ VARCHAR(64)
PROC_DEF_ID_ VARCHAR(64)
RETRIES_ INT
EXCEPTION_STACK_ID_ VARCHAR(64)
EXCEPTION_MSG_ VARCHAR(4000)
DUEDATE_ TIMESTAMP
REPEAT_ VARCHAR(255)
HANDLER_TYPE_ VARCHAR(255)
HANDLER_CFG_ VARCHAR(4000)
TENANT_ID_ VARCHAR(255)

act_ru_task 

运行时任务节点表

字段名称 字段描述 数据类型 主键 允许为空 取值说明
ID_ 唯一标识 nvarchar(64)
REV_ 乐观锁版本 int
EXECUTION_ID_ 执行实例ID nvarchar(64)
PROC_INST_ID_ 流程实例ID nvarchar(64)
PROC_DEF_ID_ 流程定义ID nvarchar(64)
NAME_ 节点名称 nvarchar(255)
PARENT_TASK_ID_ 父任务ID nvarchar(64)
DESCRIPTION_ 任务描述 nvarchar(4000)
TASK_DEF_KEY_ 任务定义KEY nvarchar(255)
OWNER_ 任务所有者 nvarchar(255) 通常为空,委托时有效
ASSIGNEE_ 任务处理人 nvarchar(255)
DELEGATION_ 委托类型 nvarchar(64)
PRIORITY_ 优先级 int 默认值50
CREATE_TIME_ 创建时间 datetime
DUE_DATE_ 截止时间 datetime
CATEGORY_ 分类 varchar(255)
SUSPENSION_STATE_ 挂起状态 int 1-激活,2-挂起
TENANT_ID_ 租户ID varchar(255)
FORM_KEY_ 表单KEY varchar(255)
CLAIM_TIME_ 认领时间 datetime

act_ru_timer_job

字段名称 描述 数据类型 主键 允许为空 取值说明
ID_ 唯一标识符 varchar(64)
REV_ 版本号 int
TYPE_ 类型 varchar(255)
LOCK_EXP_TIME_ 锁定过期时间 timestamp
LOCK_OWNER_ 锁定拥有者 varchar(255)
EXCLUSIVE_ 是否独占 tinyint(1)
EXECUTION_ID_ 执行ID varchar(64)
PROCESS_INSTANCE_ID_ 流程实例ID varchar(64)
PROC_DEF_ID_ 流程定义ID varchar(64)
RETRIES_ 重试次数 int
EXCEPTION_STACK_ID_ 异常堆栈ID varchar(64)
EXCEPTION_MSG_ 异常消息 varchar(4000)
DUEDATE_ 到期时间 timestamp
REPEAT_ 重复设置 varchar(255)
HANDLER_TYPE_ 处理器类型 varchar(255)
HANDLER_CFG_ 处理器配置 varchar(4000)
TENANT_ID_ 租户ID varchar(255)

act_ru_variable 

运行时流程变量数据表

字段名称 字段描述 数据类型 主键 为空 取值说明
ID_ 主键标识 nvarchar(64) 唯一标识符
REV_ 乐观锁 int 用于并发控制的版本号
TYPE_ 类型 nvarchar(255) 参见备注9
NAME_ 变量名称 nvarchar(255) 变量的命名标识
EXECUTION_ID_ 执行实例ID nvarchar(64) 标识执行中的流程实例
PROC_INST_ID_ 流程实例ID nvarchar(64) 流程实例的唯一标识
TASK_ID_ 节点实例ID nvarchar(64) 本地任务节点的标识(Local)
BYTEARRAY_ID_ 字节表ID nvarchar(64) 关联ACT_GE_BYTEARRAY表的引用ID
DOUBLE_ 双精度浮点数 float 存储Double类型变量
LONG_ 长整数 numeric(19) 存储long类型变量
TEXT_ 文本 nvarchar(4000) 存储String类型变量或JPA持久化对象的类信息
TEXT2_ 辅助文本 nvarchar(4000) 仅当存储JPA持久化对象时使用,记录对象ID

部署流程测试

踩坑注意

在配置Swagger2的时候出现一下错误,解决方法启动类配置@EnableSwagger2

部署步骤

压缩xml和流程图成压缩包

打开swagger使用接口上传

使用查询接口获取流程定义ID

使用发起流程接口发起流程

流程代码

Assignee办理人模式

Assignee(办理人)是 Activiti 工作流中最核心的任务分配方式,它指定
单个用户作为任务的直接负责人。这种模式简单直接,适用于任务归属明确的场景。

核心概念

Assignee:任务的直接负责人(单个用户)
任务归属:任务出现在指定用户的”待办任务列表”中
任务处理:只有被分配的用户能执行该任务(除非重新分配)

测试流程图

实现代码

修改代办人

@ApiOperation("按任务id更新代办人")
@GetMapping("updateAssigneeByTaskId")
public ReturnData updateAssigneeByTaskId(
        @ApiParam(value = "任务id", required = true) String taskId,
        @ApiParam(value = "新代办人", required = true) String assignee
) {

    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
    if (task == null) {
        return ReturnData.buildError("任务不存在");
    }
    //更新当前任务的代办人
    taskService.setAssignee(taskId, assignee);
    return ReturnData.buildSuccess("更新成功");
}

根据代办人查询任务

添加审批意见

  @ApiOperation("添加审批人意见")
    @GetMapping("addComment")
    public ReturnData addComment(
            @ApiParam(value = "任务id", required = true) String taskId,
            @ApiParam(value = "流程实例id", required = true) String processInstanceId,
            @ApiParam(value = "意见内容", required = true) String message
    ) {
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .processInstanceId(processInstanceId)
                .singleResult();
        if (task == null) {
            return ReturnData.buildError("任务不存在");
        }
        taskService.addComment(taskId, processInstanceId, message);
        return ReturnData.buildSuccess("添加成功");
    }

查询审批意见

@ApiOperation("查询个人审批意见")
@GetMapping("queryComment")
public ReturnData queryComment(
        @ApiParam(value = "任务id") String taskId
) {
    //注意,这里也可以使用type做搜索,通过添加意见的第三个参数,指定用户id
    //taskService.addComment("任务id", "流程实例id", "自定义变量type,可以用作用户id", "意见");
    List<Comment> taskComments = taskService.getTaskComments(taskId);
    //taskService.getTaskComments(taskId,"自定义变量type,可以用作用户id");
    log.info("查询个人审批意见 {}", taskComments);
    return ReturnData.buildSuccess(taskComments.toString());
}

CandidateUsers 模式详解

CandidateUsers(候选用户)模式是 Activiti 中处理
多人协作任务的核心机制,它允许将任务分配给一组用户,由其中任意一人认领并完成任务。这种模式适用于需要团队协作或任务可由多人处理的场景。

核心概念与流程

与 Assignee 模式的对比

特性

CandidateUsers

Assignee

责任人数量

多人

单人

任务可见性

所有候选人可见

仅指定办理人可见

任务处理流程

需先认领(claim)再处理

直接处理

适用场景

团队协作、多可处理人

明确责任人的任务

任务状态管理

未认领/已认领两种状态

始终属于指定办理人

API复杂度

较高(需管理认领状态)

简单

测试流程图

流程代码

认领任务



    /**
     * 拾取任务,拾取后的任务,该候选人才可以完成任务
     *
     * @param taskId   任务id
     * @param userName 候选人名称
     * @return
     */
    @ApiOperation("候选人拾取任务,拾取后的任务,候选人才可以完成")
    @GetMapping("claimTask")
    public ReturnData claimTask(
            @ApiParam(value = "任务id") String taskId,
            @ApiParam(value = "候选人名称") String userName
    ) {
        Task task = taskService.createTaskQuery()
                //任务id
                .taskId(taskId)
                //候选人名称
                .taskCandidateUser(userName)
                .singleResult();
        if (task == null) {
            return ReturnData.buildError("任务不存在");
        }
        //拾取任务
        taskService.claim(taskId, userName);
        return ReturnData.buildSuccess("拾取任务成功");
    }

查询任务



    @ApiOperation("根据候选人查询任务")
    @GetMapping("queryTaskByCandidateUser")
    public ReturnData queryTaskByCandidateUser(
            @ApiParam(value = "候选人名称") String userName
    ){
        List<Task> taskList = taskService.createTaskQuery()
                //候选人名称
                .taskCandidateUser(userName)
                .list();
        return ReturnData.buildSuccess(taskList);
    }

完整主要代码

package com.example.oaactivitiworkflow.controller;

import com.example.oaactivitiworkflow.utils.ReturnData;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.task.Comment;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import io.swagger.annotations.ApiOperation;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipInputStream;

/**
 * @Author:leroy
 * @create: 2025/5/27 17:24
 * @email:
 * @desc:
 */
@Api(tags = "工作流")
@RestController
@Slf4j
public class OaActivitiController {
    //提供对流程定义和部署存储库的访问服务
    @Autowired
    RepositoryService repositoryService;
    //运行时的接口
    @Autowired
    RuntimeService runtimeService;

    // 历史处理接口
    @Autowired
    HistoryService historyService;

    // 任务处理接口
    @Autowired
    TaskService taskService;

    /**
     * 部署流程
     * <p>
     * 1、设计器设计流程xml/png
     * 2、部署流程
     * 3、发起流程
     * 4、执行流程
     *
     * @param file 上传流程压缩包
     */
    @ApiOperation("zip部署流程")
    @PostMapping("deploy")
    public ReturnData deploy(@RequestPart("file") MultipartFile file){
        try {
            if (file.isEmpty()) {
                throw new NullPointerException("部署压缩包不能为空");
            }
            DeploymentBuilder deploymentBuilder = repositoryService.createDeployment();
            //压缩流
            ZipInputStream zip = new ZipInputStream(file.getInputStream());
            deploymentBuilder.addZipInputStream(zip);
            //设置部署流程名称
            deploymentBuilder.name("请假审批");
            //部署流程
            Deployment deploy = deploymentBuilder.deploy();
            return ReturnData.buildSuccess(deploy);

        }catch (Exception e){
            e.printStackTrace();
            return ReturnData.buildError(e.toString());
        }
    }


    @ApiOperation("查询流程部署信息")
    @PostMapping("queryDeploymentInfo")
    public ReturnData queryDeploymentInfo() {
        //也可以设置查询部署筛选条件,自行查询API,基本上都是见名知意的
        List<Deployment> list = repositoryService.createDeploymentQuery().list();
        log.info("流程部署信息:{}", list);
        return ReturnData.buildSuccess(list.toString());
    }

    @ApiOperation("查询流程定义信息")
    @PostMapping("queryProcessInfo")
    public ReturnData queryProcessInfo() {
        //也可以设置查询流程定义筛选条件,自行查询API,基本上都是见名知意的
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().list();
        log.info("流程定义信息:{}", list);
        return ReturnData.buildSuccess(list.toString());
    }


    @ApiOperation("根据部署id删除流程部署")
    @GetMapping("deleteDeploymentById")
    public ReturnData deleteDeploymentById(
            @RequestParam(value = "流程部署id", required = true) String deploymentId
    ) {
        List<Deployment> list = repositoryService.createDeploymentQuery().deploymentId(deploymentId).list();
        if (list.size() != 1) {
            return ReturnData.buildError("流程定义未找到");
        }
        //根据部署id删除流程部署
        repositoryService.deleteDeployment(deploymentId);
        return ReturnData.buildSuccess("删除成功");
    }


    @ApiOperation("发起流程")
    @GetMapping("startProcess")
    public ReturnData startProcess(@RequestParam(value = "流程定义id",required = false) String processDefinitionId) {
        log.info("发起流程,processDefinitionId:{}", processDefinitionId);
        List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery().processDefinitionId(processDefinitionId).list();
        if (list.size() != 1) {
            return ReturnData.buildError("流程定义不存在");
        }
        //流程节点中变量,替换占位符
        Map<String, Object> variablesMap = new HashMap<>();
        variablesMap.put("userName","Leroy");

        //通过流程定义ID启动一个流程实例
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId,variablesMap);
        log.info("流程实例:{}", processInstance);
        return ReturnData.buildSuccess("发起成功");
    }

    @ApiOperation("查询历史任务")
    @GetMapping("queryHistoryTask")
    public ReturnData queryHistoryTask() {
        //也可以设置查询条件,自行查询API
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().list();
        log.info("查询历史任务 {}", list);
        return ReturnData.buildSuccess(list.toString());
    }

    @ApiOperation("查看历史活动流程实例")
    @GetMapping("queryActivityInstance")
    public ReturnData queryActivityInstance() {
        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery().list();
        log.info("查看历史活动流程实例 {}", list);
        return ReturnData.buildSuccess(list.toString());
    }


    @ApiOperation("根据代办人查询任务")
    @GetMapping("queryByAssigneeTask")
    public ReturnData queryByAssigneeTask(@RequestParam(value = "代办人", required = true) String assignee) {
        List<Task> taskList = taskService.createTaskQuery()
                //代办人姓名
                .taskAssignee(assignee)
                //活动状态
                .active()
                .list();
        log.info("根据代办人查询任务 {}", taskList);
        return ReturnData.buildSuccess(taskList.toString());
    }


    @ApiOperation("按任务id更新代办人")
    @GetMapping("updateAssigneeByTaskId")
    public ReturnData updateAssigneeByTaskId(
            @ApiParam(value = "任务id", required = true) String taskId,
            @ApiParam(value = "新代办人", required = true) String assignee
    ) {

        Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (task == null) {
            return ReturnData.buildError("任务不存在");
        }
        //更新当前任务的代办人
        taskService.setAssignee(taskId, assignee);
        return ReturnData.buildSuccess("更新成功");
    }


    @ApiOperation("添加审批人意见")
    @GetMapping("addComment")
    public ReturnData addComment(
            @ApiParam(value = "任务id", required = true) String taskId,
            @ApiParam(value = "流程实例id", required = true) String processInstanceId,
            @ApiParam(value = "意见内容", required = true) String message
    ) {
        Task task = taskService.createTaskQuery()
                .taskId(taskId)
                .processInstanceId(processInstanceId)
                .singleResult();
        if (task == null) {
            return ReturnData.buildError("任务不存在");
        }
        taskService.addComment(taskId, processInstanceId, message);
        return ReturnData.buildSuccess("添加成功");
    }

    @ApiOperation("查询个人审批意见")
    @GetMapping("queryComment")
    public ReturnData queryComment(
            @ApiParam(value = "任务id") String taskId
    ) {
        //注意,这里也可以使用type做搜索,通过添加意见的第三个参数,指定用户id
        //taskService.addComment("任务id", "流程实例id", "自定义变量type,可以用作用户id", "意见");
        List<Comment> taskComments = taskService.getTaskComments(taskId);
        //taskService.getTaskComments(taskId,"自定义变量type,可以用作用户id");
        log.info("查询个人审批意见 {}", taskComments);
        return ReturnData.buildSuccess(taskComments.toString());
    }



    /**
     * 拾取任务,拾取后的任务,该候选人才可以完成任务
     *
     * @param taskId   任务id
     * @param userName 候选人名称
     * @return
     */
    @ApiOperation("候选人拾取任务,拾取后的任务,候选人才可以完成")
    @GetMapping("claimTask")
    public ReturnData claimTask(
            @ApiParam(value = "任务id") String taskId,
            @ApiParam(value = "候选人名称") String userName
    ) {
        Task task = taskService.createTaskQuery()
                //任务id
                .taskId(taskId)
                //候选人名称
                .taskCandidateUser(userName)
                .singleResult();
        if (task == null) {
            return ReturnData.buildError("任务不存在");
        }
        //拾取任务
        taskService.claim(taskId, userName);
        return ReturnData.buildSuccess("拾取任务成功");
    }

    @ApiOperation("根据候选人查询任务")
    @GetMapping("queryTaskByCandidateUser")
    public ReturnData queryTaskByCandidateUser(
            @ApiParam(value = "候选人名称") String userName
    ){
        List<Task> taskList = taskService.createTaskQuery()
                //候选人名称
                .taskCandidateUser(userName)
                .list();
        return ReturnData.buildSuccess(taskList);
    }
}
package com.example.oaactivitiworkflow.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ContentNegotiationConfigurer;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;

/**
 * @Author:leroy
 * @create: 2025/5/28 15:58
 * @email:
 * @desc:Swagger配置类
 */
@Configuration
@EnableSwagger2
@ConditionalOnProperty(name = "swagger.enable", havingValue = "true")
public class SwaggerConfiguration extends WebMvcConfigurationSupport {

    // swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
    @Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                // 为当前包路径
                .apis(RequestHandlerSelectors.basePackage("com.example.oaactivitiworkflow.controller"))
                .paths(PathSelectors.any())
                .build();

    }

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                // 页面标题
                .title("Spring Boot 测试使用 Swagger2 构建RESTful API")
                // 创建人信息
                .contact(new Contact("leroy", "", "821315744@qq.com"))
                // 版本号
                .version("1.0")
                // 描述
                .description("API 描述")
                .build();

    }


    // 配置中文乱码
    @Bean
    public HttpMessageConverter<String> responseBodyConverter() {
        return new StringHttpMessageConverter(
                StandardCharsets.UTF_8);
    }

    @Override
    public void configureMessageConverters(
            List<HttpMessageConverter<?>> converters) {
        super.configureMessageConverters(converters);
        converters.add(responseBodyConverter());
        //设置日期格式
        ObjectMapper objectMapper = new ObjectMapper();
        SimpleDateFormat smt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        objectMapper.setDateFormat(smt);
        objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
        objectMapper.setDefaultPropertyInclusion(JsonInclude.Include.NON_EMPTY);

        objectMapper.configure(SerializationFeature.INDENT_OUTPUT, true);
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
        objectMapper.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, true);

        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

        objectMapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);

        objectMapper.configure(MapperFeature.DEFAULT_VIEW_INCLUSION, false);

        MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter
                = new MappingJackson2HttpMessageConverter();
        mappingJackson2HttpMessageConverter.setObjectMapper(objectMapper);
        //设置中文编码格式
        List<MediaType> list = new ArrayList<>();
        list.add(MediaType.APPLICATION_JSON_UTF8);
        mappingJackson2HttpMessageConverter.setSupportedMediaTypes(list);
        converters.add(0, mappingJackson2HttpMessageConverter);

    }

    @Override
    public void configureContentNegotiation(
            ContentNegotiationConfigurer configurer) {
        configurer.favorPathExtension(false);
    }
}

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容