1 Activiti和Spring整合开发

1.1 Activiti和Spring整合的配置

  • 导入相关jar包的Maven坐标:
  1. <properties>
  2. <activiti.version>7.0.0.GA</activiti.version>
  3. </properties>
  4. <dependencies>
  5. <dependency>
  6. <groupId>org.activiti</groupId>
  7. <artifactId>activiti-engine</artifactId>
  8. <version>7.0.0.GA</version>
  9. </dependency>
  10. <dependency>
  11. <groupId>org.activiti</groupId>
  12. <artifactId>activiti-spring</artifactId>
  13. <version>${activiti.version}</version>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework</groupId>
  17. <artifactId>spring-test</artifactId>
  18. <version>5.1.4.RELEASE</version>
  19. </dependency>
  20. <dependency>
  21. <groupId>org.activiti</groupId>
  22. <artifactId>activiti-bpmn-model</artifactId>
  23. <version>${activiti.version}</version>
  24. </dependency>
  25. <dependency>
  26. <groupId>org.activiti</groupId>
  27. <artifactId>activiti-bpmn-converter</artifactId>
  28. <version>${activiti.version}</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.activiti</groupId>
  32. <artifactId>activiti-json-converter</artifactId>
  33. <version>${activiti.version}</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.activiti</groupId>
  37. <artifactId>activiti-bpmn-layout</artifactId>
  38. <version>${activiti.version}</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.activiti.cloud</groupId>
  42. <artifactId>activiti-cloud-services-api</artifactId>
  43. <version>7-201802-EA</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>mysql</groupId>
  47. <artifactId>mysql-connector-java</artifactId>
  48. <version>8.0.19</version>
  49. </dependency>
  50. <dependency>
  51. <groupId>junit</groupId>
  52. <artifactId>junit</artifactId>
  53. <version>4.12</version>
  54. </dependency>
  55. <!-- log start -->
  56. <dependency>
  57. <groupId>org.apache.logging.log4j</groupId>
  58. <artifactId>log4j-core</artifactId>
  59. <version>2.13.3</version>
  60. </dependency>
  61. <dependency>
  62. <groupId>org.apache.logging.log4j</groupId>
  63. <artifactId>log4j-api</artifactId>
  64. <version>2.13.3</version>
  65. </dependency>
  66. <dependency>
  67. <groupId>org.slf4j</groupId>
  68. <artifactId>slf4j-api</artifactId>
  69. <version>1.7.30</version>
  70. </dependency>
  71. <dependency>
  72. <groupId>org.apache.logging.log4j</groupId>
  73. <artifactId>log4j-slf4j-impl</artifactId>
  74. <version>2.13.3</version>
  75. </dependency>
  76. <!-- log end -->
  77. <dependency>
  78. <groupId>org.mybatis</groupId>
  79. <artifactId>mybatis</artifactId>
  80. <version>3.4.5</version>
  81. </dependency>
  82. <dependency>
  83. <groupId>commons-dbcp</groupId>
  84. <artifactId>commons-dbcp</artifactId>
  85. <version>1.4</version>
  86. </dependency>
  87. </dependencies>
  88. <dependencyManagement>
  89. <dependencies>
  90. <dependency>
  91. <groupId>org.activiti.cloud.dependencies</groupId>
  92. <artifactId>activiti-cloud-dependencies</artifactId>
  93. <version>7.0.0.GA</version>
  94. <scope>import</scope>
  95. <type>pom</type>
  96. </dependency>
  97. </dependencies>
  98. </dependencyManagement>
  • 创建Spring和Activiti的整合配置文件activiti-spring.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xmlns:context="http://www.springframework.org/schema/context"
  4. xmlns="http://www.springframework.org/schema/beans"
  5. xsi:schemaLocation="http://www.springframework.org/schema/beans
  6. http://www.springframework.org/schema/beans/spring-beans.xsd
  7. http://www.springframework.org/schema/context
  8. http://www.springframework.org/schema/context/spring-context.xsd">
  9. <!-- 配置数据源 -->
  10. <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
  11. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
  12. <property name="username" value="root"/>
  13. <property name="url"
  14. value="jdbc:mysql://192.168.1.146:3306/activiti?useUnicode=true&amp;characterEncoding=UTF-8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=GMT%2B8&amp;allowPublicKeyRetrieval=true"/>
  15. <property name="password" value="123456"/>
  16. <property name="maxActive" value="3"/>
  17. <property name="maxIdle" value="1"/>
  18. </bean>
  19. <!-- 配置事务管理器 -->
  20. <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
  21. <property name="dataSource" ref="dataSource"/>
  22. </bean>
  23. <!-- 工作流引擎配置Bean -->
  24. <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
  25. <!-- 数据源 -->
  26. <property name="dataSource" ref="dataSource"/>
  27. <!-- 使用Spring的事务管理器 -->
  28. <property name="transactionManager" ref="transactionManager"/>
  29. <!-- 数据库的策略 -->
  30. <property name="databaseSchemaUpdate" value="true"/>
  31. </bean>
  32. <!-- 流程引擎 -->
  33. <bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
  34. <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
  35. </bean>
  36. <!-- 资源服务service -->
  37. <bean id="repositoryService" factory-bean="processEngine"
  38. factory-method="getRepositoryService"/>
  39. <!-- 流程运行service -->
  40. <bean id="runtimeService" factory-bean="processEngine"
  41. factory-method="getRuntimeService"/>
  42. <!-- 任务管理service -->
  43. <bean id="taskService" factory-bean="processEngine"
  44. factory-method="getTaskService"/>
  45. <!-- 历史管理service -->
  46. <bean id="historyService" factory-bean="processEngine"
  47. factory-method="getHistoryService"/>
  48. </beans>
  • 创建日志文件log4j2.xml
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!--日志级别以及优先级排序: OFF > FATAL > ERROR > WARN > INFO > DEBUG > TRACE > ALL -->
  3. <!--Configuration后面的status用于设置log4j2自身内部的信息输出,可以不设置,当设置成trace时,可以看到log4j2内部各种详细输出-->
  4. <configuration status="INFO">
  5. <!--先定义所有的appender-->
  6. <appenders>
  7. <!--输出日志信息到控制台-->
  8. <console name="Console" target="SYSTEM_OUT">
  9. <!--控制日志输出的格式-->
  10. <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n"/>
  11. </console>
  12. </appenders>
  13. <!--然后定义logger,只有定义了logger并引入的appender,appender才会生效-->
  14. <!--root:用于指定项目的根日志,如果没有单独指定Logger,则会使用root作为默认的日志输出-->
  15. <loggers>
  16. <root level="INFO">
  17. <appender-ref ref="Console"/>
  18. </root>
  19. </loggers>
  20. </configuration>

