一、Maven依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-web</artifactId>
  4. </dependency>
  5. <!--druid-->
  6. <dependency>
  7. <groupId>com.alibaba</groupId>
  8. <artifactId>druid-spring-boot-starter</artifactId>
  9. <version>1.1.18</version>
  10. </dependency>
  11. <!--MySql驱动-->
  12. <dependency>
  13. <groupId>mysql</groupId>
  14. <artifactId>mysql-connector-java</artifactId>
  15. </dependency>
  16. <!--mybatis-plus 插件-->
  17. <dependency>
  18. <groupId>com.baomidou</groupId>
  19. <artifactId>mybatis-plus-boot-starter</artifactId>
  20. </dependency>
  21. <!--lombok-->
  22. <dependency>
  23. <groupId>org.projectlombok</groupId>
  24. <artifactId>lombok</artifactId>
  25. <optional>true</optional>
  26. </dependency>
  27. <dependency>
  28. <groupId>org.activiti</groupId>
  29. <artifactId>activiti-spring-boot-starter</artifactId>
  30. <version>7.1.0.M5</version>
  31. <exclusions>
  32. <exclusion>
  33. <groupId>org.activiti.core.common</groupId>
  34. <artifactId>activiti-spring-identity</artifactId>
  35. </exclusion>
  36. </exclusions>
  37. </dependency>
  38. <dependency>
  39. <groupId>org.springframework.boot</groupId>
  40. <artifactId>spring-boot-starter-test</artifactId>
  41. <scope>test</scope>
  42. </dependency>

二、配置

1. application.properties配置

  1. spring
  2. activiti
  3. # 表示启动时检查数据库表,不存在则创建
  4. database-schema-updatetrue
  5. # 表示哪种情况下使用历史表,这里配置为full表示全部记录历史,方便绘制流程图
  6. history-levelfull
  7. # true 表示使用历史表,如果不配置,则工程启动后可以检查数据库,只建立了17张表
  8. db-history-usedtrue
  9. # 数据库连接
  10. datasource
  11. urljdbc:mysql://localhost:3306/xtsz_workflow?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC&nullCatalogMeansCurrent=true
  12. usernameroot
  13. password123
  14. driver-class-namecom.mysql.cj.jdbc.Driver
  15. typecom.alibaba.druid.pool.DruidDataSource

参数说明: databaseSchemaUpdate配置项可以设置流程引擎启动和关闭时数据库执行的策略。 databaseSchemaUpdate有以下四个值: false:false为默认值,设置为该值后,Activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配时,将在启动时抛出异常。 true:设置为该值后,Activiti会对数据库中所有的表进行更新,如果表不存在,则Activiti会自动创建。 create-drop:Activiti启动时,会执行数据库表的创建操作,在Activiti关闭时,执行数据库表的删除操作。 drop-create:Activiti启动时,执行数据库表的删除操作在Activiti关闭时,会执行数据库表的创建操作。

  • asyncExecutorEnabled属性设置设置true后将代替那些老的Job executor
    • spring.activiti.async-executor-enabled=false
    • spring.activiti.job-executor-activate=false
  • asyncExecutorActivate是指示activiti在流程引擎启动就激活AsyncExecutor,异步
    • spring.activiti.async-executor-activate=
  • 校验流程文件,默认校验resources下的processes文件夹里的流程文件
    • spring.activiti.check-process-definitions=
  • 使用自定义mybatis-mapper
    • spring.activiti.custom-mybatis-mappers=
    • spring.activiti.custom-mybatis-xmlmappers=
  • 数据源指定
    • spring.activiti.database-schema=
  • 建表规则
    • flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。
    • true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。
    • create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。
    • drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)
    • spring.activiti.database-schema-update=false
  • 检测历史表是否存在
    • spring.activiti.db-history-used=false
  • 检测身份信息表是否存在
    • spring.activiti.db-identity-used=false
  • 流程部署名称
    • spring.activiti.deployment-name=
  • 记录历史等级 可配置的历史级别有none, acitivity, audit, all
    • spring.activiti.history-level=
  • spring jpa使用
    • spring.activiti.jpa-enabled=false
  • 邮件发送服务配置
    • spring.activiti.mail-server-default-from=
    • spring.activiti.mail-server-host=
    • spring.activiti.mail-server-password=
    • spring.activiti.mail-server-port=
    • spring.activiti.mail-server-use-ssl=
    • spring.activiti.mail-server-use-tls=
    • spring.activiti.mail-server-user-name=
  • 自定义流程文件位置
    • spring.activiti.process-definition-location-prefix=
    • spring.activiti.process-definition-location-suffixes=
  • activiti rest 配置
    • spring.activiti.rest-api-enabled=false
    • spring.activiti.rest-api-mapping=
    • spring.activiti.rest-api-servlet-name=

