Activiti学习笔记:Activiti和Spring整合、Activiti和SpringBoot整合之Gradle版

环境

activiti:7+
Java:11
本机环境:window
MySQL:5.7
gradlew:6+

Activiti和Spring整合

大体流程:

  1. 先创建项目,并导入依赖
  2. 添加activiti-spring.xml配置文件,这里是整合的关键
  3. 编写测试类

创建项目

利用Intellij IDEA创建一个Spring空项目,gradle版的。

导入依赖

buildscript {
    ext {
        activitiVersion = '7.1.0.M6'
        mysqlVersion = '5.1.49'
        mybatisVersion = '3.5.6'
        druidVersion = '1.2.5'
        junitVersion = '4.12'
        aspectjVersion = '1.9.6'
        springTest = '5.1.3.RELEASE'
    }
}

plugins {
    id 'java'
}

group 'org.sgy'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

dependencies {

    //activiti
    implementation("org.activiti:activiti-engine:$activitiVersion")
    implementation("org.activiti:activiti-bpmn-model:$activitiVersion")
    implementation("org.activiti:activiti-bpmn-converter:$activitiVersion")
    implementation("org.activiti:activiti-bpmn-layout:$activitiVersion")

    //spring
    implementation("org.activiti:activiti-spring:$activitiVersion")
    implementation("org.aspectj:aspectjweaver:$aspectjVersion")

    //json
    implementation("org.activiti:activiti-json-converter:$activitiVersion")

    //mysql
    implementation("mysql:mysql-connector-java:$mysqlVersion")

    //mybatis
    implementation("org.mybatis:mybatis:$mybatisVersion")

    //数据源
    implementation("com.alibaba:druid:$druidVersion")

    testImplementation("junit:junit:$junitVersion")
    testImplementation("org.springframework:spring-test:$springTest")
}

创建activiti与spring的配置文件

文件名随意取:activiti-spring.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">

    <!--数据源:即连接池的配置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/activiti?useSSL=false"/>
        <property name="username" value="yutao"/>
        <property name="password" value="yutaoyutao"/>
    </bean>

    <!--事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--aop配置-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="save*" propagation="REQUIRED"/>
            <tx:method name="insert*" propagation="REQUIRED"/>
            <tx:method name="delete*" propagation="REQUIRED"/>
            <tx:method name="update*" propagation="REQUIRED"/>
            <tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
            <tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
        </tx:attributes>
    </tx:advice>

    <!--切面,根据具体项目修改切点配置-->
    <!--<aop:config proxy-target-class="true">
        <aop:advisor advice-ref="txAdvice" pointcut="execution(*com.sgy.xxx..(..))"/>
    </aop:config>-->

    <!--工作流引擎配置bean-->
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <!--数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--使用spring事务管理器-->
        <property name="transactionManager" ref="transactionManager"/>
        <!--数据库策略-->
        <property name="databaseSchemaUpdate" value="drop-create"/>
    </bean>

    <!--流程引擎-->
    <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>
    <!--资源服务service-->
    <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
    <!--流程运行service-->
    <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
    <!--任务管理器service-->
    <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
    <!--历史管理器service-->
    <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>

</beans>

数据库策略的作用?

<!--数据库策略-->
<property name="databaseSchemaUpdate" value="drop-create"/>

主要是启动activiti做表操作的策略,databaseSchemaUpdate的取值内容:

取值作用
false默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产环境常用)
trueactiviti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
create_dropactiviti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表,单元测试常用)
drop-createactiviti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)

编写测试代码

import org.activiti.engine.RepositoryService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:activiti-spring.xml")
public class actSpringTest {

    @Autowired
    private RepositoryService repositoryService;

    @Test
    public void testRep() {
        System.out.println("你执行了吗?");
        System.out.println(repositoryService);
    }
}

说明:

  1. 注解:@ContextConfiguration是加载spring容器,这样,就可以使用如下代码:
@Autowired
private RepositoryService repositoryService;
  1. 在执行后,因为spring容器会通过xml配置文件去加载activiti配置,所以也就会去初始化17张表,原本有25张表,但是activiti7默认初始化history相关的表。
    在这里插入图片描述

自此说明整合成功。


Activiti和SpringBoot整合

大体思路:

  1. 先通过springboot初始化器生成项目骨架
  2. 添加依赖
  3. 添加配置
  4. 创建SpringSecurity权限相关的用户、密码、权限、所属组放入内存
  5. 启动项目

生成项目骨架

这个可以利用springboot官网去生成或者利用Intellij IDEA来生成。

添加依赖

buildscript {
    ext {
        activitiVersion = '7.1.0.M6'
        jbdcVersion = '2.4.4'
        mysqlVersion = '5.1.49'
    }
}

