栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > .Net

工作流引擎之十一 activiti7新特性

.Net 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

工作流引擎之十一 activiti7新特性

目录

一,Activiti7 基本介绍

二,下载Activit 官网demo 学习

2.1 进入 Activiti-Core 学习向导页面

2.2 下载 Activiti-Core 的 demo 示例 

2.3 Activiti7 面临的挑战

2.4 Activiti7 的组成部分 

 2.5 Activiti 新的 API 介绍

        2.5.1 TaskRuntime

2.5.2 ProcessRuntime

三,Activiti7 与 SpringBoot 整合开发 

3.1 SpringBoot 整合 Activiti7 的 配置

       3.1.1  引入依赖

        3.1.2 配置文件

3.2 添加SpringSecurity 安全框架整合配置

3.2.1 添加 SecurityUtil 类

3.2.2 添加 DemoApplicationConfig 类

3.2.3 启动类

3.3 使用 SpringBoot 整合 Junit 方式测试新特性

3.4 查看流程定义信息

3.5 启动流程实例

3.6 查询并完成任务 

四,Activiti7+ SpringBoot+SpringMVC 开发

4.1添加 Controller 类


一,Activiti7 基本介绍

Alfresco 软件在 2010 年 5 月 17 日宣布 Activiti 业务流程管理(BPM)开源项目的正式启动,其 首席架构师由业务流程管理 BPM 的专家 Tom Baeyens 担任,Tom Baeyens 就是原来 jbpm 的架构师, 而 jbpm 是一个非常有名的工作流引擎,当然 activiti 也是一个工作流引擎。 Activiti 是一个工作流引擎, activiti 可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言(BPMN2.0)进行定义,业务系统按照预先定义的流程进行执行,实现了业务系统的业务 流程由 activiti 进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的 健壮性,同时也减少了系统开发维护成本。

官方网站:https://www.activiti.org/

版本有:5.x,6.x,7.x

二,下载Activit 官网demo 学习

Activiti7 分为core,cloud两类,我们主要学习core 的内容。

2.1 进入 Activiti-Core 学习向导页面

                activiti-7-developers-guide/getting-started-activiti-core.md at 51a1681c0e4bb5e2f96a6dea73516c9fd53d8521 · Activiti/activiti-7-developers-guide · GitHubhttps://activiti.gitbook.io/activiti-7-developers-guide/ - activiti-7-developers-guide/getting-started-activiti-core.md at 51a1681c0e4bb5e2f96a6dea73516c9fd53d8521 · Activiti/activiti-7-developers-guidehttps://github.com/Activiti/activiti-7-developers-guide/blob/51a1681c0e4bb5e2f96a6dea73516c9fd53d8521/getting-started/getting-started-activiti-core.md

2.2 下载 Activiti-Core 的 demo 示例 

GitHub - AlfrescoArchive/activiti-examples: This repository contains Activiti 7.x Examples

2.3 Activiti7 面临的挑战

        Tom Baeyens 离职,并带着原班 Activiti 开发者又开发了一版新的工作流引擎,叫 flowable。这对于 Activiti 阵营而言是一个不少的挑战。我们现在所学的 Activiti7 是另一个架构师在原有的 Activiti6 基 础上再进行一层封装,所以 API 有着很大的改变。 

2.4 Activiti7 的组成部分 

从这个部分我们可以看到 Activiti 现在已经分成两个不同的部分,Activiti Core 作为 Activiti 的核心部分,本次我们重点解决。另一部分 Activiti Cloud 主要是利用云服务来实现分布式业务流程开发。 

 2.5 Activiti 新的 API 介绍

        Activiti7 为了简化对工作流的操作,特别在原有 API 的基础上再次进行封闭,这样我们原来所学习 的 Activiti 基本 API 就被封闭起来了。具体要学习的包括: ProcessRuntime 接口 TaskRuntime 接口

        2.5.1 TaskRuntime

        下面这个链接是 新API的教材地址

Getting Started - Activiti Core - Activiti & Activiti Cloud Developers Guide

public interface TaskRuntime {
  TaskRuntimeConfiguration configuration();
  Task task(String taskId);
  Page tasks(Pageable pageable);
  Page tasks(Pageable pageable, GetTasksPayload payload);
  Task create(CreateTaskPayload payload);
  Task claim(ClaimTaskPayload payload);
  Task release(ReleaseTaskPayload payload);
  Task complete(CompleteTaskPayload payload);
  Task update(UpdateTaskPayload payload);
  Task delete(DeleteTaskPayload payload);
  ...
}

创建任务

taskRuntime.create(
            TaskPayloadBuilder.create()
                .withName("First Team Task")
                .withDescription("This is something really important")
                .withGroup("activitiTeam")
                .withPriority(10)
           .build());

