当前位置:   article > 正文

Flowable-SpringBoot项目集成_flowable-spring-boot-starter-process

flowable-spring-boot-starter-process

在前面的介绍中,虽然实现了绘制流程图,然后将流程图存储到数据库中,然后从数据库中获取流程信息,并部署和启动流程,但是部署的流程绘制器是在tomcat中部署的,可能在部分的项目中,需要我们将流程设计器,设置到自己的项目中,这样部署项目就相当于部署了流程设计器,下面对SpringBoot项目集成flowable流程设计器进行简单介绍。

一、项目整合

在前面部署flowable-ui后可以看到,ui界面分为了任务应用程序、建模器应用程序、管理员应用程序和身份管理应用程序。

在这几个应用中,最重要的就是建模器应用程序(flowable-modeler),它主要是用来绘制流程图和流程定义信息,因此,在这里我们是在项目中集成了建模器应用程序,实现在自己的项目中使用flowable-ui官方的建模器具绘制流程图,并将其保存到mysql数据库中。

环境:flowable版本:6.7.2 MySQL版本:5.7

  1. 下载源码

在这里下载对应版本的flowable-ui的源码。

Release Flowable 6.7.2 release · flowable/flowable-engine · GitHub

6.7.2版本的源码:

flowable-engine-flowable-6.7.2.zip

  1. flowable引擎基础配置

由于是 spring-boot 项目,因此直接选择 flowable-spring-boot-starter,里面提供了齐全的 REST API

  1. <!--Flowable的核心依赖-->
  2. <dependency>
  3. <groupId>org.flowable</groupId>
  4. <artifactId>flowable-spring-boot-starter-process</artifactId>
  5. <version>${flowable.version}</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.flowable</groupId>
  9. <artifactId>flowable-spring-boot-starter</artifactId>
  10. <version>${flowable.version}</version>
  11. </dependency>
  12. <dependency>
  13. <groupId>org.flowable</groupId>
  14. <artifactId>flowable-json-converter</artifactId>
  15. <version>${flowable.version}</version>
  16. </dependency>
  17. <dependency>
  18. <groupId>org.flowable</groupId>
  19. <artifactId>flowable-bpmn-layout</artifactId>
  20. <version>${flowable.version}</version>
  21. </dependency>

添加yml配置:

  1. # flowable config
  2. flowable:
  3. # 关闭定时任务JOB
  4. async-executor-activate: true
  5. # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  6. database-schema-update: true
  7. check-process-definitions: false
  8. db-history-used: true
  9. history-level: full

日志配置:

注意:Flowable 使用 SLF4J 作为内部日志框架,所以我们使用 log4j 作为 SLF4J 的实现

添加依赖:

  1. <!--日志-->
  2. <dependency>
  3. <groupId>org.slf4j</groupId>
  4. <artifactId>slf4j-api</artifactId>
  5. <version>1.7.21</version>
  6. </dependency>
  7. <dependency>
  8. <groupId>org.slf4j</groupId>
  9. <artifactId>slf4j-log4j12</artifactId>
  10. <version>1.7.21</version>
  11. </dependency>

resource 目录下新建文件 log4j.properties

  1. log4j.rootLogger=DEBUG, CA
  2. log4j.appender.CA=org.apache.log4j.ConsoleAppender
  3. log4j.appender.CA.layout=org.apache.log4j.PatternLayout
  4. log4j.appender.CA.layout.ConversionPattern= %d{hh:mm:ss,SSS} [%t] %-5p %c %x - %m%n
  1. 集成 flowable-modeler 前端

这里为了方便我们开发,将官方的flowable-modeler前端项目直接集成到了后端中。

从刚刚下载的源码中获取flowable-modeler的statci文件,6.7.2版本的目录在:

flowable-engine-flowable-6.7.2\modules\flowable-ui\flowable-ui-modeler-frontend\src\main\resources

复制包中 resources\static 下所有前端代码文件,复制到我们自己的项目static 文件夹下,项目没有static就在resource目录下新建static文件夹。

