整合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 }
运行结果
执行流程分析
下面我们一起来分析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 #开启历史信息
将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 }
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 }
启动工程
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 }
执行查询流程定义操作
执行启动流程示例
执行获取任务,拾取任务,并且执行操作