Activiti7之整合spring和spring boot

整合spring

通过 org.activiti.spring.SpringProcessEngineConfiguration Spring 整合方式来创建ProcessEngine 对象。

1.导入依赖

jdk的版本是1.8

junit的版本必须是4.12以上

  1 <dependencies>
  2     <dependency>
  3       <groupId>org.activiti</groupId>
  4       <artifactId>activiti-engine</artifactId>
  5       <version>7.0.0.Beta1</version>
  6     </dependency>
  7 
  8     <dependency>
  9       <groupId>org.activiti</groupId>
 10       <artifactId>activiti-bpmn-model</artifactId>
 11       <version>7.0.0.Beta1</version>
 12     </dependency>
 13 
 14     <dependency>
 15       <groupId>org.activiti</groupId>
 16       <artifactId>activiti-bpmn-converter</artifactId>
 17       <version>7.0.0.Beta1</version>
 18     </dependency>
 19 
 20     <dependency>
 21       <groupId>org.activiti</groupId>
 22       <artifactId>activiti-json-converter</artifactId>
 23       <version>7.0.0.Beta1</version>
 24     </dependency>
 25 
 26  <!--   <dependency>
 27       <groupId>org.activiti</groupId>
 28       <artifactId>activiti-bpmn-layout</artifactId>
 29       <version>7.0.0.Beta1</version>
 30     </dependency>-->
 31 
 32     <dependency>
 33       <groupId>org.activiti.cloud</groupId>
 34       <artifactId>activiti-cloud-services-api</artifactId>
 35       <version>7.0.0.Beta1</version>
 36     </dependency>
 37 
 38     <!--activiti和Spring整合依赖-->
 39     <dependency>
 40       <groupId>org.activiti</groupId>
 41       <artifactId>activiti-spring</artifactId>
 42       <version>7.0.0.Beta1</version>
 43     </dependency>
 44 
 45     <!--数据库依赖-->
 46     <dependency>
 47       <groupId>mysql</groupId>
 48       <artifactId>mysql-connector-java</artifactId>
 49       <version>5.1.38</version>
 50     </dependency>
 51 
 52 
 53     <!--单测依赖-->
 54     <dependency>
 55       <groupId>junit</groupId>
 56       <artifactId>junit</artifactId>
 57       <version>4.12</version>
 58     </dependency>
 59 
 60     <dependency>
 61       <groupId>org.springframework</groupId>
 62       <artifactId>spring-test</artifactId>
 63       <version>5.0.7.RELEASE</version>
 64     </dependency>
 65 
 66 
 67     <!-- log start -->
 68     <dependency>
 69       <groupId>log4j</groupId>
 70       <artifactId>log4j</artifactId>
 71       <version>${log4j.version}</version>
 72     </dependency>
 73     <dependency>
 74       <groupId>org.slf4j</groupId>
 75       <artifactId>slf4j-api</artifactId>
 76       <version>${slf4j.version}</version>
 77     </dependency>
 78     <dependency>
 79       <groupId>org.slf4j</groupId>
 80       <artifactId>slf4j-log4j12</artifactId>
 81       <version>${slf4j.version}</version>
 82     </dependency>
 83 
 84 
 85     <dependency>
 86       <groupId>org.mybatis</groupId>
 87       <artifactId>mybatis</artifactId>
 88       <version>3.4.5</version>
 89     </dependency>
 90 
 91 
 92     <!--数据源-->
 93     <dependency>
 94       <groupId>commons-dbcp</groupId>
 95       <artifactId>commons-dbcp</artifactId>
 96       <version>1.4</version>
 97     </dependency>
 98 
 99     <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
100     <dependency>
101       <groupId>commons-io</groupId>
102       <artifactId>commons-io</artifactId>
103       <version>2.4</version>
104     </dependency>
105 
106   </dependencies>
107   <repositories>
108     <repository>
109       <id>alfresco</id>
110       <name>Activiti Releases</name>
111       <url>https://artifacts.alfresco.com/nexus/content/repositories/activiti-releases/</url>
112       <releases>
113         <enabled>true</enabled>
114       </releases>
115     </repository>
116   </repositories>
依赖

2.配置Activiti

 1 配置内容:1.数据源         2.配置processEngine对象        3.配置XXXXService
 2                 <!--数据源-->
 3                 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
 4                     <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
 5                     <property name="url" value="jdbc:mysql://localhost:3306/activiti-y2170"/>
 6                     <property name="username" value="root"/>
 7                     <property name="password" value="root"/>
 8                 </bean>
 9 