添加依赖:

  1. <!--通过下方的配置,加上官方源码中的静态文件,就可以将建模器应用程序集成到项目中-->
  2. <dependency>
  3. <groupId>org.flowable</groupId>
  4. <artifactId>flowable-ui-modeler-rest</artifactId>
  5. <version>${flowable.version}</version>
  6. <exclusions>
  7. <exclusion>
  8. <groupId>org.mybatis</groupId>
  9. <artifactId>mybatis</artifactId>
  10. </exclusion>
  11. </exclusions>
  12. </dependency>
  13. <dependency>
  14. <groupId>org.flowable</groupId>
  15. <artifactId>flowable-ui-modeler-conf</artifactId>
  16. <version>${flowable.version}</version>
  17. </dependency>
  18. <dependency>
  19. <groupId>org.flowable</groupId>
  20. <artifactId>flowable-ui-modeler-logic</artifactId>
  21. <version>${flowable.version}</version>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.liquibase</groupId>
  25. <artifactId>liquibase-core</artifactId>
  26. <version>4.4.0</version>
  27. </dependency>

配置文件:

在新版本的flowable-modeler中,需要配置idm,身份认证的相关配置,因此,在配置文件中添加:

  1. # flowable config
  2. flowable:
  3. # 关闭定时任务JOB
  4. async-executor-activate: true
  5. # 将databaseSchemaUpdate设置为true。当Flowable发现库与数据库表结构不一致时,会自动将数据库表结构升级至新版本。
  6. database-schema-update: true
  7. check-process-definitions: false
  8. db-history-used: true
  9. history-level: full
  10. common:
  11. app:
  12. idm-url: http://localhost:8099/flowable-idm
  13. idm-admin:
  14. user: admin
  15. password: admin

自定义配置类:

DatabaseAutoConfiguration.java

Flowable 是基于 liquibase 进行数据库自动管理与追踪的,因此需要加一个 liquibase 的配置类(可以把org.flowable.ui.modeler.conf.DatabaseConfiguration下的复制下来改一改)

  1. import liquibase.Liquibase;
  2. import liquibase.database.Database;
  3. import liquibase.database.DatabaseConnection;
  4. import liquibase.database.DatabaseFactory;
  5. import liquibase.database.jvm.JdbcConnection;
  6. import liquibase.exception.DatabaseException;
  7. import liquibase.resource.ClassLoaderResourceAccessor;
  8. import org.flowable.ui.common.service.exception.InternalServerErrorException;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import org.springframework.context.annotation.Bean;
  12. import org.springframework.context.annotation.Configuration;
  13. import javax.sql.DataSource;
  14. @Configuration
  15. public class DatabaseAutoConfiguration {
  16. private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseAutoConfiguration.class);
  17. protected static final String LIQUIBASE_CHANGELOG_PREFIX = "ACT_DE_";
  18. @Bean
  19. public Liquibase liquibase(DataSource dataSource) {
  20. LOGGER.info("Configuring Liquibase");
  21. Liquibase liquibase = null;
  22. try {
  23. DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());
  24. Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
  25. database.setDatabaseChangeLogTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogTableName());
  26. database.setDatabaseChangeLogLockTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogLockTableName());
  27. liquibase = new Liquibase("META-INF/liquibase/flowable-modeler-app-db-changelog.xml", new ClassLoaderResourceAccessor(), database);
  28. liquibase.update("flowable");
  29. return liquibase;
  30. } catch (Exception e) {
  31. throw new InternalServerErrorException("Error creating liquibase database", e);
  32. } finally {
  33. closeDatabase(liquibase);
  34. }
  35. }
  36. private void closeDatabase(Liquibase liquibase) {
  37. if (liquibase != null) {
  38. Database database = liquibase.getDatabase();
  39. if (database != null) {
  40. try {
  41. database.close();
  42. } catch (DatabaseException e) {
  43. LOGGER.warn("Error closing database", e);
  44. }
  45. }
  46. }
  47. }
  48. }