2.5.2 ProcessRuntime
public interface ProcessRuntime {
  ProcessRuntimeConfiguration configuration();
  ProcessDefinition processDefinition(String processDefinitionId);
  Page processDefinitions(Pageable pageable);
  Page processDefinitions(Pageable pageable,
              GetProcessDefinitionsPayload payload);
  ProcessInstance start(StartProcessPayload payload);
  Page processInstances(Pageable pageable);
  Page processInstances(Pageable pageable,
              GetProcessInstancesPayload payload);
  ProcessInstance processInstance(String processInstanceId);
  ProcessInstance suspend(SuspendProcessPayload payload);
  ProcessInstance resume(ResumeProcessPayload payload);
  ProcessInstance delete(DeleteProcessPayload payload);
  void signal(SignalPayload payload);
  ...
}

获取这两个类,直接@Autowried 就好

        查询流程定义

Page processDefinitionPage = processRuntime
                                .processDefinitions(Pageable.of(0, 10));
logger.info("> Available Process definitions: " +
                  processDefinitionPage.getTotalItems());
for (ProcessDefinition pd : processDefinitionPage.getContent()) {
  logger.info("t > Process definition: " + pd);
}

1,因为activiti7 和springSecurity 进行了强耦合,所以在进行activiti 增删改查的时候都要做权限验证

2,流程定义需要放在 /src/main/resources/processes/

三,Activiti7 与 SpringBoot 整合开发 

Activiti7 发布正式版之后,它与 SpringBoot2.x 已经完全支持整合开发。我们可以将 Activiti7 与 SpringBoot 整合开发的坐标引入到工程中,从而达到 SpringBoot 支持 Activti7 整合。

SpringBoot 整合 Activti7 的具体步骤如下:

1.添加 SpringBoot 整合 Activti7 的坐标

2.添加 SpringSecurity 安全框架的整合配置信息

3.使用 Activti7 新支持的类来实现工作流开发 ProcessRuntime 接口 TaskRuntime 接口

4.使用新的 API 实现工作流开发,主要包括

        流程定义查询

        启动流程实例

        任务的查询

        任务的完成

3.1 SpringBoot 整合 Activiti7 的 配置

       3.1.1  引入依赖


    4.0.0

    org.example
    springBoot_Activiti7New
    1.0-SNAPSHOT


    
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.0.RELEASE
         
    

    
        UTF-8
        UTF-8
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-jdbc
        
        
            mysql
            mysql-connector-java
        
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        

        
        
            org.activiti
            activiti-spring-boot-starter
            7.1.0.M6
        

        
            org.mybatis
            mybatis
            3.4.5
        
        
            mysql
            mysql-connector-java
            8.0.21
        


    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

        3.1.2 配置文件
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT
    username : root
    password : root
    driver-class-name: com.mysql.jdbc.Driver
  activiti:
    database-schema-update: true
    history-level: full
    db-history-used: true

Activiti7与SpringBoot整合时,默认生成的activiti数据库中只有17张表,无另外8张历史表。

Activiti默认关闭了历史表的使用。

在连接数据库的application.yml配置文件中,开启即可,配置文件内容如下。

3.2 添加SpringSecurity 安全框架整合配置

因为 Activiti7 与 SpringBoot 整合后,默认情况下,集成了 SpringSecurity 安全框架,这样我们就要去 准备 SpringSecurity 整合进来的相关用户权限配置信息。

可以查看一下整合 SpringBoot 的依赖包,发现同时也将 SpringSecurity 的依赖包也添加进项目中了,

3.2.1 添加 SecurityUtil 类

添加 SecurityUtil 类。 为了能够快速实现 SpringSecurity 安全框架的配置,所添加的一个组件。

import org.springframework.beans.factory.annotation.Autowired;
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 {

    @Autowired
    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");
        }

        SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
            @Override
            public Collection 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);
    }
}

3.2.2 添加 DemoApplicationConfig 类

在 Activiti7 官方下载的 Example 中找到 DemoApplicationConfig 类,它的作用是为了实现 SpringSecurity 框架的用户权限的配置,这样我们就可以在系统中使用用户权限信息。本次项目中基 本是在文件中定义出来的用户信息,当然也可以是数据库中查询的用户权限信息。



import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
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
@EnableWebSecurity
public class DemoApplicationConfiguration extends WebSecurityConfigurerAdapter {

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