2. 关闭activiti默认的安全校验

activiti7内置了Spring security框架,因此只要我们在项目中引入了如下jar包,那么项目中所有接口都会被security拦截到,然后跳转到登录页面。
取消security验证:

  1. @SpringBootApplication(exclude = {SecurityAutoConfiguration.class})

Activit 7 - 图1
security认证
这里需要输入用户名和密码,默认的用户名是user用户,密码会在项目启动的时候生成。
Activit 7 - 图2
密码

3. 配置类

  1. @Configuration
  2. public class SecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Override
  4. protected void configure(HttpSecurity http) throws Exception {
  5. http.authorizeRequests().anyRequest().permitAll().and().logout().permitAll();
  6. }
  7. }

4. 重写用户权限

  1. @Service
  2. public class CustomUserGroupManagerImpl implements UserGroupManager {
  3. public static List<String> roles = new ArrayList<>();
  4. public static List<String> groups = new ArrayList<>();
  5. public static List<String> users = new ArrayList<>();
  6. public static Map<String,String> userRoleMap = new HashMap<>();
  7. static {
  8. roles.add("workCreate");
  9. roles.add("workPermit");
  10. roles.add("workLeader");
  11. groups.add("workGroupA");
  12. users.add("admin");
  13. users.add("laowang");
  14. users.add("xiaofang");
  15. userRoleMap.put("admin", "workCreate");
  16. userRoleMap.put("laowang", "workPermit");
  17. userRoleMap.put("xiaofang", "workLeader");
  18. }
  19. @Override
  20. public List<String> getUserGroups(String s) {
  21. return groups;
  22. }
  23. @Override
  24. public List<String> getUserRoles(String s) {
  25. String role = userRoleMap.get(s);
  26. List<String> list = new ArrayList<>();
  27. list.add(role);
  28. return list;
  29. }
  30. @Override
  31. public List<String> getGroups() {
  32. return groups;
  33. }
  34. @Override
  35. public List<String> getUsers() {
  36. return users;
  37. }
  38. }

5. 配置activiti的数据源和线程池

  1. @Configuration
  2. public class WorkFlowConfiguration {
  3. @Autowired
  4. private UserGroupManager userGroupManager;
  5. @Autowired
  6. private DataSource dataSource;
  7. private int corePoolSize = 10;
  8. private int maxPoolSize = 30;
  9. private int keepAliveSeconds = 300;
  10. private int queueCapacity = 300;
  11. /**
  12. * 处理引擎配置
  13. * @param transactionManager
  14. * @return
  15. */
  16. @Bean
  17. public SpringProcessEngineConfiguration springProcessEngineConfiguration(
  18. PlatformTransactionManager transactionManager) {
  19. SpringProcessEngineConfiguration configuration = new SpringProcessEngineConfiguration();
  20. configuration.setDataSource(dataSource);
  21. configuration.setTransactionManager(transactionManager);
  22. SpringAsyncExecutor asyncExecutor = new SpringAsyncExecutor();
  23. asyncExecutor.setTaskExecutor(workFlowAsync());
  24. configuration.setAsyncExecutor(asyncExecutor);
  25. configuration.setDatabaseSchemaUpdate("true");
  26. configuration.setUserGroupManager(userGroupManager);
  27. configuration.setHistoryLevel(HistoryLevel.FULL);
  28. configuration.setDbHistoryUsed(true);
  29. return configuration;
  30. }
  31. /**
  32. * 线程池
  33. *
  34. * @return
  35. */
  36. @Primary
  37. @Bean("workFlowTaskExecutor")
  38. public ThreadPoolTaskExecutor workFlowAsync() {
  39. ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
  40. executor.setCorePoolSize(corePoolSize);
  41. executor.setMaxPoolSize(maxPoolSize);
  42. executor.setKeepAliveSeconds(keepAliveSeconds);
  43. executor.setQueueCapacity(queueCapacity);
  44. executor.setThreadNamePrefix("workFlowTaskExecutor-");
  45. executor.initialize();
  46. return executor;
  47. }
  48. }