之后还需要添加mybatis-plus的相关配置:需要配置扫描 classpath:/META-INF/modeler-mybatis-mappings/*.xml

  1. mybatis-plus:
  2. mapper-locations: classpath:/mapper/*Mapper.xml, classpath:/META-INF/modeler-mybatis-mappings/*.xml
  3. configuration:
  4. map-underscore-to-camel-case: true
  5. jdbc-type-for-null: null
  6. # 参数配置
  7. configuration-properties:
  8. # 配置流程引擎参数,详情可见 DatabaseConfiguration
  9. blobType: BLOB
  10. boolValue: TRUE
  11. # 不要设置库名,否则会出现双库名 bug
  12. prefix: ''

汉化配置:

StencilSetResource.java

在源码中找到这俩文件:

在resource下新建stencilset文件夹,将源码中的两个汉化文件放入该文件夹中。

添加类配置,在这里新建类的时候,名称不能为StencilSetResource,会与官方的jar包中的bean冲突,因此,我们新建FlowableStencilSetResource.java。

  1. import com.fasterxml.jackson.databind.JsonNode;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import org.flowable.ui.common.service.exception.InternalServerErrorException;
  4. import org.slf4j.Logger;
  5. import org.slf4j.LoggerFactory;
  6. import org.springframework.beans.factory.annotation.Autowired;
  7. import org.springframework.web.bind.annotation.RequestMapping;
  8. import org.springframework.web.bind.annotation.RequestMethod;
  9. import org.springframework.web.bind.annotation.RestController;
  10. /**
  11. * 汉化 配置
  12. */
  13. @RestController
  14. @RequestMapping("/app")
  15. public class FlowableStencilSetResource {
  16. private static final Logger LOGGER = LoggerFactory.getLogger(FlowableStencilSetResource.class);
  17. @Autowired
  18. protected ObjectMapper objectMapper;
  19. @RequestMapping(value = "/rest/stencil-sets/editor", method = RequestMethod.GET, produces = "application/json")
  20. public JsonNode getStencilSetForEditor() {
  21. try {
  22. JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream("stencilset/stencilset_bpmn.json"));
  23. return stencilNode;
  24. } catch (Exception e) {
  25. LOGGER.error("Error reading bpmn stencil set json", e);
  26. throw new InternalServerErrorException("Error reading bpmn stencil set json");
  27. }
  28. }
  29. @RequestMapping(value = "/rest/stencil-sets/cmmneditor", method = RequestMethod.GET, produces = "application/json")
  30. public JsonNode getCmmnStencilSetForEditor() {
  31. try {
  32. JsonNode stencilNode = objectMapper.readTree(this.getClass().getClassLoader().getResourceAsStream("stencilset/stencilset_cmmn.json"));
  33. return stencilNode;
  34. } catch (Exception e) {
  35. LOGGER.error("Error reading bpmn stencil set json", e);
  36. throw new InternalServerErrorException("Error reading bpmn stencil set json");
  37. }
  38. }
  39. }

SecurityUtils配置

注意因为源码中引用了这个类,因此我们在配置的时候,路径需要与源码中的路径保持一致,也就是:org.flowable.ui.common.security 这样在 Jar 中的方法在调用时会覆盖原 Jar 里的工具类