1.2 测试Activiti和Spring的整合

  • 测试:
  1. package com.sunxiaping.test;
  2. import org.activiti.engine.RepositoryService;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.test.context.ContextConfiguration;
  7. import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
  8. /**
  9. * @author <a href="mailto:1900919313@qq.com">weiwei.xu</a>
  10. * @version 1.0
  11. * 2020-08-12 09:23
  12. */
  13. @RunWith(SpringJUnit4ClassRunner.class)
  14. @ContextConfiguration(locations={"classpath:activiti-spring.xml"})
  15. public class Activiti7Test {
  16. @Autowired
  17. private RepositoryService repositoryService;
  18. @Test
  19. public void test(){
  20. System.out.println("repositoryService = " + repositoryService);
  21. }
  22. }

2 Activiti7和SpringBoot的整合开发

2.1 概述

  • Activiti7发布正式版以后,它可以和SpringBoot2.x完全整合。我们可以将Activiti7和SpringBoot整合开发的坐标引入到工程中,从而达到SpringBoot支持Activiti7。
  • SpringBoot整合Activiti7的具体步骤如下:
    • Activiti7新特性和整合开发 - 图1添加SpringBoot整合Activiti7的jar包的坐标。
    • Activiti7新特性和整合开发 - 图2添加SpringSecurity安全框架的整合配置信息。
    • Activiti7新特性和整合开发 - 图3使用Activiti7新支持的接口(ProcessRuntime接口和TaskRuntime接口)来实现工作流开发。
    • Activiti7新特性和整合开发 - 图4使用新的API实现工作流的开发,主要包括:流程定义查询,启动流程实例,任务的查询,任务的完成。

2.2 Activiti和SpringBoot整合的配置

  • 导入相关jar包的坐标:
  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.2.9.RELEASE</version>
  5. <relativePath/>
  6. </parent>
  7. <dependencies>
  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. <dependency>
  22. <groupId>org.activiti</groupId>
  23. <artifactId>activiti-spring-boot-starter</artifactId>
  24. <version>7.0.0.GA</version>
  25. </dependency>
  26. <dependency>
  27. <groupId>org.mybatis.spring.boot</groupId>
  28. <artifactId>mybatis-spring-boot-starter</artifactId>
  29. <version>2.1.3</version>
  30. </dependency>
  31. <dependency>
  32. <groupId>mysql</groupId>
  33. <artifactId>mysql-connector-java</artifactId>
  34. </dependency>
  35. </dependencies>
  36. <build>
  37. <plugins>
  38. <plugin>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-maven-plugin</artifactId>
  41. <version>2.2.9.RELEASE</version>
  42. </plugin>
  43. </plugins>
  44. </build>
  • application.yml
  1. spring:
  2. datasource:
  3. url: jdbc:mysql://192.168.134.100:3306/activiti?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&useSSL=false&serverTimezone=GMT%2B8&allowPublicKeyRetrieval=true
  4. username : root
  5. password : 123456
  6. driver-class-name: com.mysql.cj.jdbc.Driver
  7. activiti:
  8. database-schema-update: true
  9. db-history-used: true
  10. history-level: full
  11. check-process-definitions: false
  12. async-executor-activate: true
  • 流程定义文件team01.bpmn