三、Spring Security相关配置

因为activiti7使用了Spring Security,因此需要创建Spring Security需要用到的表和初始化一系列的用户数据。

1. 创建表

  1. DROP TABLE IF EXISTS `users`;
  2. CREATE TABLE `users` (
  3. `id` int(8) NOT NULL AUTO_INCREMENT,
  4. `userName` varchar(20) DEFAULT NULL,
  5. `password` varchar(255) DEFAULT NULL,
  6. `enabled` tinyint(4) DEFAULT NULL,
  7. PRIMARY KEY (`id`)
  8. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  9. DROP TABLE IF EXISTS `authorities`;
  10. CREATE TABLE `authorities` (
  11. `id` int(11) NOT NULL AUTO_INCREMENT,
  12. `username` varchar(255) DEFAULT NULL,
  13. `authority` varchar(255) DEFAULT NULL,
  14. PRIMARY KEY (`id`)
  15. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;

2. 程序启用web security

为了能够与Process Runtime API进行交互,我们需要使用具有ROLE_ACTIVITI_USER角色的用户进行身份验证。 如果我们只是直接从Java代码调用Process Runtime API,例如来自带有main方法的类,那么我们可以在进行API调用之前直接设置用户上下文。

设置我们在与流程引擎API交互时可以使用的一些用户和组。

关于security问题
activiti7最新的类似Runtime API和Task API都集成了security。
如果使用上述的API,那么必须要使用security,不能屏蔽security,否则会报错。
使用引擎服务类的时候,可以排除security,因为这些是最原始的API。但是activiti7官方已经明确说了,随时可能会干掉这些API。不建议开发人员直接使用引擎类以及引擎配置了、服务类等。

四、流程绘制

其实就是设计中的活动图。
activiti7目前使用的Bpmn-js设计器,但是目前还没有发布正式版。activiti7流程设计器可以使用eclipse或者idea插件即可。接下来绘制一个简单的请假流程。流程图如下:

  1. 在resources中创建目录processes:

Activit 7 - 图3

  1. 绘制流程图

Activit 7 - 图4
Activit 7 - 图5
**
Activit 7 - 图6

加-》任务的办理人(Assignee)-> houjianjun
流程非常简单,请假天数大于3天,总经理审批;否则部门经理审批。
拷贝bpmn文件修改扩展名为xml,然后调整布局:
Activit 7 - 图7
保存为png图片
Activit 7 - 图8

五、部署流程

部署流程直接使用RepositoryService即可:

  1. @Autowired
  2. private RepositoryService repositoryService;
  3. @Autowired
  4. private RuntimeService runtimeService;
  5. @Autowired
  6. private TaskService taskService;
  7. @Test
  8. public void deploy() {
  9. DeploymentBuilder builder = repositoryService.createDeployment();
  10. // bpmn文件的名称
  11. builder.addClasspathResource("processes/leave.bpmn");
  12. builder.addClasspathResource("processes/leave.png");
  13. // 设置key
  14. builder.key("leave");
  15. // 设定名称,也可以在图中定义
  16. builder.name("请假流程");
  17. // 进行布署
  18. Deployment deployment = builder.deploy();
  19. log.info("部署ID:" + deployment.getId());
  20. log.info("部署名称:" + deployment.getName());
  21. }

startProcessInstanceByKey需要的参数,对应ACTRE_PROCDEF表key列的值。

流程文档部署完毕之后,会在以下表中创建记录:

  • ACT_RE_DEPLOYMENT(部署表)
  • ACT_RE_PROCDEF(流程定义表)
  • ACT_GE_BYTEARRAY(资源表)
  • ACT_GE_PROPERTY(通用属性表)
  • ACT_RU_IDENTITYLINK(运行权限表)

六、核心service

  • 服务类:
    • 在activiti5/6时代,用户永远可以通过如下几个服务类进行操作。
    • RepositoryService:仓库服务类
    • RuntimeService :运行服务类
    • TaskService :用户任务服务类
    • HistoryService :历史服务类
    • ManagementService :管理服务类
    • DynamicBpmnService :动态服务类

activiti7在salaboy带领下开发的云bpm产品,为了使其能够更好的支持cloud换机,activiti7进行了如下几个点的重构。
**

  • 服务类替换类:
    • Activiti Cloud Runtime Bundle
    • Activiti Cloud Query
    • Activiti Cloud Audit
    • Activiti Cloud Connectors
    • Activiti Cloud Notifications Service (GraphQL)

总结

  1. ProcessRuntime类内部最终调用repositoryService和runtimeService相关API。
  2. TaskRuntime类内部调用taskService。
  3. TaskAdminRuntime类内部调用taskService
  4. ProcessRuntime类需要ACTIVITI_USER权限。
  5. TaskRuntime需要ACTIVITI_USER权限。
  6. TaskAdminRuntime需要ACTIVITI_ADMIN权限。

七、启动流程

  1. /**
  2. * 启动流程
  3. */
  4. @Test
  5. public void start() {
  6. // 每一个流程有对应的一个key这个是某一个流程内固定的写在bpmn内的
  7. String processDefinitionKey = "leave";
  8. HashMap<String, Object> variables = new HashMap<>();
  9. // 流程实例
  10. ProcessInstance instance = runtimeService
  11. .startProcessInstanceByKey(processDefinitionKey,variables);
  12. log.info("流程实例ID:" + instance.getId());
  13. log.info("流程定义ID:" + instance.getProcessDefinitionId());
  14. }

startProcessInstanceByKey需要的参数,对应ACTRE_PROCDEF表key列的值。

八、查询任务

  1. /**
  2. * 查询当前人的个人任务
  3. * 查询任务表ACT_RU_TASK。启动实例之后,实例直接运转到请假申请节点。
  4. */
  5. @Test
  6. public void findTask() {
  7. // 创建任务查询对象
  8. List<Task> list = taskService.createTaskQuery()
  9. .list();
  10. if (list != null && list.size() > 0) {
  11. for (Task task : list) {
  12. log.info("任务ID:" + task.getId());
  13. log.info("任务名称:" + task.getName());
  14. log.info("任务的创建时间:" + task.getCreateTime());
  15. log.info("任务的办理人:" + task.getAssignee());
  16. log.info("流程实例ID:" + task.getProcessInstanceId());
  17. log.info("执行对象ID:" + task.getExecutionId());
  18. log.info("流程定义ID:" + task.getProcessDefinitionId());
  19. }
  20. }
  21. }

九、完成用户任务

完成该任务之后,实例直接运转到了总经理审批节点,完成任务的时候如果没有传递day参数,会报错。继续查询待办-完成任务,直至实例结束即可。

  1. /**
  2. * 完成用户任务
  3. * 完成该任务之后,实例直接运转到了总经理审批节点,完成任务的时候如果没有传递day参数,
  4. * 会报错。继续查询待办-完成任务,直至实例结束即可。
  5. */
  6. @Test
  7. public void completeTask() {
  8. Map map = new HashMap();
  9. map.put("day", 4);
  10. // 按配置的任务id填写
  11. map.put("_7","true");
  12. // 参数为:act_ru_task 表中的ID_
  13. taskService.complete("10005", map);
  14. }

十、常见问题:

  1. Error updating database. Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘VERSION‘ in ‘field list’
    Error updating database. Cause: java.sql.SQLSyntaxErrorException: Unknown column ‘PROJECT_RELEASE_VERSION
    ‘ in ‘field list’
    原因:
    创建表缺少VERSION_字段
    添加两个字段。

Activit 7 - 图9