Springboot整合Activiti详解

这篇具有很好参考价值的文章主要介绍了Springboot整合Activiti详解。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。



版本依赖

  • 开发工具 IDEA
  • SpringBoot 2.4.5(这里我试过SpringBoot 3.1.1版本,Activiti没有启动,应该是依赖冲突了,后改成了2.4.5版本)
  • Activiti 7.1.0.M6

父项目pom.xml

    <dependencyManagement>
        <dependencies>
            <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-parent -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-parent</artifactId>
                <version>2.4.5</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.activiti.dependencies/activiti-dependencies -->
            <dependency>
                <groupId>org.activiti.dependencies</groupId>
                <artifactId>activiti-dependencies</artifactId>
                <version>7.1.0.M6</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

子项目pom.xml

    <dependencies>
        <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>
        </dependency>
        <dependency>
            <groupId>org.activiti</groupId>
            <artifactId>activiti-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
    </dependencies>

配置文件

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    username: root
    password: 111111
    url: jdbc:mysql://127.0.0.1:3306/activiti?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8&useSSL=false&useInformationSchema=true
    hikari:
      #连接池做大连接数
      maximum-pool-size: 30
      #连接池空闲连接最小数量
      #minimum-idle: 10
      #允许连接在连接池中闲置最长时间
      #idle-timeout: 30000
      #池中连接最长生命周期
      max-lifetime: 120000
      #等待来自池的连接的最大毫秒数
      connection-timeout: 30000
  activiti:
    #自动更新数据库结构
    #1.flase:默认值。activiti在启动时,对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常
    #2.true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建
    #3.create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)
    #4.drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    database-schema-update: true
    #activiti7默认不生成历史信息表,开启历史表
    db-history-used: true
    #记录历史等级 可配置的历史级别有none, activity, audit, full
    #none:不保存任何的历史数据,因此,在流程执行过程中,这是最高效的。
    #activity:级别高于none,保存流程实例与流程行为,其他数据不保存。
    #audit:除activity级别会保存的数据外,还会保存全部的流程任务及其属性。audit为history的默认值。
    #full:保存历史数据的最高级别,除了会保存audit级别的数据外,还会保存其他全部流程相关的细节数据,包括一些流程参数等。
    history-level: full
    #自动检查、部署流程定义文件
    check-process-definitions: false
    # asyncExecutorActivate是指activiti在流程引擎启动就激活AsyncExecutor,异步:true-开启(默认)、false-关闭
    async-executor-activate: true

配置文件这里注意要设置 database-sechema-update的属性为true,才会自动创建表。

需要注意的问题

在初次启动时可能会报错,报错如下:

Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.springframework.security.core.userdetails.UserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1790)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1346)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1300)
	at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:887)
	at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791)
	... 142 more

这里是需要一个UserDetailsService的Bean,需要创建一个类去实现UserDetailsService接口

UserDetailsServiceImpl.class

package org.example.config;

import org.example.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;

@Component
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    UserService userService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        return userService.findOneUserByName(username);
    }
}

UserService.class

package org.example.service;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserService {

    public User findOneUserByName(String username){
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
        return new User(username,"",authorities);
    }
}

启动成功后,数据库会生成25张表
Springboot整合Activiti详解,Spring,spring boot,后端,java

画流程图

在使用IDEA时,需要下载一个插件
Springboot整合Activiti详解,Spring,spring boot,后端,java
当这个插件安装好以后,新建文件会多一个选项
Springboot整合Activiti详解,Spring,spring boot,后端,java
新建的xml文件可以通过view BPMN Diagram,转化为图表操作
Springboot整合Activiti详解,Spring,spring boot,后端,java
Springboot整合Activiti详解,Spring,spring boot,后端,java
如何通过图表操作画流程这里就不说了,可以自己摸索看看。

activiti服务类进行编写

package org.example.service;

import org.activiti.engine.*;
import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.DeploymentQuery;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

@Service
public class ActivitiService {

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    TaskService taskService;

    @Autowired
    HistoryService historyService;

    /**
     * 部署流程服务
     */
    public void deployProcess(){
        String file = "bpmn/test.bpmn20.xml";
        Deployment deployment = repositoryService.createDeployment()
                .addClasspathResource(file)
                .name("流程部署测试")
                .deploy();
        System.out.println("流程部署名称:"+deployment.getName());
    }

