一、Spring Boot整合Flowable UI Modeler 6.7.2

在若依项目中创建基础模块,按照Spring Boot整合Flowable UI Modeler 6.7.2,可以参考上一篇文章,文章地址如下:

Spring Boot 整合 Flowable-ui-modeler 6.7.2_wangdaoyin2010的博客-CSDN博客

二、修改数据库配置

按照Spring Boot方式整合Modeler后,在flowable-ui-modeler-conf依赖中类ModelerDatabaseConfiguration中注入了SqlSessionFactory和SqlSessionTemplate数据库相关Bean。这些注入的Bean会与ruoyi中的MyBatis自动注入的会冲突。所以需要需要重写flowable-ui-modeler-conf中的ModelerDatabaseConfiguration类中对应响应的配置进行重写。

1、覆盖ModelerDatabaseConfiguration

床建ModelerDatabaseConfiguration类,覆盖flowable-ui-modeler-conf依赖中的该类。


@Configuration(proxyBeanMethods = false)
public class ModelerDatabaseConfiguration {

    private static final Logger LOGGER = LoggerFactory.getLogger(ModelerDatabaseConfiguration.class);

    protected static final String LIQUIBASE_CHANGELOG_PREFIX = "ACT_DE_";

    @Autowired
    protected FlowableModelerAppProperties modelerAppProperties;
    @Autowired
    protected MybatisProperties mybatisProperties;

    @Autowired
    protected ResourceLoader resourceLoader;

    protected static Properties databaseTypeMappings = getDefaultDatabaseTypeMappings();

    public static final String DATABASE_TYPE_H2 = "h2";
    public static final String DATABASE_TYPE_HSQL = "hsql";
    public static final String DATABASE_TYPE_MYSQL = "mysql";
    public static final String DATABASE_TYPE_ORACLE = "oracle";
    public static final String DATABASE_TYPE_POSTGRES = "postgres";
    public static final String DATABASE_TYPE_MSSQL = "mssql";
    public static final String DATABASE_TYPE_DB2 = "db2";

    public static Properties getDefaultDatabaseTypeMappings() {
        Properties databaseTypeMappings = new Properties();
        databaseTypeMappings.setProperty("H2", DATABASE_TYPE_H2);
        databaseTypeMappings.setProperty("HSQL Database Engine", DATABASE_TYPE_HSQL);
        databaseTypeMappings.setProperty("MySQL", DATABASE_TYPE_MYSQL);
        databaseTypeMappings.setProperty("MariaDB", DATABASE_TYPE_MYSQL);
        databaseTypeMappings.setProperty("Oracle", DATABASE_TYPE_ORACLE);
        databaseTypeMappings.setProperty("PostgreSQL", DATABASE_TYPE_POSTGRES);
        databaseTypeMappings.setProperty("Microsoft SQL Server", DATABASE_TYPE_MSSQL);
        databaseTypeMappings.setProperty(DATABASE_TYPE_DB2, DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/NT", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/NT64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDP", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUX390", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXX8664", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXZ64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXPPC64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/LINUXPPC64LE", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/400 SQL", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/6000", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDB iSeries", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/AIX64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/HPUX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/HP64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/SUN", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/SUN64", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/PTX", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2/2", DATABASE_TYPE_DB2);
        databaseTypeMappings.setProperty("DB2 UDB AS400", DATABASE_TYPE_DB2);
        return databaseTypeMappings;
    }

    @Bean
    @Qualifier("flowableModeler")
    @Primary
    public SqlSessionFactory modelerSqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        String databaseType = initDatabaseType(dataSource);
        if (databaseType == null) {
            throw new FlowableException("couldn't deduct database type");
        }

        try {
            Properties properties = new Properties();
            properties.put("prefix", modelerAppProperties.getDataSourcePrefix());
            properties.put("blobType", "BLOB");
            properties.put("boolValue", "TRUE");

            properties.load(this.getClass().getClassLoader().getResourceAsStream("org/flowable/db/properties/" + databaseType + ".properties"));

            sqlSessionFactoryBean.setConfigurationProperties(properties);
            //这个是原始代码,只添加flowable的扫描路径
//            sqlSessionFactoryBean
//                    .setMapperLocations(ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:/META-INF/modeler-mybatis-mappings/*.xml"));
            //由于后面要设置该SqlSessionFactory为主要的SqlSessionFactory,
            // 然后Ruoyi中使用时Mybatis自动注入,所以在这个地方就需要添加Ruoyi配置扫描
            ResourcePatternResolver resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);

