当前位置: 首页 > article >正文

工作流之Activiti7 和BPMN讲解

文章目录

  • 1 Activiti
    • 1.1 简介
    • 1.2 BPMN
      • 1.2.1 简介
      • 1.2.2 符号
    • 1.3 准备工作
      • 1.3.1 安装插件
        • 1.3.1.1 插件
        • 1.3.1.2 本地网页
      • 1.3.2 pom依赖
      • 1.3.3 添加配置
      • 1.3.4 表介绍
      • 1.3.5 常用Service服务介绍
    • 1.4 无校验操作流程
      • 1.4.1 部署&查看文件
        • 1.4.1.1 单个文件部署方式
        • 1.4.1.2 静态类部署
        • 1.4.1.3 压缩包部署方式
        • 1.4.1.4 查看文件
      • 1.4.2 启动流程实例和查询
      • 1.4.3 查询任务和历史
      • 1.4.4 处理当前任务
      • 1.4.5 流程定义
    • 1.5 新版校验操作
      • 1.5.1 配置Security用户
      • 1.5.2 操作
      • 1.5.3 报错 Process definition with the given id:xxx belongs to a different application version
    • 1.6 Activiti 7.1.0.M6之后

1 Activiti

1.1 简介

Activiti 是一个开源的工作流和业务流程管理 (BPM) 平台,旨在帮助开发者和企业自动化业务流程。它提供了一整套工具,用于定义、执行、监控和优化业务流程。Activiti 支持 BPMN 2.0 标准,具有强大的扩展能力和易用性,适用于各种规模的组织和复杂的业务需求。
官方网站:https://www.activiti.org
https://mp.weixin.qq.com/s/Xa3yIp1FRYpQF87lmf91OA

1.2 BPMN

1.2.1 简介

BPM(Business Process Management) 即业务流程管理,是一种规范化的构造端到端的业务流程,以持续提高组织业务效率

BPMN(Business Process Model AndNotation) 即业务流程模型和符号,是一套标准的业务流程建模符号,使用 BPMN 提供的符号可以创建业务流程。Activit 就是使用 BPMN 进行流程建模、流程执行管理的
BPMN2.0 是业务流程建模符号 2.0 的缩写,它由 Business Process Management Initiative 这个非营利协会创建并不断发展。BPMN2.0 是使用一些符号来明确业务流程设计流程图的一套符号规范,能增进业务建模时的沟通效率。

1.2.2 符号