10                 <!--配置ProcessEngineConfiguration-->
11                 <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
12                     <!--数据源-->
13                     <property name="dataSource" ref="dataSource"/>
14                     <!--配置事务-->
15                     <property name="transactionManager" ref="transactionManager"/>
16                     <!--数据生成策略    true   false   create   drop-create -->
17                     <property name="databaseSchemaUpdate" value="true"/>
18                 </bean>
19 
20                 <!--配置ProcessEngine-->
21                 <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
22                     <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
23                 </bean>
24 
25                 <!--配置RepositoryService-->
26                 <bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
27                 <!--配置RuntimeService-->
28                 <bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
29                 <!--配置TaskService-->
30                 <bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
31                 <!--配置HistoryService-->
32                 <bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
33                 
34                 <!--配置事务管理器-->
35                 <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
36                     <property name="dataSource" ref="dataSource"/>
37                 </bean>
配置

3.测试

 1 package com.wish;
 2 
 3 import static org.junit.Assert.assertTrue;
 4 
 5 import org.activiti.engine.RepositoryService;
 6 import org.junit.Test;
 7 import org.junit.runner.RunWith;
 8 import org.springframework.test.context.ContextConfiguration;
 9 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
10 
11 import javax.annotation.Resource;
12 
13 /**
14  * Unit test for simple App.
15  */
16 @RunWith(SpringJUnit4ClassRunner.class)     //测试方式  junit4.12+
17 @ContextConfiguration("classpath:springActibiti.xml")   //配置
18 public class AppTest 
19 {
20     @Resource
21     private RepositoryService repositoryService;
22     @Test
23     public void shouldAnswerWithTrue()
24     {
25         System.out.println("部署对象:"+repositoryService);
26     }
27 }
测试

运行结果:接下来就可以部署了

使用RepositoryService 进行部署

 1    /**
 2      * 测试流程部署
 3      */
 4     @Test
 5     public void deployment(){
 6         repositoryService.createDeployment()
 7                 .addClasspathResource("flowchart/process.bpmn")
 8                 .name("测试Spring流程部署")
 9                 .deploy();
10     }
repositoryService部署

运行结果

 

执行流程分析

下面我们一起来分析Activiti 与Spring 整合加载的过程。如下图所示:

从图中我们可以看出,首先我们加载 activiti-spring.xml 配置文件,而该配置文件中又会加载SpringProcessEngineConfiguration 对 象 ,

这 个 对 象 它 需 要 依 赖 注 入 dataSource 对 象 和transactionManager 对象。

其次会加载ProcessEngineFactoryBean 工厂来创建ProcessEngine 对象,而ProcessEngineFactoryBean 工厂又需要 依赖注 入 processEngineConfiguration 对 象。

最后 由processEngine 对象来负责创建我们的 Service 对象,从而简化 Activiti 的开发过程。在程序代码中我们可以根据实际需求来决定使用的Service 对象。

 

Activiti7的新特性

Activiti7的GitHub官方网站:https://github.com/Activiti/activiti-7-developers-guide/blob/51a1681c0e4bb5e2f96a6dea73516c9fd53 d8521/getting-started/getting-started-activiti-core.md

下载 Activiti-Core 的Example 示例:https://github.com/Activiti/activiti-examples

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

具体要学习的包括:

ProcessRuntime 接口TaskRuntime 接口

ProcessRuntime 接口

通过上面的分析,我们发现使用 Activiti7 开发时,只要注入ProcessRuntime 的实现对象,就可以实现流程定义信息的操作。

当然这个过程中因为 Activiti7 与SpringSecurity 的强耦合,引导我们也必须将SpringSecurity 加入进来。

TaskRuntime 接口

 

上面部分给我们介绍了如何引入Activiti Core 所需的坐标,同时介绍了如何添加 TaskRuntime 实现对象,源码介绍等。我们会发现TaskRuntime 本身就是对于TaskService 的一个封装。

SpringBoot整合Activiti7

 导入依赖

 1    <parent>
 2         <groupId>org.springframework.boot</groupId>
 3         <artifactId>spring-boot-starter-parent</artifactId>
 4         <version>2.1.4.RELEASE</version>
 5     </parent>
 6 
 7 
 8 <dependency>
 9             <groupId>org.springframework.boot</groupId>