流程定义文件team01.bpmn.jpg

  • SpringSecurity的配置
  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. package com.sunxiaping.activiti7.config;
  17. import org.slf4j.Logger;
  18. import org.slf4j.LoggerFactory;
  19. import org.springframework.context.annotation.Bean;
  20. import org.springframework.context.annotation.Configuration;
  21. import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
  22. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  23. import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
  24. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  25. import org.springframework.security.core.authority.SimpleGrantedAuthority;
  26. import org.springframework.security.core.userdetails.User;
  27. import org.springframework.security.core.userdetails.UserDetailsService;
  28. import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
  29. import org.springframework.security.crypto.password.PasswordEncoder;
  30. import org.springframework.security.provisioning.InMemoryUserDetailsManager;
  31. import java.util.Arrays;
  32. import java.util.List;
  33. import java.util.stream.Collectors;
  34. /**
  35. * SpringSecurity的配置类
  36. */
  37. @Configuration
  38. @EnableWebSecurity
  39. public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
  40. private Logger logger = LoggerFactory.getLogger(SpringSecurityConfig.class);
  41. @Override
  42. public void configure(AuthenticationManagerBuilder auth) throws Exception {
  43. auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
  44. }
  45. @Bean
  46. public UserDetailsService userDetailsService() {
  47. InMemoryUserDetailsManager inMemoryUserDetailsManager = new InMemoryUserDetailsManager();
  48. String[][] usersGroupsAndRoles = {
  49. {"salaboy", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
  50. {"ryandawsonuk", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
  51. {"erdemedeiros", "password", "ROLE_ACTIVITI_USER", "GROUP_activitiTeam"},
  52. {"other", "password", "ROLE_ACTIVITI_USER", "GROUP_otherTeam"},
  53. {"admin", "password", "ROLE_ACTIVITI_ADMIN"},
  54. };
  55. for (String[] user : usersGroupsAndRoles) {
  56. List<String> authoritiesStrings = Arrays.asList(Arrays.copyOfRange(user, 2, user.length));
  57. logger.info("> Registering new user: " + user[0] + " with the following Authorities[" + authoritiesStrings + "]");
  58. inMemoryUserDetailsManager.createUser(new User(user[0], passwordEncoder().encode(user[1]),
  59. authoritiesStrings.stream().map(s -> new SimpleGrantedAuthority(s)).collect(Collectors.toList())));
  60. }
  61. return inMemoryUserDetailsManager;
  62. }
  63. @Override
  64. protected void configure(HttpSecurity http) throws Exception {
  65. http.csrf().disable()
  66. .authorizeRequests()
  67. .anyRequest()
  68. .authenticated()
  69. .and()
  70. .httpBasic();
  71. }
  72. @Bean
  73. public PasswordEncoder passwordEncoder() {
  74. return new BCryptPasswordEncoder();
  75. }
  76. }
  • UserService.java
  1. package com.sunxiaping.activiti7.service;
  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.beans.factory.annotation.Qualifier;
  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. import java.util.Collection;
  12. @Component
  13. public class UserService {
  14. @Qualifier("userDetailsService")
  15. @Autowired
  16. private UserDetailsService userDetailsService;
  17. public void logInAs(String username) {
  18. UserDetails user = userDetailsService.loadUserByUsername(username);
  19. if (user == null) {
  20. throw new IllegalStateException("User " + username + " doesn't exist, please provide a valid user");
  21. }
  22. SecurityContextHolder.setContext(new SecurityContextImpl(new Authentication() {
  23. @Override
  24. public Collection<? extends GrantedAuthority> getAuthorities() {
  25. return user.getAuthorities();
  26. }
  27. @Override
  28. public Object getCredentials() {
  29. return user.getPassword();
  30. }
  31. @Override
  32. public Object getDetails() {
  33. return user;
  34. }
  35. @Override
  36. public Object getPrincipal() {
  37. return user;
  38. }
  39. @Override
  40. public boolean isAuthenticated() {
  41. return true;
  42. }
  43. @Override
  44. public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
  45. }
  46. @Override
  47. public String getName() {
  48. return user.getUsername();
  49. }
  50. }));
  51. org.activiti.engine.impl.identity.Authentication.setAuthenticatedUserId(username);
  52. }
  53. }
  • SpringBoot的启动类:
  1. package com.sunxiaping.activiti7;
  2. import org.springframework.boot.SpringApplication;
  3. import org.springframework.boot.autoconfigure.SpringBootApplication;
  4. @SpringBootApplication
  5. public class Activiti7SpringBootApplication {
  6. public static void main(String[] args) {
  7. SpringApplication.run(Activiti7SpringBootApplication.class, args);
  8. }
  9. }