plugins {
    id 'org.springframework.boot' version '2.4.4'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'com.sgy'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    //activiti
    implementation("org.activiti:activiti-spring-boot-starter:$activitiVersion")
    //mysql
    implementation("mysql:mysql-connector-java:$mysqlVersion")
    //jdbc
    implementation("org.springframework.boot:spring-boot-starter-jdbc:$jbdcVersion")
    //web
    implementation 'org.springframework.boot:spring-boot-starter-web'
    //数据源
    implementation("com.alibaba:druid:$druidVersion")

    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

test {
    useJUnitPlatform()
}

添加配置

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/activitispringboot?useSSL=false
    username: yutao
    password: yutaoyutao
    type: com.alibaba.druid.pool.DruidDataSource

  activiti:
    database-schema-update: true
    #activiti7默认不生成历史信息表,开启历史表
    db-history-used: true
    #历史信息等级
    history-level: full

原则上,目前应该整合完毕;

但是,假设现在就启动,会报错:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-03-28 18:15:36.430 ERROR 15604 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

***************************
APPLICATION FAILED TO START
***************************

Description:

Parameter 0 of method userGroupManager in org.activiti.core.common.spring.identity.config.ActivitiSpringIdentityAutoConfiguration required a bean of type 'org.springframework.security.core.userdetails.UserDetailsService' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=false)


Action:

Consider defining a bean of type 'org.springframework.security.core.userdetails.UserDetailsService' in your configuration.


Process finished with exit code 1

这是因为activiti7的源码和springsecurity进行了整合,需要获取用户权限信息,如果启动时没有就会报错;正常情况下,我们应该自定义相应配置,让程序去读用户权限表,但是这里为了测试,就直接写死,并将数据保存到内存中,这里就用官方提供的例子:

配置security相关类

我们需要告诉security到哪里获取用户信息,因为是测试代码,我们就简单点,直接硬编码写在内存里吧~ 此处,采用官方提供的代码:

官方的源码类名叫DemoApplicationConfiguration,我重命名了,改为UserDetailsConfiguration

官方地址:https://github.com/Activiti/activiti-examples/blob/master/activiti-api-basic-task-example/src/main/java/org/activiti/examples/DemoApplicationConfiguration.java#L26

package com.sgy.activitispringbootdemo.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Configuration
public class UserDetailsConfiguration {

    private Logger logger = LoggerFactory.getLogger(UserDetailsConfiguration.class);

    @Bean
    public UserDetailsService myUserDetailsService() {
        //将用户信息存入内存
        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
        // 构造用户信息
        String[][] usersGroupsAndRoles = {
                // 用户名、密码、ROLE_:是角色的前置,后面跟着的是角色名、GROUP_:用户组前置,activitiTeam是组的名称
                {"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
                {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
                {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
        };

        for (String[] user : usersGroupsAndRoles) {
            //从角色开始获取,也就得到了用户的认证信息。
            List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
            logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
            inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
                    authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
        }


        return inMemoryUserDetailsManager;
    }


    /**
     * 加密
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}

有上面这个类,启动程序就ok了。

不过在使用activiti的过程中,你会发现,对它的操作,都需要先登录,即让security知道当前是哪个用户,为了方便测试,我们可以再编写一个工具类:

官方地址:https://github.com/Activiti/activiti-examples/blob/ddd1cf9c77374267b68150262e1a5559b3a63567/activiti-api-basic-task-example/src/main/java/org/activiti/examples/SecurityUtil.java#L17

package com.sgy.activitispringbootdemo.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.context.SecurityContextImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import java.util.Collection;

@Component
public class SecurityUtil {
    private Logger logger = LoggerFactory.getLogger(SecurityUtil.class);

    @Autowired
    @Qualifier("myUserDetailsService")
    private UserDetailsService userDetailsService;

    public void logInAs(String username) {

        UserDetails user = userDetailsService.loadUserByUsername(username);
        if (user == null) {
            throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
        }
        logger.info("> Logged in as: " + 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);
    }
}

怎么使用呢? 下面给出一个简单示例:

@Autowired
private SecurityUtil securityUtil;

public void test(){
	securityUtil.logInAs("yutao");
}

总结

  1. 整合的本质,就是要让Spring容器,认识并可以管理第三方框架(这里就是activiti7框架);所以配置文件是关键。
  2. activiti和springboot整合时,需要告诉springsecurity去哪里可以获取到用户。

未解决的问题:

  • Intellij IDEA 2020+的版本,activiti7没办法画bpmn图。

参考地址:

https://www.bilibili.com/video/BV1H54y167gf?p=105&spm_id_from=pageDriver

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值