10             <artifactId>spring-boot-starter-jdbc</artifactId>
11         </dependency>
12         <dependency>
13             <groupId>org.springframework.boot</groupId>
14             <artifactId>spring-boot-starter-web</artifactId>
15         </dependency>
16         <dependency>
17             <groupId>org.springframework.boot</groupId>
18             <artifactId>spring-boot-starter-test</artifactId>
19             <scope>test</scope>
20         </dependency>
21         <!-- https://mvnrepository.com/artifact/org.activiti/activiti-spring-boot-starter -->
22         <dependency>
23             <groupId>org.activiti</groupId>
24             <artifactId>activiti-spring-boot-starter</artifactId>
25             <version>7.0.0.Beta2</version>
26         </dependency>
27         <dependency>
28             <groupId>org.mybatis</groupId>
29             <artifactId>mybatis</artifactId>
30             <version>3.4.5</version>
31         </dependency>
32         <dependency>
33             <groupId>mysql</groupId>
34             <artifactId>mysql-connector-java</artifactId>
35             <version>5.1.38</version>
36         </dependency>
依赖

配置application.yml

1 spring:
2   datasource:
3     url: jdbc:mysql://localhost:3306/activiti-wn?useUnicode=true&characterEncoding=utf8&serverT imezone=GMT
4     username : root
5     password : 123456
6     driver-class-name: com.mysql.jdbc.Driver
7   activiti:
8     db-history-used: true   #开启历史信息
配置application.yml

将SpringSecurity配置添加到项目当中

SecurityUtil关于权限登陆

 1 package com.wish.activiti;
 2 
 3 import org.springframework.beans.factory.annotation.Autowired;
 4 import org.springframework.security.core.Authentication;
 5 import org.springframework.security.core.GrantedAuthority;
 6 import org.springframework.security.core.context.SecurityContextHolder;
 7 import org.springframework.security.core.context.SecurityContextImpl;
 8 import org.springframework.security.core.userdetails.UserDetails;
 9 import org.springframework.security.core.userdetails.UserDetailsService;
10 import org.springframework.stereotype.Component;
11 
12 import java.util.Collection;
13 
14 @Component
15 public class SecurityUtil {
16 
17     @Autowired
18     private UserDetailsService userDetailsService;
19 
20     public void logInAs(String username) {
21 
22          UserDetails user = userDetailsService.loadUserByUsername(username);
23         if (user == null) {
24             throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
25         }
26 
27         SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
28             @Override
29             public Collection<? extends GrantedAuthority> getAuthorities() {
30                 return user.getAuthorities();
31             }
32 
33             @Override
34             public Object getCredentials() {
35                 return user.getPassword();
36             }
37 
38             @Override
39             public Object getDetails() {
40                 return user;
41             }
42 
43             @Override
44             public Object getPrincipal() {
45                 return user;
46             }
47 
48             @Override
49             public boolean isAuthenticated() {
50                 return true;
51             }
52 
53             @Override
54             public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
55 
56             }
57 
58             @Override
59             public String getName() {
60                 return user.getUsername();
61             }
62         }));
63         org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
64     }
65 }
SecurityUtil