下方的类为6.7.2版本的配置,如果是低版本的配置,可能不同,在旧版本中,flowable使用了FlowableAppUser,但是在新版本的依赖中,转而是:SecurityScope,因此这个配置需要根据自己的flowable版本配置。

  1. import java.util.ArrayList;
  2. import java.util.List;
  3. import org.flowable.common.engine.api.FlowableIllegalStateException;
  4. import org.flowable.idm.api.User;
  5. import org.flowable.ui.common.model.RemoteUser;
  6. import org.springframework.security.core.Authentication;
  7. import org.springframework.security.core.context.SecurityContext;
  8. import org.springframework.security.core.context.SecurityContextHolder;
  9. /**
  10. * 重构流程编辑器获取用户信息
  11. */
  12. public class SecurityUtils {
  13. private static User assumeUser;
  14. private static SecurityScopeProvider securityScopeProvider = new FlowableSecurityScopeProvider();
  15. private SecurityUtils() {
  16. }
  17. /**
  18. * Get the login of the current user.
  19. */
  20. public static String getCurrentUserId() {
  21. User user = getCurrentUserObject();
  22. if (user != null) {
  23. return user.getId();
  24. }
  25. return null;
  26. }
  27. /**
  28. * @return the {@link User} object associated with the current logged in user.
  29. */
  30. public static User getCurrentUserObject() {
  31. if (assumeUser != null) {
  32. return assumeUser;
  33. }
  34. RemoteUser user = new RemoteUser();
  35. user.setId("admin");
  36. user.setDisplayName("admin");
  37. user.setFirstName("admin");
  38. user.setLastName("admin");
  39. user.setEmail("admin@flowable.com");
  40. user.setPassword("123456");
  41. List<String> pris = new ArrayList<>();
  42. pris.add(DefaultPrivileges.ACCESS_MODELER);
  43. pris.add(DefaultPrivileges.ACCESS_IDM);
  44. pris.add(DefaultPrivileges.ACCESS_ADMIN);
  45. pris.add(DefaultPrivileges.ACCESS_TASK);
  46. pris.add(DefaultPrivileges.ACCESS_REST_API);
  47. user.setPrivileges(pris);
  48. return user;
  49. }
  50. public static void setSecurityScopeProvider(SecurityScopeProvider securityScopeProvider) {
  51. SecurityUtils.securityScopeProvider = securityScopeProvider;
  52. }
  53. public static SecurityScope getCurrentSecurityScope() {
  54. SecurityContext securityContext = SecurityContextHolder.getContext();
  55. if (securityContext != null && securityContext.getAuthentication() != null) {
  56. return getSecurityScope(securityContext.getAuthentication());
  57. }
  58. return null;
  59. }
  60. public static SecurityScope getSecurityScope(Authentication authentication) {
  61. return securityScopeProvider.getSecurityScope(authentication);
  62. }
  63. public static SecurityScope getAuthenticatedSecurityScope() {
  64. SecurityScope currentSecurityScope = getCurrentSecurityScope();
  65. if (currentSecurityScope != null) {
  66. return currentSecurityScope;
  67. }
  68. throw new FlowableIllegalStateException("User is not authenticated");
  69. }
  70. public static void assumeUser(User user) {
  71. assumeUser = user;
  72. }
  73. public static void clearAssumeUser() {
  74. assumeUser = null;
  75. }
  76. }

认证请求配置

前端 url-config.js 修改

路径:resource\static\scripts\configuration\url-conf.js

将 getAccountUrl 的路径改为上面自己的 getAccount 接口的路径,我们让他使用我们自己的认证

后端添加Controller

添加一个登录认证的FlowModelerController

  1. /**
  2. * flowable-modeler获取默认的管理员信息
  3. *
  4. * @Author: yichangqiao
  5. * @Date: 2024/4/19 16:11
  6. */
  7. @Slf4j
  8. @RestController
  9. public class FlowModelerController {
  10. /**
  11. * 获取默认的管理员信息
  12. * @return
  13. */
  14. @RequestMapping(value = "/flow/rest/account", method = RequestMethod.GET, produces = "application/json")
  15. public UserRepresentation getAccount() {
  16. UserRepresentation userRepresentation = new UserRepresentation();
  17. userRepresentation.setId("admin");
  18. userRepresentation.setEmail("admin@flowable.org");
  19. userRepresentation.setFullName("Administrator");
  20. userRepresentation.setLastName("Administrator");
  21. userRepresentation.setFirstName("Administrator");
  22. List<String> privileges = new ArrayList<>();
  23. privileges.add(DefaultPrivileges.ACCESS_MODELER);
  24. privileges.add(DefaultPrivileges.ACCESS_IDM);
  25. privileges.add(DefaultPrivileges.ACCESS_ADMIN);
  26. privileges.add(DefaultPrivileges.ACCESS_TASK);
  27. privileges.add(DefaultPrivileges.ACCESS_REST_API);
  28. userRepresentation.setPrivileges(privileges);
  29. log.info("login init success ..... ");
  30. return userRepresentation;
  31. }
  32. }

mybatis-plus配置