BPMN2.0 的基本符号主要包含

  • 事件 Event
    开始:表示一个流程的开始
    中间:发生的开始和结束事件之间,影响处理的流程
    结束:表示该过程结束
    在这里插入图片描述

  • 活动 Activities
    活动是工作或任务的一个通用术语。一个活动可以是一个任务,还可以是一个当前流程的子处理流程;其次,还可以为活动指定不同的类型。常见活动如下:
    在这里插入图片描述

  • 网关 GateWay
    用于表示流程的分支与合并,有几种常用网关需要了解:
    在这里插入图片描述
    排他网关:只有一条路径会被选择,基于条件选择单一路径
    并行网关:无条件并行执行所有路径
    包容网关:可以同时执行多条线路,也可以在网关上设置条件,基于条件可以选择多个路径同时执行
    事件网关:基于外部事件的发生来决定路径选择,即专门为中间捕获事件设置的,允许设置多个输出流指向多个不同的中间捕获事件。当流程执行到事件网关后,流程处于等待状态,需要等待抛出事件才能将等待状态转换为活动状态

  • 流向 Flow
    流是连接两个流程节点的连线,常见的流向包含以下几种:
    顺序流:用一个带实心箭头的实心线表示,用于指定活动执行的顺序
    信息流:用一条带箭头的虚线表示,用于描述两个独立的业务参与者(业务实体/业务角色)之间发送和接受的消息流动
    关联:用一根带有线箭头的点线表示,用于将相关的数据、文本和其他人工信息与流对象联系起来。用于展示活动的输入和输出
    在这里插入图片描述

  • 边界事件(Boundary Events
    边界事件是一种特殊的事件,它附加在流程元素(如任务、子流程等)上,用于捕捉特定事件并对其进行处理。边界事件通常用于中断或处理任务的异常情况,或者处理流程中某些特定的事件场景。

    • 中断任务: 当绑定在某个任务上的边界事件被触发时,任务可以被中断,流程将根据边界事件的定义跳转到其他节点或执行特定的操作。这通常用于处理异常情况,如错误、超时等。
    • 捕获事件: 边界事件可以用来捕捉在任务执行过程中发生的特定事件,例如错误事件(Error Event)、定时事件(Timer Event)、消息事件(Message Event)等。当这些事件发生时,流程会从当前任务转移到处理该事件的流程路径。
    • 处理子流程: 在嵌套子流程中,边界事件可以用于在子流程内某个特定事件发生时触发相应的处理逻辑。

1.3 准备工作

1.3.1 安装插件

1.3.1.1 插件

IDEA版本小于等于2019,可使用Activiti插件actiBPM,如果获取不到插件市场获取:https://plugins.jetbrains.com/plugin/7429-actibpm
否则使用Activiti BPMN visualizer
在这里插入图片描述
假如要画一个请假的 activiti 流程图,使用 Idea 安装 actiBPM 插件,创建该流程图,文件命名apply.mpmn,实现请假流程的二级审批能力,右键点击view bpmn diagram 才会有图示出来
在这里插入图片描述

1.3.1.2 本地网页

如果觉得插件画图麻烦,可以用 Activiti ModelerActiviti Modeler 是 Activiti 官方提供的一款在线流程设计的前端插件,开发人员可以方便在线进行流程设计,保存流程模型,部署至流程定义等等

下载activiti-explorer,官网下载:Get started | Activiti
解压activiti-5.22.0.zip,在activiti-5.22.0\wars目录下获取activiti-explorer.war
启动路径:双击startup.bat
在这里插入图片描述

访问activiti-explorer:http://localhost:8080/activiti-explorer
默认登录账号:kermit kermit

1.3.2 pom依赖

<!--引入activiti的springboot启动器 -->
<dependency>
    <groupId>org.activiti</groupId>
    <artifactId>activiti-spring-boot-starter</artifactId>
    <version>7.1.0.M6</version>
    <exclusions>
        <exclusion>
            <artifactId>mybatis</artifactId>
            <groupId>org.mybatis</groupId>
        </exclusion>
    </exclusions>

	<!-- 不加如下依赖报错:'org.springframework.security.core.userdetails.UserDetailsService' that could not be found. 
	-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-security</artifactId>
    </dependency>
<!-- 不加可能报错:Consider defining a bean of type 'javax.sql.DataSource' in your configuration -->
	<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
        <!-- 或者使用druid-spring-boot-starter -->
    </dependency>
</dependency>

说明:Activiti7SpringBoot整合后,默认集成了SpringSecurity安全框架,当前项目已经集成过了SpringSecurity,后续案例设置审批人时都必须是系统用户,Activiti框架会检查用户是否存在,否则会出现异常

1.3.3 添加配置

数据源项目已经添加,只需要如下配置即可

spring:
  datasource:
    url: jdbc:mysql://localhost:3316/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=Asia/Shanghai
    username: xxxx
    password: xxxx
    driver-class-name: com.mysql.cj.jdbc.Driver
  activiti:
    #    false:默认,数据库表不变,但是如果版本不对或者缺失表会抛出异常(生产使用)
    #    true:表不存在,自动创建(开发使用)
    #    create_drop: 启动时创建,关闭时删除表(测试使用)
    #    drop_create: 启动时删除表,在创建表 (不需要手动关闭引擎)
    database-schema-update: true
    #监测历史表是否存在,activities7默认不开启历史表
    db-history-used: true
    #none:不保存任何历史数据,流程中这是最高效的
    #activity:只保存流程实例和流程行为
    #audit:除了activity,还保存全部的流程任务以及其属性,audit为history默认值
    #full:除了audit、还保存其他全部流程相关的细节数据,包括一些流程参数
    history-level: full
    #校验流程文件,默认校验resources下的process 文件夹的流程文件
    check-process-definitions: false
    # 定义.bpmn文件的位置
    process-definition-location-prefix: classpath:/process/

1.3.4 表介绍

启动项目,即可生成项目数据库表
在这里插入图片描述
Activiti 的运行支持必须要有这 25 张表的支持,主要是在业务流程运行过程中,记录参与流程的用户主体,用户组信息,以及流程的定义,流程执行时的信息,和流程的历史信息等等

表的命名规则和作用:

  • Activiti 的表都以 act_ 开头,紧接着是表示表的用途的两个字母标识,也和 Activiti 所提供的服务的 API 对应:
    • ACT_RE:RE 表示 repository,这个前缀的表包含了流程定义和流程静态资源 (图片、规则、等等)
    • ACT_RU:RU 表示 runtime,这些表运行时,会包含流程实例、任务、变量、异步任务等流程业务进行中的数据。Activiti 只在流程实例执行过程中保存这些数据,在流程结束时就会删除这些记录。这样表就可以一直保持很小的体积,并且速度很快
    • ACT_HI:HI 表示 history,这些表包含一些历史数据,比如历史流程实例、变量、任务等等
    • ACT_GE:GE 表示 general,通用数据

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]运行时变量表