    @Override
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService());
    }

    @Bean
    public UserDetailsService myUserDetailsService() {

        InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();

        String[][] usersGroupsAndRoles = {
                {"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 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;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .authorizeRequests()
                .anyRequest()
                .authenticated()
                .and()
                .httpBasic();


    }

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

3.2.3 启动类
import org.activiti.api.process.runtime.connector.Connector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
import org.springframework.context.annotation.Bean;

@SpringBootApplication(exclude = SecurityAutoConfiguration.class)
public class Actviti7DemoApplication {
	private Logger logger = LoggerFactory.getLogger(Actviti7DemoApplication.class);



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

	@Bean
	public Connector testConnector() {
		return integrationContext -> {
			logger.info("以前叫代理,现在叫连接器被调用啦~~");
			return integrationContext;
		};
	}
}

3.3 使用 SpringBoot 整合 Junit 方式测试新特性

3.4 查看流程定义信息
@RunWith(SpringRunner.class)
@SpringBootTest
public class ActivitiDemoApplicationTests {

    @Autowired
    private ProcessRuntime processRuntime;

    @Autowired
    private TaskRuntime taskRuntime;

    @Autowired
    private SecurityUtil securityUtil;

    
    @Test
    public void contextLoads(){
        securityUtil.logInAs("system");
        Page processDefinitionPage =processRuntime.processDefinitions(Pageable.of(0, 10));
        System.out.println("可用的流程定义数量:" +processDefinitionPage.getTotalItems());
        for (org.activiti.api.process.model.ProcessDefinition pd :
                processDefinitionPage.getContent()) {
            System.out.println("流程定义:" + pd);
        }
    }
}

        通过 ProcessRuntime 的方法,我们可以查看已经部署的流程定义信息。通过加入 Pageable.of()方法可 以实现分页查询效果。

3.5 启动流程实例
    
    @Test
    public void testStartProcess() {
        securityUtil.logInAs("system");
        ProcessInstance pi = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("myProcess").build());
        System.out.println("流程实例 ID:" + pi.getId());
    }

现在要启动流程实例,我们可以使用 ProcessRuntime 的 start()方法就可以实现流程实例的启动

3.6 查询并完成任务 
    
    @Test
    public void testTask() {
        securityUtil.logInAs("ryandawsonuk");
        Page taskPage=taskRuntime.tasks(Pageable.of(0,10));
        if (taskPage.getTotalItems()>0){
            for (Task task:taskPage.getContent()){

                taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());
                System.out.println("任务:"+task);
                taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build()
                );
            }
        }
        Page taskPage2=taskRuntime.tasks(Pageable.of(0,10));
        if (taskPage2.getTotalItems()>0){
            System.out.println("任务:"+taskPage2.getContent());
        }
    }

使用 TaskRuntime 接口的 tasks()方法实现任务的查询。

使用 TaskRuntime 接口的 claim()方法实现任务拾取。

使用 TaskRuntime 接口的 complete()方法实现任务的完成

四,Activiti7+ SpringBoot+SpringMVC 开发

4.1添加 Controller 类
import org.activiti.api.process.model.ProcessDefinition;
import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
import org.activiti.api.process.runtime.ProcessRuntime;
import org.activiti.api.runtime.shared.query.Page;
import org.activiti.api.runtime.shared.query.Pageable;
import org.activiti.api.task.model.Task;
import org.activiti.api.task.model.builders.TaskPayloadBuilder;
import org.activiti.api.task.runtime.TaskRuntime;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.logging.Logger;

@RestController
public class TestController {
    private Logger logger = (Logger) LoggerFactory.getLogger(TestController.class);
    @Autowired
    private ProcessRuntime processRuntime;
    @Autowired
    private TaskRuntime taskRuntime;
    @Autowired
    private SecurityUtil securityUtil;

    @RequestMapping(value = "/hello")
    public void hello() {
        //首先,取出项目中的最多 10 个流程定义
        Page processDefinitionPage =
                processRuntime.processDefinitions(Pageable.of(0, 10));
        if (processDefinitionPage.getTotalItems() > 0) {
            //然后,对取出的流程进行启动
            for (ProcessDefinition definition : processDefinitionPage.getContent()) {
                logger.info("流程定义信息:" + definition);

                processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionId(definition.getId()).build());
            }
        }
        //完成 流程启动后, 由于当前项目中 只有 other.bpmn 一个流程,且该流程在设计时,已分配给activitiTeam 组
        //因此我们登录一个activitiTeam组成员,该账号信息会被设置到security上下文中,activiti会对其信息进行读取
        //获取当前用户任务,最多 10 个
        Page taskPage = taskRuntime.tasks(Pageable.of(0, 10));
        //由于目前只有一个流程,两个任务,我们尝试一下完成一个,看看会发生什么变化
        if (taskPage.getTotalItems() > 0) {
            for (Task task : taskPage.getContent()) {
                logger.info("任务信息:" + task);
                //注意,完成任务前必须先声明

                taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());
                //完成任务

                taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build()
                );
            }
        }
        //上一轮任务完成,再看一下,现在流程是否走到了 second?
        Page taskPage2 = taskRuntime.tasks(Pageable.of(0, 10));
        if (taskPage2.getTotalItems() > 0) {
            logger.info("任务信息:" + taskPage2.getContent());
        }
    }
}

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983404.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号