            List<Resource> allResourceList = new ArrayList<>();
            List<String> mapperLocations = new ArrayList<>();
            //先添加
            mapperLocations.add("classpath:/META-INF/modeler-mybatis-mappings/*.xml");
            mapperLocations.add("classpath*:/mapper/**/*Mapper.xml");

            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] resources = resourcePatternResolver.getResources(mapperLocation);
                    allResourceList.addAll(Arrays.asList(resources));
                } catch (Exception ex) {
                    throw new FlowableException("Could not create sqlSessionFactory", ex);
                }
            }
            Resource[] allResourceArr = allResourceList.toArray(new Resource[allResourceList.size()]);
            //因为若依中使用了类别名基础包,所以需要在这个地方进行添加
            sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackage());
            sqlSessionFactoryBean.setMapperLocations(allResourceArr);
            sqlSessionFactoryBean.afterPropertiesSet();
            return sqlSessionFactoryBean.getObject();
        } catch (Exception e) {
            throw new FlowableException("Could not create sqlSessionFactory", e);
        }

    }

    @Bean(destroyMethod = "clearCache")
    // destroyMethod: see https://github.com/mybatis/old-google-code-issues/issues/778
    @Qualifier("flowableModeler")
    @Primary
    public SqlSessionTemplate modelerSqlSessionTemplate(@Qualifier("flowableModeler") SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }

    @Bean
    @Qualifier("flowableModeler")
    public Liquibase modelerLiquibase(DataSource dataSource) {
        LOGGER.info("Configuring Liquibase");

        try {
            return LiquibaseUtil.runInFlowableScope(() -> createAndUpdateLiquibase(dataSource));
        } catch (Exception e) {
            throw new InternalServerErrorException("Error creating liquibase database", e);
        }
    }

    protected Liquibase createAndUpdateLiquibase(DataSource dataSource) {
        Liquibase liquibase = null;
        try {
            DatabaseConnection connection = new JdbcConnection(dataSource.getConnection());
            Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(connection);
            database.setDatabaseChangeLogTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogTableName());
            database.setDatabaseChangeLogLockTableName(LIQUIBASE_CHANGELOG_PREFIX + database.getDatabaseChangeLogLockTableName());

            liquibase = new Liquibase("META-INF/liquibase/flowable-modeler-app-db-changelog.xml", new ClassLoaderResourceAccessor(), database);
            liquibase.update("flowable");
            return liquibase;

        } catch (Exception e) {
            throw new InternalServerErrorException("Error creating liquibase database", e);
        } finally {
            closeDatabase(liquibase);
        }
    }

    protected String initDatabaseType(DataSource dataSource) {
        String databaseType = null;
        Connection connection = null;
        try {
            connection = dataSource.getConnection();
            DatabaseMetaData databaseMetaData = connection.getMetaData();
            String databaseProductName = databaseMetaData.getDatabaseProductName();
            LOGGER.info("database product name: '{}'", databaseProductName);
            databaseType = databaseTypeMappings.getProperty(databaseProductName);
            if (databaseType == null) {
                throw new FlowableException("couldn't deduct database type from database product name '" + databaseProductName + "'");
            }
            LOGGER.info("using database type: {}", databaseType);

        } catch (SQLException e) {
            LOGGER.error("Exception while initializing Database connection", e);
        } finally {
            try {
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                LOGGER.error("Exception while closing the Database connection", e);
            }
        }

        return databaseType;
    }

    private void closeDatabase(Liquibase liquibase) {
        if (liquibase != null) {
            Database database = liquibase.getDatabase();
            if (database != null) {
                try {
                    database.close();
                } catch (DatabaseException e) {
                    LOGGER.warn("Error closing database", e);
                }
            }
        }
    }

}

2、添加注解@Primary

由于flowable-ui-modeler-rest中对SqlSessionTemplate和SqlSessionFactory注入添加了@Qualifier("flowableModeler"),所以不能通过只保留Mybatis自动注入的Bean。所以在这两个Bean注入的地方添加@Primary,让MyBatis自动注入的时候使用这个地方生成的bean,就不会报两个Bean不知道怎么选的错误。

Flowable-logic中对SqlSessionTemplate和SqlSessionFactory的注入代码如下