1.3.5 常用Service服务介绍

各个 Service 的实现类,这些服务是 Activiti 的底层核心 API,提供了对工作流引擎内部的细粒度控制。它们是 Activiti 5 和 6 中主要使用的服务,提供了更低级别的操作接口:

  • RepositoryService
    Activiti 的资源管理类,该服务负责部署流程定义,管理流程资源。在使用 Activiti 时,一开始需要先完成流程部署,即将使用建模工具设计的业务流程图通过 RepositoryService 进行部署
  • RuntimeService
    Activiti 的流程运行管理类,用于开始一个新的流程实例,获取关于流程执行的相关信息。流程定义用于确定一个流程中的结构和各个节点间行为,而流程实例则是对应的流程定义的一个执行,可以理解为 Java 中类和对象的关系
  • TaskService
    Activiti 的任务管理类,用于处理业务运行中的各种任务,例如查询分给用户或组的任务、创建新的任务、分配任务、确定和完成一个任务
  • HistoryService
    Activiti 的历史管理类,可以查询历史信息。执行流程时,引擎会保存很多数据,比如流程实例启动时间、任务的参与者、完成任务的时间、每个流程实例的执行路径等等。这个服务主要通过查询功能来获得这些数据
  • ManagementService
    Activiti 的引擎管理类,提供了对 Activiti 流程引擎的管理和维护功能,这些功能不在工作流驱动的应用程序中使用,主要用于 Activiti 系统的日常维护

Activiti7后新增服务:

  • TaskRuntime:这个服务主要用于管理用户任务。通过它,可以查询任务、完成任务、分配任务、认领任务等。这些操作是围绕任务管理的高层次抽象,开发人员可以更加方便地与任务进行交互,而无需直接处理底层的 API 调用。
  • ProcessRuntime:这个服务用于管理流程实例。可以通过它启动流程、查询流程实例、暂停和恢复流程等。ProcessRuntime 提供了一个更简单的方式来处理流程的生命周期管理。

1.4 无校验操作流程

将画好的流程图部署到activiti数据库中,就是流程定义部署。通过调用activiti的api将流程定义的bpmn和png两个文件一个一个添加部署到activiti中,也可以将两个文件打成zip包进行部署。

1.4.1 部署&查看文件

流程定义部署后操作activiti的3张表如下:

  • act_re_deployment:流程定义部署表,每部署一次增加一条记录
  • act_re_procdef:流程定义表,部署每个新的流程定义都会在这张表中增加一条记录
  • act_ge_bytearray:流程资源表
1.4.1.1 单个文件部署方式

@SpringBootTest
public class ProcessTest {