    /**
     * 查询所有部署的流程定义
     * @return
     */
    public List<ProcessDefinition> getAllProcessDefinition(){
        ProcessDefinitionQuery query = repositoryService.createProcessDefinitionQuery();
        return query.orderByProcessDefinitionVersion().desc().list();
    }

    /**
     * 查询所有的部署
     * @return
     */
    public List<Deployment> getAllDeployment(){
        DeploymentQuery query = repositoryService.createDeploymentQuery();
        return query.list();
    }

    /**
     * 查询所有流程实例
     * @return
     */
    public List<ProcessInstance> getAllProcessInstance(){
        List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
        return list;
    }

    public List<Task> getAllProcessTask(){
        List<Task> list = taskService.createTaskQuery().list();
        return list;
    }


    /**
     * 查询用户待完成和待认领的任务
     * @param username
     * @return
     */
    public List<Task> getAllProcessTaskByCandidateOrAssigned(String username){
        List<Task> list = taskService.createTaskQuery().taskCandidateOrAssigned(username).list();
        return list;
    }



    public List<Task> getAllProcessTaskByCandidate(String username){
        List<Task> list = taskService.createTaskQuery().taskCandidateUser(username).list();
        return list;
    }



    /**
     * 查询用户的待完成任务
     * @param username
     * @return
     */
    public List<Task> getAllProcessTaskByAssigned(String username){
        List<Task> list = taskService.createTaskQuery().taskAssignee(username).list();
        return list;
    }

    public void complateTask(Task task, Map<String, Object> map){
        taskService.complete(task.getId(),map);
    }


    public void complateTask(Task task){
        taskService.complete(task.getId());
    }


    public void claimTask(Task task,String username){
        taskService.claim(task.getId(),username);
    }
    public ProcessInstance startProcess(String processDefinitionKey,String businessKey,Map<String,Object> map){
        return runtimeService.startProcessInstanceById(processDefinitionKey,businessKey,map);
    }

    public String getProcessDefinitionXml(String processDefinitionId) {
        ProcessDefinition processDefinition = repositoryService.getProcessDefinition(processDefinitionId);
        String resourceName = processDefinition.getResourceName();
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        try {
            return IOUtils.toString(resourceAsStream, StandardCharsets.UTF_8);
        } catch (IOException e) {
            // handle exception
        }
        return null;
    }


    public List<HistoricProcessInstance> getHistoryByBusinessKey(String businessKey){
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).list();
        return list;
    }
}

Springboot整合Activiti详解,Spring,spring boot,后端,java
上图是,如果需要使用activiti中提供的服务类,直接注入即可。即springboot整合activiti启动过程中,已经在容器中自动装配了对应的服务类,需要的时候,仅仅需要取来用即可。如果启动以后报错,容器没有自动装配对应的服务类,那很有可能是依赖冲突,activiti没有正常启动。

流程部署

流程部署有多种方式,这是通过资源路径部署的,也可以通过压缩包的形式部署流程。那就需要用到DeploymentBuilderaddZipInputStream方法,这里也是用到了设计模式中的建造者模式。
Springboot整合Activiti详解,Spring,spring boot,后端,java

Springboot整合Activiti详解,Spring,spring boot,后端,java

流程定义

这是一个查询所有部署的流程定义的方法
Springboot整合Activiti详解,Spring,spring boot,后端,java
当一个流程部署以后,就会生成一个流程定义,流程图的xml信息也会存入数据库。每次部署流程图都会生成一个新的流程定义。
Springboot整合Activiti详解,Spring,spring boot,后端,java

启动流程

启动流程可以通过流程定义的id或者key,如果想通过流程定义的id启动一个流程可以使用startProcessInstanceById方法,如果想通过流程定义的key启动一个流程可以使用startProcessInstanceByKey方法。Springboot整合Activiti详解,Spring,spring boot,后端,java
这里要明白流程定义id和key的区别,流程定义的key是在画流程的时候可以设置的,通过设置流程的id,这个就是流程的key。
Springboot整合Activiti详解,Spring,spring boot,后端,java

Springboot整合Activiti详解,Spring,spring boot,后端,java
那流程的id呢,这是部署以后在数据库表的id。可以根据需要自行选择启动流程的方法。

流程实例

查询所有启动的流程实例
Springboot整合Activiti详解,Spring,spring boot,后端,java
每次开始一个流程以后,就会生成一个流程实例。通过这个方法可以查看所有的流程实例。

测试流程

