flowable 达梦迁移

This commit is contained in:
chenbowen
2025-11-27 09:58:44 +08:00
parent 76eabb6db0
commit cd21239ff2
36 changed files with 1649 additions and 23 deletions

View File

@@ -8,17 +8,25 @@ import com.zt.plat.module.bpm.framework.flowable.core.event.BpmProcessInstanceEv
import com.zt.plat.module.system.api.user.AdminUserApi; import com.zt.plat.module.system.api.user.AdminUserApi;
import org.flowable.common.engine.api.delegate.FlowableFunctionDelegate; import org.flowable.common.engine.api.delegate.FlowableFunctionDelegate;
import org.flowable.common.engine.api.delegate.event.FlowableEventListener; import org.flowable.common.engine.api.delegate.event.FlowableEventListener;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.spring.SpringProcessEngineConfiguration; import org.flowable.spring.SpringProcessEngineConfiguration;
import org.flowable.spring.boot.EngineConfigurationConfigurer; import org.flowable.spring.boot.EngineConfigurationConfigurer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.ApplicationEventPublisher; import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncListenableTaskExecutor; import org.springframework.core.task.AsyncListenableTaskExecutor;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.List; import java.util.List;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.SQLException;
/** /**
* BPM 模块的 Flowable 配置类 * BPM 模块的 Flowable 配置类
@@ -28,6 +36,8 @@ import java.util.List;
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class BpmFlowableConfiguration { public class BpmFlowableConfiguration {
private static final Logger log = LoggerFactory.getLogger(BpmFlowableConfiguration.class);
/** /**
* 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean * 参考 {@link org.flowable.spring.boot.FlowableJobConfiguration} 类,创建对应的 AsyncListenableTaskExecutor Bean
* *
@@ -69,6 +79,37 @@ public class BpmFlowableConfiguration {
}; };
} }
@Bean
public EngineConfigurationConfigurer<SpringProcessEngineConfiguration> dmProcessEngineConfigurationConfigurer(DataSource dataSource) {
return configuration -> {
try {
configureDmCompatibility(configuration, dataSource);
} catch (SQLException ex) {
log.warn("Failed to inspect datasource for DM compatibility; Flowable will keep default settings", ex);
}
};
}
private void configureDmCompatibility(SpringProcessEngineConfiguration configuration, DataSource dataSource) throws SQLException {
Connection connection = null;
try {
connection = DataSourceUtils.getConnection(dataSource);
DatabaseMetaData metaData = connection.getMetaData();
String productName = metaData.getDatabaseProductName();
String jdbcUrl = metaData.getURL();
boolean dmProduct = productName != null && productName.toLowerCase().contains("dm");
boolean dmUrl = jdbcUrl != null && jdbcUrl.toLowerCase().startsWith("jdbc:dm");
if (!dmProduct && !dmUrl) {
return;
}
log.info("Detected DM database (product='{}'); enabling Flowable Oracle compatibility with automatic schema updates", productName);
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
configuration.setDatabaseType("oracle");
} finally {
DataSourceUtils.releaseConnection(connection, dataSource);
}
}
// =========== 审批人相关的 Bean ========== // =========== 审批人相关的 Bean ==========
@Bean @Bean

View File

@@ -8,6 +8,7 @@ package liquibase.database.core;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@@ -114,6 +115,7 @@ public class DmDatabase extends AbstractJdbcDatabase {
public void setConnection(DatabaseConnection conn) { public void setConnection(DatabaseConnection conn) {
this.reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER")); this.reservedWords.addAll(Arrays.asList("GROUP", "USER", "SESSION", "PASSWORD", "RESOURCE", "START", "SIZE", "UID", "DESC", "ORDER"));
Connection sqlConn = null; Connection sqlConn = null;
boolean dmDatabase = false;
if (!(conn instanceof OfflineConnection)) { if (!(conn instanceof OfflineConnection)) {
try { try {
if (conn instanceof JdbcConnection) { if (conn instanceof JdbcConnection) {
@@ -140,26 +142,42 @@ public class DmDatabase extends AbstractJdbcDatabase {
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set remarks reporting on OracleDatabase: " + e.getMessage()); Scope.getCurrentScope().getLog(this.getClass()).info("Could not set remarks reporting on OracleDatabase: " + e.getMessage());
} }
CallableStatement statement = null;
try { try {
statement = sqlConn.prepareCall("{call DBMS_UTILITY.DB_VERSION(?,?)}"); DatabaseMetaData metaData = sqlConn.getMetaData();
statement.registerOutParameter(1, 12); if (metaData != null) {
statement.registerOutParameter(2, 12); String productName = metaData.getDatabaseProductName();
statement.execute(); dmDatabase = productName != null && PRODUCT_NAME.equalsIgnoreCase(productName);
String compatibleVersion = statement.getString(2); if (dmDatabase) {
if (compatibleVersion != null) { this.databaseMajorVersion = metaData.getDatabaseMajorVersion();
Matcher majorVersionMatcher = VERSION_PATTERN.matcher(compatibleVersion); this.databaseMinorVersion = metaData.getDatabaseMinorVersion();
if (majorVersionMatcher.matches()) {
this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
} }
} }
} catch (SQLException e) { } catch (SQLException e) {
String message = "Cannot read from DBMS_UTILITY.DB_VERSION: " + e.getMessage(); Scope.getCurrentScope().getLog(this.getClass()).info("Unable to inspect database metadata for DM version detection: " + e.getMessage());
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: " + message); }
} finally {
JdbcUtil.closeStatement(statement); if (!dmDatabase) {
CallableStatement statement = null;
try {
statement = sqlConn.prepareCall("{call DBMS_UTILITY.DB_VERSION(?,?)}");
statement.registerOutParameter(1, 12);
statement.registerOutParameter(2, 12);
statement.execute();
String compatibleVersion = statement.getString(2);
if (compatibleVersion != null) {
Matcher majorVersionMatcher = VERSION_PATTERN.matcher(compatibleVersion);
if (majorVersionMatcher.matches()) {
this.databaseMajorVersion = Integer.valueOf(majorVersionMatcher.group(1));
this.databaseMinorVersion = Integer.valueOf(majorVersionMatcher.group(2));
}
}
} catch (SQLException e) {
String message = "Cannot read from DBMS_UTILITY.DB_VERSION: " + e.getMessage();
Scope.getCurrentScope().getLog(this.getClass()).info("Could not set check compatibility mode on OracleDatabase, assuming not running in any sort of compatibility mode: " + message);
} finally {
JdbcUtil.closeStatement(statement);
}
} }
if (GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue() != null) { if (GlobalConfiguration.DDL_LOCK_TIMEOUT.getCurrentValue() != null) {
@@ -266,7 +284,15 @@ public class DmDatabase extends AbstractJdbcDatabase {
} }
public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException { public boolean isCorrectDatabaseImplementation(DatabaseConnection conn) throws DatabaseException {
return "oracle".equalsIgnoreCase(conn.getDatabaseProductName()); String databaseProductName = conn == null ? null : conn.getDatabaseProductName();
if (databaseProductName == null) {
return false;
}
if (PRODUCT_NAME.equalsIgnoreCase(databaseProductName)) {
return true;
}
// Flowable 历史上将 DM 映射为 Oracle 元数据,因此这里同样接受 Oracle 以保持兼容
return "oracle".equalsIgnoreCase(databaseProductName);
} }
public String getDefaultDriver(String url) { public String getDefaultDriver(String url) {

View File

@@ -0,0 +1,32 @@
package liquibase.datatype.core;
import liquibase.database.Database;
import liquibase.database.core.DmDatabase;
import liquibase.datatype.DataTypeInfo;
import liquibase.datatype.DatabaseDataType;
@DataTypeInfo(
name = "boolean",
aliases = {"java.sql.Types.BOOLEAN", "java.lang.Boolean", "bit", "bool"},
minParameters = 0,
maxParameters = 0,
priority = 2
)
public class DmBooleanType extends BooleanType {
@Override
public boolean supports(Database database) {
if (database instanceof DmDatabase) {
return true;
}
return super.supports(database);
}
@Override
public DatabaseDataType toDatabaseDataType(Database database) {
if (database instanceof DmDatabase) {
return new DatabaseDataType("NUMBER", 1);
}
return super.toDatabaseDataType(database);
}
}

View File

@@ -13,6 +13,7 @@ liquibase.database.core.MariaDBDatabase
liquibase.database.core.MockDatabase liquibase.database.core.MockDatabase
liquibase.database.core.MySQLDatabase liquibase.database.core.MySQLDatabase
liquibase.database.core.OracleDatabase liquibase.database.core.OracleDatabase
liquibase.database.core.DmDatabase
liquibase.database.core.PostgresDatabase liquibase.database.core.PostgresDatabase
liquibase.database.core.SQLiteDatabase liquibase.database.core.SQLiteDatabase
liquibase.database.core.SybaseASADatabase liquibase.database.core.SybaseASADatabase

View File

@@ -0,0 +1 @@
liquibase.datatype.core.DmBooleanType

View File

@@ -39,14 +39,14 @@ spring:
primary: master primary: master
datasource: datasource:
master: master:
url: jdbc:mysql://172.16.46.247:4787/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 url: jdbc:dm://172.16.46.247:1050?schema=BPM
username: jygk-test username: SYSDBA
password: Zgty@0527 password: pgbsci6ddJ6Sqj@e
slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改 slave: # 模拟从库,可根据自己需要修改 # 模拟从库,可根据自己需要修改
lazy: true # 开启懒加载,保证启动速度 lazy: true # 开启懒加载,保证启动速度
url: jdbc:mysql://172.16.46.247:4787/ruoyi-vue-pro?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true&rewriteBatchedStatements=true # MySQL Connector/J 8.X 连接的示例 url: jdbc:dm://172.16.46.247:1050?schema=BPM
username: jygk-test username: SYSDBA
password: Zgty@0527 password: pgbsci6ddJ6Sqj@e
# Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优 # Redis 配置。Redisson 默认的配置足够使用,一般不需要进行调优
data: data:
@@ -56,6 +56,11 @@ spring:
database: 0 # 数据库索引 database: 0 # 数据库索引
# password: 123456 # 密码,建议生产环境开启 # password: 123456 # 密码,建议生产环境开启
# Flowable 在 DM 场景下需要识别为 Oracle 并自动升级表结构
flowable:
database-schema-update: true
database-type: oracle
--- #################### MQ 消息队列相关配置 #################### --- #################### MQ 消息队列相关配置 ####################
--- #################### 定时任务相关配置 #################### --- #################### 定时任务相关配置 ####################

View File

@@ -0,0 +1,41 @@
create table FLW_RU_BATCH (
ID_ VARCHAR2(64) not null,
REV_ INTEGER,
TYPE_ VARCHAR2(64) not null,
SEARCH_KEY_ VARCHAR2(255),
SEARCH_KEY2_ VARCHAR2(255),
CREATE_TIME_ TIMESTAMP(6) not null,
COMPLETE_TIME_ TIMESTAMP(6),
STATUS_ VARCHAR2(255),
BATCH_DOC_ID_ VARCHAR2(64),
TENANT_ID_ VARCHAR2(255) default '',
primary key (ID_)
);
create table FLW_RU_BATCH_PART (
ID_ VARCHAR2(64) not null,
REV_ INTEGER,
BATCH_ID_ VARCHAR2(64),
TYPE_ VARCHAR2(64) not null,
SCOPE_ID_ VARCHAR2(64),
SUB_SCOPE_ID_ VARCHAR2(64),
SCOPE_TYPE_ VARCHAR2(64),
SEARCH_KEY_ VARCHAR2(255),
SEARCH_KEY2_ VARCHAR2(255),
CREATE_TIME_ TIMESTAMP(6) not null,
COMPLETE_TIME_ TIMESTAMP(6),
STATUS_ VARCHAR2(255),
RESULT_DOC_ID_ VARCHAR2(64),
TENANT_ID_ VARCHAR2(255) default '',
primary key (ID_)
);
create index FLW_IDX_BATCH_PART on FLW_RU_BATCH_PART(BATCH_ID_);
alter table FLW_RU_BATCH_PART
add constraint FLW_FK_BATCH_PART_PARENT
foreign key (BATCH_ID_)
references FLW_RU_BATCH (ID_);
insert into ACT_GE_PROPERTY values ('batch.schema.version', '7.0.1.1', 1);

View File

@@ -0,0 +1,4 @@
drop index FLW_IDX_BATCH_PART;
drop table FLW_RU_BATCH_PART;
drop table FLW_RU_BATCH;

View File

@@ -0,0 +1,23 @@
create table ACT_GE_PROPERTY (
NAME_ VARCHAR2(64),
VALUE_ VARCHAR2(300),
REV_ INTEGER,
primary key (NAME_)
);
create table ACT_GE_BYTEARRAY (
ID_ VARCHAR2(64),
REV_ INTEGER,
NAME_ VARCHAR2(255),
DEPLOYMENT_ID_ VARCHAR2(64),
BYTES_ BLOB,
GENERATED_ NUMBER(1) CHECK (GENERATED_ IN (1,0)),
primary key (ID_)
);
insert into ACT_GE_PROPERTY
values ('common.schema.version', '7.0.1.1', 1);
insert into ACT_GE_PROPERTY
values ('next.dbid', '1', 1);

View File

@@ -0,0 +1,2 @@
drop table ACT_GE_BYTEARRAY;
drop table ACT_GE_PROPERTY;

Some files were not shown because too many files have changed in this diff Show More