    //注入RepositoryService
    @Autowired
    private RepositoryService repositoryService;

    /**
     * 单个文件部署方式
     */
    @Test
    public void deployProcess() {
        //流程部署
        Deployment deploy = repositoryService.createDeployment()
                .addClasspathResource("process/qingjia.bpmn20.xml")
                // 如果报错找不到图片在pom里面添加: <include>**/*.png</include>
               
                .addClasspathResource("process/qingjia.png")
                .name("请假申请流程")
                .deploy();
        System.out.println(deploy.getId());
        System.out.println(deploy.getName());
    }
}
1.4.1.2 静态类部署
	@Test
    public void testDeployment(){
//        1、创建ProcessEngine
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//        2、得到RepositoryService实例
        RepositoryService repositoryService = processEngine.getRepositoryService();
//        3、使用RepositoryService进行部署
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource("process/qingjia.bpmn") // 添加bpmn资源 
                .name("请假申请流程")
                .deploy();
//        4、输出部署信息
        System.out.println("流程部署id:" + deployment.getId());
        System.out.println("流程部署名称:" + deployment.getName());
    }
1.4.1.3 压缩包部署方式
@Autowired
private RepositoryService repositoryService;
@Test
public void deployProcessByZip() {
    // 定义zip输入流
    InputStream inputStream = this
            .getClass()
            .getClassLoader()
            .getResourceAsStream(
                    "process/qingjia.zip");
    ZipInputStream zipInputStream = new ZipInputStream(inputStream);

    // 流程部署
    Deployment deployment = repositoryService.createDeployment()
            .addZipInputStream(zipInputStream)
            .name("请假申请流程")
            .deploy();
    System.out.println("流程部署id:" + deployment.getId());
    System.out.println("流程部署名称:" + deployment.getName());
}
1.4.1.4 查看文件
@Test
public void  queryBpmnFile() throws IOException {
//得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
    ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
            .processDefinitionKey("qingjia")
            .singleResult();
//通过流程定义信息,得到部署ID
    String deploymentId = processDefinition.getDeploymentId();
//  通过repositoryService的方法,实现读取图片信息和bpmn信息
//        png图片的流
    InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
//        bpmn文件的流
    InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
//  构造OutputStream流
    File file_png = new File("d:/qingjia.png");
    File file_bpmn = new File("d:/qingjia.bpmn");
    FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
    FileOutputStream pngOut = new FileOutputStream(file_png);
//        7、输入流,输出流的转换
    IOUtils.copy(pngInput,pngOut);
    IOUtils.copy(bpmnInput,bpmnOut);
//        8、关闭流
    pngOut.close();
    bpmnOut.close();
    pngInput.close();
    bpmnInput.close();
}

1.4.2 启动流程实例和查询

将bpmn文件放到activiti的三张表中,好比是java中的一个类 流程实例:好比是java中的一个实例对象(一个流程定义可以对应多个流程实例),张三可以启动一个请假流程实例,李四也可以启动一个请假流程实例,他们互不影响

@Autowired
private RuntimeService runtimeService;

@Test
public void startUpProcess() {
    //创建流程实例,我们需要知道流程定义的key
    ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("qingjia");
    //输出实例的相关信息
    System.out.println("流程定义id:" + processInstance.getProcessDefinitionId());
    System.out.println("流程实例id:" + processInstance.getId());
    System.out.println("当前活动Id:" + processInstance.getActivityId());
}

注意:使用startProcessInstanceByKey的方式不用在部署了,springboot会自动部署bpmn文件
操作数据表:

  • act_hi_actinst 流程实例执行历史
  • act_hi_identitylink 流程的参与用户历史信息
  • act_hi_procinst 流程实例历史信息
  • act_hi_taskinst 流程任务历史信息
  • act_ru_execution 流程执行信息
  • act_ru_identitylink 流程的参与用户信息
  • act_ru_task 任务信息
/**
 * 查询流程实例
 */