DemoApplicationConfiguration 关于权限配置

 1 /*
 2  * Copyright 2018 Alfresco, Inc. and/or its affiliates.
 3  *
 4  * Licensed under the Apache License, Version 2.0 (the "License");
 5  * you may not use this file except in compliance with the License.
 6  * You may obtain a copy of the License at
 7  *
 8  *       http://www.apache.org/licenses/LICENSE-2.0
 9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.wish.activiti;
18 
19 import org.slf4j.Logger;
20 import org.slf4j.LoggerFactory;
21 import org.springframework.beans.factory.annotation.Autowired;
22 import org.springframework.context.annotation.Bean;
23 import org.springframework.context.annotation.Configuration;
24 import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
25 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
26 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
27 import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
28 import org.springframework.security.core.authority.SimpleGrantedAuthority;
29 import org.springframework.security.core.userdetails.User;
30 import org.springframework.security.core.userdetails.UserDetailsService;
31 import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
32 import org.springframework.security.crypto.password.PasswordEncoder;
33 import org.springframework.security.provisioning.InMemoryUserDetailsManager;
34 import java.util.Arrays;
35 import java.util.List;
36 import java.util.stream.Collectors;
37 
38 @Configuration
39 @EnableWebSecurity
40 public class DemoApplicationConfiguration extends WebSecurityConfigurerAdapter {
41 
42     private Logger logger = LoggerFactory.getLogger(DemoApplicationConfiguration.class);
43 
44     @Override
45     @Autowired
46     public void configure(AuthenticationManagerBuilder auth) throws Exception {
47         auth.userDetailsService(myUserDetailsService());
48     }
49 
50     @Bean
51     public UserDetailsService myUserDetailsService() {
52 
53         InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
54 
55         String[][] usersGroupsAndRoles = {
56                 {"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
57                 {"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
58                 {"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
59                 {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
60                 {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
61         };
62 
63         for (String[] user : usersGroupsAndRoles) {
64             List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
65             logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
66             inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
67                     authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
68         }
69 
70 
71         return inMemoryUserDetailsManager;
72     }
73 
74 
75     @Override
76     protected void configure(HttpSecurity http) throws Exception {
77         http
78                 .csrf().disable()
79                 .authorizeRequests()
80                 .anyRequest()
81                 .authenticated()
82                 .and()
83                 .httpBasic();
84 
85 
86     }
87 
88     @Bean
89     public PasswordEncoder passwordEncoder() {
90         return new BCryptPasswordEncoder();
91     }
92 }
DemoApplicationConfiguration

启动工程

 1 package com.wish;
 2 
 3 import org.springframework.boot.SpringApplication;
 4 import org.springframework.boot.autoconfigure.SpringBootApplication;
 5 
 6 @SpringBootApplication
 7 public class StartActiviti {
 8     public static void main(String[] args) {
 9         SpringApplication.run(StartActiviti.class,args);
10     }
11 }
启动项目

运行成功,数据库创建表

注意问题:
1.Activiti7和SpringSecurity耦合,需要加入SpringSecurity的依赖和配置,我们可以使用Security中的用户角色组定义流程执行的组
2.流程默认可自动部署,但是需要再resources/processes文件夹,将流程文件放入当中
3.默认历史表不会生成,需要手动开启配置

执行流程

 1 package com.wish.controller;
 2 
 3 
 4 import com.wish.activiti.SecurityUtil;
 5 import org.activiti.api.process.model.ProcessDefinition;
 6 import org.activiti.api.process.model.ProcessInstance;
 7 import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
 8 import org.activiti.api.process.runtime.ProcessRuntime;
 9 import org.activiti.api.runtime.shared.query.Page;
10 import org.activiti.api.runtime.shared.query.Pageable;
11 import org.activiti.api.task.model.Task;
12 import org.activiti.api.task.model.builders.TaskPayloadBuilder;
13 import org.activiti.api.task.runtime.TaskRuntime;
14 import org.springframework.web.bind.annotation.RequestMapping;
15 import org.springframework.web.bind.annotation.RestController;
16 
17 import javax.annotation.Resource;
18 
19 @RestController
20 @RequestMapping("/activiti")
21 public class ActivitiController {
22     @Resource
23     private ProcessRuntime processRuntime;
24     @Resource
25     private TaskRuntime taskRuntime;
26     @Resource
27     private SecurityUtil securityUtil;
28     /**
29      * 查询流程定义
30      */
31     @RequestMapping("/getProcess")
32     public void getProcess(){
33         //查询所有流程定义信息
34         Page<ProcessDefinition> processDefinitionPage = processRuntime.processDefinitions(Pageable.of(0, 10));
35         System.out.println("当前流程定义的数量:"+processDefinitionPage.getTotalItems());
36         //获取流程信息
37         for (ProcessDefinition processDefinition:processDefinitionPage.getContent()) {
38             System.out.println("流程定义信息"+processDefinition);
39         }
40     }
41 
42     /**
43      * 启动流程示例
44      */
45     @RequestMapping("/startInstance")
46     public void startInstance(){
47         ProcessInstance instance = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("demo").build());
48         System.out.println(instance.getId());
49     }
50 
51     /**
52      * 获取任务,拾取任务,并且执行
53      */
54     @RequestMapping("/getTask")
55     public void getTask(){
56         securityUtil.logInAs("salaboy");        //指定组内任务人
57         Page<Task> tasks = taskRuntime.tasks(Pageable.of(0, 10));
58         if(tasks.getTotalItems()>0){
59             for (Task task:tasks.getContent()) {
60                 System.out.println("任务名称:"+task.getName());
61                 //拾取任务
62                 taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(task.getId()).build());
63                 //执行任务
64                 taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(task.getId()).build());
65             }
66         }
67     }
68 }
执行流程

执行查询流程定义操作

 

执行启动流程示例

执行获取任务,拾取任务,并且执行操作

原文地址:https://www.cnblogs.com/wishsaber/p/12669702.html