@Component
public class ModelHistoryRepositoryImpl implements ModelHistoryRepository {

    private static final String NAMESPACE = "org.flowable.ui.modeler.domain.ModelHistory.";

    @Autowired
    @Qualifier("flowableModeler")
    protected SqlSessionTemplate sqlSessionTemplate;
}

@Component
public class ModelRelationRepositoryImpl implements ModelRelationRepository {

    private static final String NAMESPACE = "org.flowable.ui.modeler.domain.ModelRelation.";

    @Autowired
    @Qualifier("flowableModeler")
    protected SqlSessionTemplate sqlSessionTemplate;
}
@Component
public class ModelRepositoryImpl implements ModelRepository {

    private static final String NAMESPACE = "org.flowable.ui.modeler.domain.Model.";

    @Autowired
    @Qualifier("flowableModeler")
    protected SqlSessionTemplate sqlSessionTemplate;
}

3、配置SqlSessionFactory提价ruoyi中mapper扫描

由于使用了该类中创建的SqlSessionFactory,所以需要将ruoyi中的mapper添加到该工厂下进行扫描。ruoyi中Mapper可以参考nacos数据库配置,配置如下

# mybatis配置
mybatis:
    # 搜索指定包别名
    typeAliasesPackage: com.ruoyi.system
    # 配置mapper的扫描,找到所有的mapper.xml映射文件
    mapperLocations: classpath:mapper/**/*.xml

注意:在添加扫描路径的时候,需要搜索指定包别名

具体修改代码如下

  sqlSessionFactoryBean.setConfigurationProperties(properties);
            //这个是原始代码,只添加flowable的扫描路径
//            sqlSessionFactoryBean
//                    .setMapperLocations(ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources("classpath:/META-INF/modeler-mybatis-mappings/*.xml"));
            //由于后面要设置该SqlSessionFactory为主要的SqlSessionFactory,
            // 然后Ruoyi中使用时Mybatis自动注入,所以在这个地方就需要添加Ruoyi配置扫描
            ResourcePatternResolver resourcePatternResolver = ResourcePatternUtils.getResourcePatternResolver(resourceLoader);
            List<Resource> allResourceList = new ArrayList<>();
            List<String> mapperLocations = new ArrayList<>();
            //先添加
            mapperLocations.add("classpath:/META-INF/modeler-mybatis-mappings/*.xml");
            mapperLocations.add("classpath*:/mapper/**/*Mapper.xml");

            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] resources = resourcePatternResolver.getResources(mapperLocation);
                    allResourceList.addAll(Arrays.asList(resources));
                } catch (Exception ex) {
                    throw new FlowableException("Could not create sqlSessionFactory", ex);
                }
            }
            Resource[] allResourceArr = allResourceList.toArray(new Resource[allResourceList.size()]);
            //因为若依中使用了类别名基础包,所以需要在这个地方进行添加
            sqlSessionFactoryBean.setTypeAliasesPackage(mybatisProperties.getTypeAliasesPackage());
            sqlSessionFactoryBean.setMapperLocations(allResourceArr);
            sqlSessionFactoryBean.afterPropertiesSet();
            return sqlSessionFactoryBean.getObject();

三、添加自动配置

1、添加自动配置类

由于在自己创建的子模块中添加了SecurityConfiguration安全配置类,然后该子模块要被其他模块进行依赖添加,所以需要添加自动配置类来扫描到自己添加的安全配置类

@Configuration
//这个地方通过配置扫描包的方式让SecurityConfiguration能被扫描到
//以后在该包下添加的类也会自动被扫描
@ComponentScan("com.ruoyi.flowable.modeler")
public class RuoyiFlowableModelerAutoConfiguration {

}

2、添加spring.factories文件

要在引用该模块时能完成该模块中的自动配置,需要添加spring.factories。在resources目录下创建META-INF文件夹,在该文件夹下创建spring.factories文件。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    com.ruoyi.flowable.modeler.config.RuoyiFlowableModelerAutoConfiguration

四、测试

在ruoyi-system中添加前面子模块的依赖,然后启动ruoyi-system模块。然后在浏览器中浏览http://localhost:9201/modeler得到如下如图标识添加Modeler成功

 

到此Ruoyi集成Flowable UI Modeler成功

Logo

快速构建 Web 应用程序

更多推荐