@Test
public void queryProcessInstance() {
    List<ProcessInstance> list = runtimeService
            .createProcessInstanceQuery("qingjia")
            .processDefinitionKey()//
            .list();

    for (ProcessInstance processInstance : list) {
        System.out.println("----------------------------");
        System.out.println("流程实例id:"
                + processInstance.getProcessInstanceId());
        System.out.println("所属流程定义id:"
                + processInstance.getProcessDefinitionId());
        System.out.println("是否执行完成:" + processInstance.isEnded());
        System.out.println("是否暂停:" + processInstance.isSuspended());
        System.out.println("当前活动标识:" + processInstance.getActivityId());
        System.out.println("业务关键字:"+processInstance.getBusinessKey());
    }
}

查看流程实例历史

/**
 * 查看历史信息
 */
@Test
public void findHistoryInfo(){
//        获取 actinst表的查询对象
    HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//        查询 actinst表,条件:根据 InstanceId 查询,查询一个流程的所有历史信息
    instanceQuery.processInstanceId("25001");
//        查询 actinst表,条件:根据 DefinitionId 查询,查询一种流程的所有历史信息
//        instanceQuery.processDefinitionId("myLeave:1:22504");
//        增加排序操作,orderByHistoricActivityInstanceStartTime 根据开始时间排序 asc 升序
    instanceQuery.orderByHistoricActivityInstanceStartTime().asc();
//        查询所有内容
    List<HistoricActivityInstance> activityInstanceList = instanceQuery.list();
//        输出
    for (HistoricActivityInstance hi : activityInstanceList) {
        System.out.println(hi.getActivityId());
        System.out.println(hi.getActivityName());
        System.out.println(hi.getProcessDefinitionId());
        System.out.println(hi.getProcessInstanceId());
        System.out.println("<==========================>");
    }
}

1.4.3 查询任务和历史

每个节点都配置了Assignee,流程启动后,任务的负责人就可以查询自己当前需要处理的任务,查询出来的任务都是该用户的待办任务。

@Autowired
private TaskService taskService;/**
 * 查询当前个人待执行的任务
 */
@Test
public void findPendingTaskList() {
    //任务负责人
    String assignee = "zhangsan";
    List<Task> list = taskService.createTaskQuery()
    		.processDefinitionKey("qingjia") //流程Key
            .taskAssignee(assignee)//只查询该任务负责人的任务
            .list();
    for (Task task : list) {
        System.out.println("流程实例id:" + task.getProcessInstanceId());
        System.out.println("任务id:" + task.getId());
        System.out.println("任务负责人:" + task.getAssignee());
        System.out.println("任务名称:" + task.getName());
    }
}

@Autowired
private HistoryService historyService;/**
 * 查询已处理历史任务
 */
@Test
public void findProcessedTaskList() {
    //张三已处理过的历史任务
    List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
	.processDefinitionKey("qingjia") //流程Key
	.taskAssignee("zhangsan").finished().list();
    for (HistoricTaskInstance historicTaskInstance : list) {
        System.out.println("流程实例id:" + historicTaskInstance.getProcessInstanceId());
        System.out.println("任务id:" + historicTaskInstance.getId());
        System.out.println("任务负责人:" + historicTaskInstance.getAssignee());
        System.out.println("任务名称:" + historicTaskInstance.getName());
    }
}

说明:

  • 流程实例id:一个流程只有一个,标识这个流程
  • 任务id:流程每进行到某个节点,就会给这个节点分配一个任务id

1.4.4 处理当前任务

任务负责人查询待办任务,选择任务进行处理,完成任务。

@Test
public void completTask(){
    Task task = taskService.createTaskQuery()
    		.processDefinitionKey("qingjia") //流程Key
            .taskAssignee("zhangsan")  //要查询的负责人
            .singleResult();//返回一条//完成任务,参数:任务id
    taskService.complete(task.getId());
}

完成任务后,任务自动到下一个节点

1.4.5 流程定义

/**
 * 查询流程定义
 */