因为flowable自己使用了一个sqlsessionfactory创建SQL会话,但是我们自己的项目中又需要使用mybatis-plus的sqlsessionfactory,在mybatis-plus加载sqlsessionfactory默认是单例的,因此我们需要配置默认的回话连接:

  1. import com.baomidou.mybatisplus.annotation.DbType;
  2. import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
  3. import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
  4. import org.mybatis.spring.annotation.MapperScan;
  5. import org.springframework.context.annotation.Bean;
  6. import org.springframework.context.annotation.Configuration;
  7. @Configuration
  8. @MapperScan(basePackages = {"com.flowable.mapper"},
  9. sqlSessionFactoryRef = "sqlSessionFactory",
  10. sqlSessionTemplateRef = "sqlSessionTemplate")
  11. public class MybatisPlusConfig {
  12. @Bean
  13. public MybatisPlusInterceptor mybatisPlusInterceptor() {
  14. MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
  15. interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
  16. return interceptor;
  17. }
  18. }

配置security

这里我们需要跳过flowable的权限校验,而是使用我们自己的认证框架,因此,需要在项目中配置:

  1. import org.flowable.ui.common.security.SecurityConstants;
  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.core.annotation.Order;
  4. import org.springframework.security.config.annotation.web.builders.HttpSecurity;
  5. import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
  6. @Configuration
  7. public class SecurityConfiguration {
  8. @Configuration(proxyBeanMethods = false)//所以这个地方-1让该配置项在FlowableUiSecurityAutoConfiguration中对应配置项前加载,以跳过授权
  9. @Order(SecurityConstants.FORM_LOGIN_SECURITY_ORDER - 1)
  10. public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
  11. @Override
  12. protected void configure(HttpSecurity http) throws Exception {
  13. http
  14. //必须要将csrf设置为disable,不然后面发送POST请求时会报403错误
  15. .csrf().disable()
  16. //为了简单起见,简单粗暴方式直接放行modeler下面所有请求
  17. .authorizeRequests().antMatchers("/**").permitAll();
  18. }
  19. }
  20. }

修改Application启动类配置

让spring加载我们自定义的配置bean:FlowableStencilSetResource.class、DatabaseAutoConfiguration.class

  1. import com.yichangqiao.flowable.config.DatabaseAutoConfiguration;
  2. import com.yichangqiao.flowable.config.FlowableStencilSetResource;
  3. import lombok.extern.slf4j.Slf4j;
  4. import org.flowable.ui.common.security.ApiHttpSecurityCustomizer;
  5. import org.flowable.ui.common.security.FlowableUiSecurityAutoConfiguration;
  6. import org.mybatis.spring.annotation.MapperScan;
  7. import org.springframework.boot.SpringApplication;
  8. import org.springframework.boot.autoconfigure.SpringBootApplication;
  9. import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration;
  10. import org.springframework.context.annotation.ComponentScan;
  11. import org.springframework.context.annotation.Import;
  12. import java.time.LocalDateTime;
  13. @Slf4j
  14. //启用全局异常拦截器
  15. @Import(value = {
  16. FlowableStencilSetResource.class,
  17. // 引入 DatabaseConfiguration 表更新转换,
  18. DatabaseAutoConfiguration.class
  19. })
  20. @ComponentScan(basePackages = {"com.flowable.*"})
  21. @SpringBootApplication(exclude = {SecurityAutoConfiguration.class})
  22. public class MasterYiFlowableApplication {
  23. public static void main(String[] args) {
  24. SpringApplication.run(MasterYiFlowableApplication.class, args);
  25. log.info("flowable模块加载成功 ================> {}", LocalDateTime.now());
  26. }
  27. }

启动项目

启动项目后,访问项目地址:127.0.0.1:端口,就可以访问到我们本地项目中的flowable-modeler了。

三、结语

实际整合过程中,可能存在版本、环境、依赖等影响,导致出现报错,但是大体的思路如上,可以参考整合。

下一节:flowable-整合系统角色人员 Flowable-整合系统角色人员-CSDN博客

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/木道寻08/article/detail/982826
推荐阅读
相关标签
  

闽ICP备14008679号