2.3 测试Activiti和SpringBoot的整合

  • 测试:
  1. package com.sunxiaping.activiti7;
  2. import com.sunxiaping.activiti7.service.UserService;
  3. import org.activiti.api.process.model.ProcessDefinition;
  4. import org.activiti.api.process.model.ProcessInstance;
  5. import org.activiti.api.process.model.builders.ProcessPayloadBuilder;
  6. import org.activiti.api.process.runtime.ProcessRuntime;
  7. import org.activiti.api.runtime.shared.query.Page;
  8. import org.activiti.api.runtime.shared.query.Pageable;
  9. import org.activiti.api.task.model.Task;
  10. import org.activiti.api.task.model.builders.TaskPayloadBuilder;
  11. import org.activiti.api.task.runtime.TaskRuntime;
  12. import org.junit.Test;
  13. import org.junit.runner.RunWith;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.boot.test.context.SpringBootTest;
  16. import org.springframework.test.context.junit4.SpringRunner;
  17. import java.util.List;
  18. @RunWith(SpringRunner.class)
  19. @SpringBootTest(classes = Activiti7SpringBootApplication.class)
  20. public class Activiti7Test {
  21. /**
  22. * 流程定义相关操作
  23. */
  24. @Autowired
  25. private ProcessRuntime processRuntime;
  26. /**
  27. * 任务相关操作
  28. */
  29. @Autowired
  30. private TaskRuntime taskRuntime;
  31. @Autowired
  32. private UserService userService;
  33. /**
  34. * 查看流程定义
  35. */
  36. @Test
  37. public void testQueryProcessDefinition() {
  38. userService.logInAs("salaboy");
  39. //分页查询流程定义信息
  40. Page<ProcessDefinition> page = processRuntime.processDefinitions(Pageable.of(0, 10));
  41. int totalItems = page.getTotalItems();
  42. System.out.println("查看部署流程的个数 = " + totalItems);
  43. List<ProcessDefinition> content = page.getContent();
  44. for (ProcessDefinition processDefinition : content) {
  45. String id = processDefinition.getId();
  46. System.out.println("当前部署的流程定义的id = " + id);
  47. }
  48. }
  49. /**
  50. * 启动流程实例
  51. */
  52. @Test
  53. public void testStartProcessInstance() {
  54. userService.logInAs("salaboy");
  55. ProcessInstance processInstance = processRuntime.start(ProcessPayloadBuilder.start().withProcessDefinitionKey("team01").build());
  56. System.out.println("流程实例的id = " + processInstance.getId());
  57. }
  58. /**
  59. * 任务分页查询
  60. */
  61. @Test
  62. public void testQueryTask() {
  63. userService.logInAs("salaboy");
  64. Page<Task> page = taskRuntime.tasks(Pageable.of(0, 10));
  65. int totalItems = page.getTotalItems();
  66. System.out.println("任务的总数 = " + totalItems);
  67. for (Task task : page.getContent()) {
  68. String id = task.getId();
  69. System.out.println("任务的id = " + id);
  70. String name = task.getName();
  71. System.out.println("任务名称 = " + name);
  72. }
  73. }
  74. /**
  75. * 测试查询任务并完成任务
  76. */
  77. @Test
  78. public void testQueryTaskAndCompleteTask(){
  79. userService.logInAs("salaboy");
  80. Page<Task> page = taskRuntime.tasks(Pageable.of(0, 10));
  81. int totalItems = page.getTotalItems();
  82. System.out.println("任务的总数 = " + totalItems);
  83. for (Task task : page.getContent()) {
  84. String id = task.getId();
  85. System.out.println("任务的id = " + id);
  86. String name = task.getName();
  87. System.out.println("任务名称 = " + name);
  88. //拾取任务
  89. taskRuntime.claim(TaskPayloadBuilder.claim().withTaskId(id).build());
  90. //完成任务
  91. taskRuntime.complete(TaskPayloadBuilder.complete().withTaskId(id).build());
  92. }
  93. }
  94. }