@Test
public void findProcessDefinitionList(){
    List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
    		.processDefinitionKey("qingjia")
            .orderByProcessDefinitionVersion()
            .desc()
            .list();
    //输出流程定义信息
    for (ProcessDefinition processDefinition : definitionList) {
        System.out.println("流程定义 id="+processDefinition.getId());
        System.out.println("流程定义 name="+processDefinition.getName());
        System.out.println("流程定义 key="+processDefinition.getKey());
        System.out.println("流程定义 Version="+processDefinition.getVersion());
        System.out.println("流程部署ID ="+processDefinition.getDeploymentId());
    }
}/**
 * 删除流程定义
 */
public void deleteDeployment() {
    //部署id
    String deploymentId = "82e3bc6b-81da-11ed-8e03-7c57581a7819";
    //删除流程定义,如果该流程定义已有流程实例启动则删除时出错
    repositoryService.deleteDeployment(deploymentId);
    //设置true 级联删除流程定义,即使该流程有流程实例启动也可以删除,设置为false非级别删除方式
    //repositoryService.deleteDeployment(deploymentId, true);
}

1.5 新版校验操作

1.5.1 配置Security用户

@Configuration
@EnableWebSecurity
public class MyWebSecurityConfiguration {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeRequests(authorize -> authorize.anyRequest().authenticated())
                .formLogin(Customizer.withDefaults());
        return http.build();
    }

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring()
                .requestMatchers()
                // Spring Security should completely ignore URLs starting with /resources/
                .antMatchers("/**");
    }

    @Bean
    public UserDetailsService userDetailsService() {
        UserDetails admin = User.withUsername("tom")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER", "ACTIVITI_ADMIN", "APPLICATION_MANAGER")
                .build();
        UserDetails user = User.withUsername("jerry")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER", "GROUP_BUSINESS_MANAGER")
                .build();
        UserDetails zhangsan = User.withUsername("zhangsan")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER")
                .build();
        UserDetails lisi = User.withUsername("lisi")
                .password("$2a$10$tk29HhXGXCZDOSvn.VZlFeBsLmtJrKE2Uv6zLrRpTyvZMu3ipQLgC")
                .roles("ACTIVITI_USER")
                .build();
        return new InMemoryUserDetailsManager(admin, user, zhangsan, lisi);
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("123456"));
    }
}

Security工具类

@Component
public class SecurityUtil {

    @Autowired
    private UserDetailsService userDetailsService;

    public void logInAs(String username) {
        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (null == user) {
            throw new IllegalStateException(String.format("用户【%s】不存在", username));
        }
        SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
            @Override
            public Collection<? extends GrantedAuthority> getAuthorities() {
                return user.getAuthorities();
            }

            @Override
            public Object getCredentials() {
                return user.getPassword();
            }

            @Override
            public Object getDetails() {
                return user;
            }

            @Override
            public Object getPrincipal() {
                return user;
            }

            @Override
            public boolean isAuthenticated() {
                return true;
            }

            @Override
            public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {

            }

            @Override
            public String getName() {
                return user.getUsername();
            }
        }));
        org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
    }
}

1.5.2 操作

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestSecurityActiviti {

    @Autowired
    private ProcessRuntime processRuntime;

    @Autowired
    private TaskRuntime taskRuntime;

    @Autowired
    private SecurityUtil securityUtil;

    @Test
    public void findProcess(){
        securityUtil.logInAs("jack");

        final ProcessDefinition processDefinition = processRuntime.processDefinition("apply");
        log.info("流程定义内容:{}",processDefinition);

        final Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
        for (ProcessDefinition definition : processDefinitionPage.getContent()) {
            log.info("2- 流程定义内容:  {}",definition);
        }
    }

    /**
     * 启动流程
     */
    @Test
    public void startProcess(){
//        设置登录用户
        securityUtil.logInAs("system");
        ProcessInstance processInstance = processRuntime.
                start(ProcessPayloadBuilder.
                        start().
                        withProcessDefinitionKey("apply").
                        build());
        log.info("流程实例的内容,{}",processInstance);
    }

    /**
     * 执行任务
     */
    @Test
    public void doTask(){
//        设置登录用户
        securityUtil.logInAs("jerry");
//        查询任务
        Page<Task> taskPage = taskRuntime.tasks(Pageable.of(0, 10));
        if(taskPage != null && taskPage.getTotalItems()>0){
            for (Task task : taskPage.getContent()) {
                //        拾取任务
                taskRuntime.claim(TaskPayloadBuilder.
                        claim().
                        withTaskId(task.getId()).
                        build());
                log.info("任务内容,{}",task);
                //        完成任务
                taskRuntime.complete(TaskPayloadBuilder.
                        complete().
                        withTaskId(task.getId()).
                        build());
            }
        }
    }
}