package org.example;

import org.activiti.engine.history.HistoricProcessInstance;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.assertj.core.util.DateUtil;
import org.example.common.PrintUtil;
import org.example.entity.User;
import org.example.service.ActivitiService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import javax.annotation.Resource;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.*;

@SpringBootTest
public class SpringBootApplicationTest {

    @Resource
    DataSource dataSource;

    @Autowired
    ActivitiService activitiService;


    @Test
    void context() throws SQLException {
        System.out.println(dataSource.getConnection());
    }

    @Test
    public void deployProcess(){
        activitiService.deployProcess();
    }

    @Test
    public void TestStartProcess(){
        ProcessDefinition processDefinition = activitiService.getAllProcessDefinition().get(0);
        String bussinessKey = this.getClass().getSimpleName();
        Map<String , Object> map = new HashMap<String , Object>();
        map.put("creator","Echo");
        activitiService.startProcess(processDefinition.getId(),bussinessKey,map);
    }

    @Test
    public void findAllDeployment(){
        List<Deployment> list = activitiService.getAllDeployment();
        PrintUtil.printTable(list);
    }

    @Test
    public void findAllProcessDefinition(){
        List<ProcessDefinition> list = activitiService.getAllProcessDefinition();
        PrintUtil.printTable(list);
    }


    @Test
    public void findAllProcessInstance(){
        List<ProcessInstance> list = activitiService.getAllProcessInstance();
        PrintUtil.printTable(list);
    }

    @Test
    public void findAllProcessTask(){
        List<Task> list = activitiService.getAllProcessTask();
        PrintUtil.printTable(list);
    }

    @Test
    public void findTaskByUserId(){
        String userId = "keaizp";
        List<Task> list = activitiService.getAllProcessTaskByCandidateOrAssigned(userId);
        PrintUtil.printTable(list);
    }

    @Test
    public void claimTask(){
        String userId="keaizp";
        List<Task> list = activitiService.getAllProcessTaskByCandidate(userId);
        PrintUtil.printTable(list);
        activitiService.claimTask(list.get(0),userId);
        list = activitiService.getAllProcessTaskByCandidate("zengpei");
        PrintUtil.printTable(list);
    }
    @Test
    public void complateUserTask(){
        String userId = "Echo";
        List<Task> list = activitiService.getAllProcessTaskByAssigned(userId);
        List<String> candidateUsers = new ArrayList<String>();
        candidateUsers.add("keaizp");
        candidateUsers.add("zengpei");
        Map<String,Object> map = new HashMap<String,Object>();
        map.put("approver",candidateUsers);
        activitiService.complateTask(list.get(0),map);
    }

    @Test
    public void processDefinitionXml(){
        List<ProcessDefinition> list = activitiService.getAllProcessDefinition();
        String xmlStr = activitiService.getProcessDefinitionXml(list.get(0).getId());
        System.out.println(xmlStr);
    }

    @Test
    public void findHistoryByBusinessKey(){
        List<HistoricProcessInstance> list = activitiService.getHistoryByBusinessKey("2023-07-02T22:45:45");
        PrintUtil.printTable(list);
    }


    @Test
    public void printTest(){
        List<User> users = new ArrayList<>();
        users.add(new User("keaizpeeeeeeeee",24,"male"));
        users.add(new User("Echo",24,"male"));
        users.add(new User("nick",24,"male"));
        users.add(new User("amy",24,"male"));
        PrintUtil.printTableFixed(users,16);
    }
}


启动流程

Springboot整合Activiti详解,Spring,spring boot,后端,java
这里我用的是一个格式化的日期做bussinessKey,实际业务中最好使用 流程作业类型 + 一个业务台账id,比如:请假申请要走审批流程, 离职申请也要走审批流程,如果只用id作为bussinessKey的话,bussinessKey就无法满足唯一性。所以最好 前面加上作业类型。这里的map传入的是流程图里面的参数。
Springboot整合Activiti详解,Spring,spring boot,后端,java
传入受理人,这里就会产生一个Task,就是用户的代办任务。

完成任务

Springboot整合Activiti详解,Spring,spring boot,后端,java
当用户登录系统的时候,应该给用户提示,用户有未完成的代办事项,然后给出用户代办事项列表,做完一切以后,就是完成用户任务,这个时候,可以传入下一流程节点参与任务的人,当然你也可以传入几个候选人,candidate Users就是 候选人。可以传入一个用户id的列表,然后这几个人就会收到可以受理的任务,可以选择是否接受该任务。只要接受了任务,其他候选人就无法再接受此任务,同时这个任务的Assignee就会设置成受理人的id