1.5.3 报错 Process definition with the given id:xxx belongs to a different application version

报错参考:https://blog.csdn.net/u011410254/article/details/117368489
在resources目录下添加文件default-project.json内容:

{
  "createdBy": "superadminuser",
  "creationDate": "2019-08-16T15:58:46.056+0000",
  "lastModifiedBy": "qa-modeler-1",
  "lastModifiedDate": "2019-08-16T16:03:41.941+0000",
  "id": "c519a458-539f-4385-a937-2edfb4045eb9",
  "name": "projectA",
  "description": "",
  "version": "1"
}

application配置文件:


# project manifest path
project.manifest.file.path=classpath:/default-project.json

1.6 Activiti 7.1.0.M6之后

activiti-spring-boot-starter最大是支持到7.1.0.M6,在大版本就需要 如下处理
pom.xml

<parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.5</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.activiti</groupId>
                <artifactId>activiti-dependencies</artifactId>
                <version>7.6.1</version>
                <scope>import</scope>
                <type>pom</type>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <repositories>
        <repository>
            <id>activiti-releases</id>
            <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases</url>
        </repository>
    </repositories>

修改 mirror 镜像

  <mirrors>
	 <mirror>
		<id>nexus-aliyun</id>
		<mirrorOf>*,!activiti-releases</mirrorOf>
		<url>https://maven.aliyun.com/repository/public</url>	
	</mirror>
  </mirrors>

http://www.kler.cn/news/293401.html

相关文章:

  • Elastic Stack--ES集群加密及Kibana的RBAC实战
  • 报错:Reached the max session limit(DM8 达梦数据库)
  • 【C语言】---- 复合数据类型之结构体(Struct)
  • 期权虚值和实值的投资风险有什么不同?
  • docker 安装mongoDB
  • Anchor Alignment Metric来优化目标检测的标签分配和损失函数。
  • Apache CloudStack Official Document 翻译节选(十三)
  • 使用多尺度C-LSTM进行单变量时间序列异常检测
  • 细胞因子系列
  • 92. UE5 GAS RPG 使用C++创建GE实现灼烧的负面效果
  • 嵌入式学习(链式栈和链式队列)
  • yolov8目标检测pyside6可视化图形界面+检测源码ui文件——用于计数统计
  • Docker基本使用:创建clickhouse容器
  • OKRs-E 目标管理上手指南
  • 电脑错误mfc140.dll丢失怎么办?mfc140.dll丢失如何修复?
  • 使用docker调试odoo
  • 并行编程实战——TBB的安装
  • Go语言实战 pdf
  • 2、硬件工程师笔试面试汇总
  • 实时渲染技术的崛起:游戏与实时交互的新篇章
  • ISO26262和Aspice之间的关联
  • OpenCV结构分析与形状描述符(7)计算轮廓的面积的函数contourArea()的使用
  • Qt/QML学习-Calendar
  • 探秘DevSecOps黄金管道,安全与效率的完美融合
  • Golang | Leetcode Golang题解之第391题完美矩形
  • 实战docker第一天——windows安装docker,测试,并解决被墙办法
  • 【最后一轮征稿】第三届人工智能、物联网和云计算技术国际会议(AIoTC 2024)
  • Oracle同一台服务器创建多个数据库
  • 计算机毕业设计选题推荐-中华诗词文化交流平台-Java/Python项目实战
  • cmd常用指令举例说明使用方法