受理任务

Springboot整合Activiti详解,Spring,spring boot,后端,java
因为用户“keaizp”成为了候选者,他就可以看到自己可以受理的这个任务,用claim方法就可以受理该任务,当受理任务完成以后,再去看看另外一名候选者的受理任务,会发现已经没有待受理的任务了。文章来源地址https://www.toymoban.com/news/detail-524406.html


到了这里,关于Springboot整合Activiti详解的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Springboot整合Activiti详解

    开发工具 IDEA SpringBoot 2.4.5 (这里我试过SpringBoot 3.1.1版本,Activiti没有启动,应该是依赖冲突了,后改成了2.4.5版本) Activiti 7.1.0.M6 父项目pom.xml 子项目pom.xml 配置文件这里注意要设置 database-sechema-update 的属性为 true ,才会自动创建表。 在初次启动时可能会报错,报错如下:

    2024年02月12日
    浏览(34)
  • 【SpringBoot】Spring Boot 项目中整合 MyBatis 和 PageHelper

    目录 前言         步骤 1: 添加依赖 步骤 2: 配置数据源和 MyBatis 步骤 3: 配置 PageHelper 步骤 4: 使用 PageHelper 进行分页查询 IDEA指定端口启动 总结         Spring Boot 与 MyBatis 的整合是 Java 开发中常见的需求,特别是在使用分页插件如 PageHelper 时。PageHelper 是一个针对 MyBat

    2024年04月25日
    浏览(51)
  • Spring Boot + Activiti 结合,实现工作流

    Activiti是一个工作流引擎,Activiti可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程由Activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,Activiti流程就是数据库表

    2023年04月13日
    浏览(75)
  • 【Spring Boot】SpringBoot 优雅整合Swagger Api 自动生成文档

    Swagger 是一套 RESTful API 文档生成工具,可以方便地生成 API 文档并提供 API 调试页面。 而 Spring Boot 是一款非常优秀的 Java Web 开发框架,它可以非常方便地构建 Web 应用程序。 在本文中,我们将介绍如何使用 Swagger 以及如何在 Spring Boot 中整合 Swagger 。 首先,在 pom.xml 文件中添

    2023年04月22日
    浏览(46)
  • 【工作流】Activiti工作流简介以及Spring Boot 集成 Activiti7

    什么是工作流? 工作流指通过计算机对业务流程进行自动化管理,实现多个参与者按照预定义的流程去自动执行业务流程。 文章源码托管:https://github.com/OUYANGSIHAI/Activiti-learninig Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、

    2024年02月08日
    浏览(51)
  • SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月12日
    浏览(66)
  • SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接

    系列文章: SpringBoot + Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot + Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot + Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot + Vue前后端分离项目实战 || 四:用户管理功能实现 SpringBoot + Vue前后

    2024年02月11日
    浏览(60)
  • spring boot学习第六篇:SpringBoot 集成WebSocket详解

    1、WebSocket简介 WebSocket协议是基于TCP的一种新的网络协议。它实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。 2、为什么需要WebSocket HTTP 是基于请求响应式的,即通信只能由客户端发起,服务端做出响应,无状态,无连接。 无状态:每次连

    2024年01月21日
    浏览(50)
  • spring boot es | spring boot 整合elasticsearch | spring boot整合多数据源es

    目录 Spring Boot与ES版本对应 Maven依赖 配置类 使用方式 @Test中注入方式 @Component中注入方式 查询文档 实体类 通过ElasticsearchRestTemplate查询 通过JPA查询 保存文档 参考链接 项目组件版本: Spring Boot:2.2.13.RELEASE Elasticsearch:6.8.0 JDK:1.8.0_66 Tips: 主要看第3列和第5列,根据ES版本选择

    2023年04月18日
    浏览(56)
  • 【Spring Boot】Spring Boot整合多数据源

    在实际的开发工作中,我们经常会遇到需要整合多个数据源的情况,比如同时连接多个数据库、读写分离、跨数据库查询等。本文将介绍如何使用Spring Boot来实现多数据源的整合,对于刚刚接触开发的小伙伴可能有一些帮助。 在一个应用程序中使用多个数据源意味着我们需要

    2024年02月10日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包