Commit 88fd7b685a34f79500d3717af0a42f86d4b70006
1 parent
607b2e33
feat: 完善瀚高可选接入与信创兼容说明
Showing
6 changed files
with
223 additions
and
4 deletions
README.md
| ... | ... | @@ -47,7 +47,7 @@ |
| 47 | 47 | * 管理后台的电脑端:Vue3 提供 `element-plus`、`vben(ant-design-vue)` 两个版本,Vue2 提供 `element-ui` 版本 |
| 48 | 48 | * 管理后台的移动端:采用 `uni-app` 方案,一份代码多终端适配,同时支持 APP、小程序、H5! |
| 49 | 49 | * 后端采用 Spring Boot 多模块架构、MySQL + MyBatis Plus、Redis + Redisson |
| 50 | -* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB、国产达梦 DM、TiDB 等 | |
| 50 | +* 数据库可使用 MySQL、Oracle、PostgreSQL、SQL Server、MariaDB,以及达梦、人大金仓、瀚高等国产数据库,详见 [信创兼容与数据库支持](#-信创兼容与数据库支持) | |
| 51 | 51 | * 消息队列可使用 Event、Redis、RabbitMQ、Kafka、RocketMQ 等 |
| 52 | 52 | * 权限认证使用 Spring Security & Token & Redis,支持多终端、多种用户的认证系统,支持 SSO 单点登录 |
| 53 | 53 | * 支持加载动态权限菜单,按钮级别权限控制,Redis 缓存提升性能 |
| ... | ... | @@ -59,6 +59,22 @@ |
| 59 | 59 | * 集成阿里云、腾讯云等短信渠道,集成 MinIO、阿里云、腾讯云、七牛云等云存储服务 |
| 60 | 60 | * 集成报表设计器、大屏设计器,通过拖拽即可生成酷炫的报表与大屏 |
| 61 | 61 | |
| 62 | +## 🐲 信创兼容与数据库支持 | |
| 63 | + | |
| 64 | +支持国产操作系统、数据库和中间件,满足信创环境的部署需要: | |
| 65 | + | |
| 66 | +| 类别 | 支持 | 说明 | | |
| 67 | +|----------|-----------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------| | |
| 68 | +| 国产操作系统 | 银河麒麟、统信 UOS 等 Linux 系统 | 参考 [《Linux 部署》](https://doc.iocoder.cn/deployment-linux/),选择与 CPU 架构匹配的 JDK | | |
| 69 | +| 关系型数据库 | MySQL、MariaDB、Oracle、PostgreSQL、SQL Server | 默认使用 MySQL | | |
| 70 | +| 国产关系型数据库 | 达梦 DM、人大金仓 KingbaseES、openGauss、瀚高 HighGo、OceanBase、TiDB | 参考 [《国产信创数据库》](https://doc.iocoder.cn/xinchuang-db/) | | |
| 71 | +| 国产缓存 | 东方通 TongRDS、宝兰德 BES CacheDB | 替换 Redis,参考 [《国产信创数据库》](https://doc.iocoder.cn/xinchuang-db/)。BES CacheDB 提供接入说明,待介质验证 | | |
| 72 | +| 国产应用服务器 | 东方通 TongWeb、宝兰德 BES AppServer | 替换 Tomcat,参考 [《东方通服务器部署》](https://doc.iocoder.cn/deployment-tong/)、[《宝兰德服务器部署》](https://doc.iocoder.cn/deployment-bes/)。BES AppServer 提供接入说明,待介质验证 | | |
| 73 | +| 国产 Web 服务器 | 东方通 TongHttpServer | 替换 Nginx,提供静态资源、反向代理,参考 [《东方通服务器部署》](https://doc.iocoder.cn/deployment-tong/) | | |
| 74 | + | |
| 75 | +* 数据库脚本:[`sql`](sql/) 目录提供 MySQL、Oracle、PostgreSQL、SQL Server、达梦、人大金仓、openGauss、瀚高、OceanBase 的项目初始化脚本(含 Quartz),优先使用对应目录;MariaDB、TiDB 直接使用 MySQL 脚本 | |
| 76 | +* 其它数据库、后续表结构变更,可参考 [`sql/tools`](sql/tools/README.md) 的转换工具及 [《表结构变更(版本升级)》](https://doc.iocoder.cn/sql-update/#_3-数据库转换),转换后仍需按实际数据库调整、测试 | |
| 77 | + | |
| 62 | 78 | ## 🐳 项目关系 |
| 63 | 79 | |
| 64 | 80 |  | ... | ... |
sql/tools/README.md
| ... | ... | @@ -109,9 +109,17 @@ docker tag <image>:<tag> highgo:local |
| 109 | 109 | docker compose up -d highgo |
| 110 | 110 | ``` |
| 111 | 111 | |
| 112 | -> 注意:不同瀚高镜像的数据目录可能不同,如果容器无法启动,请按镜像实际 `PGDATA` 修改 `docker-compose.yaml` 中的 `highgo` 数据卷挂载目录。 | |
| 112 | +> 注意:`highgo` 服务属于 `highgo` profile,执行 `docker compose up -d` 时不会启动,需要像上面一样指定服务名。不同瀚高镜像的数据目录可能不同,如果容器无法启动,请按镜像实际 `PGDATA` 修改 `docker-compose.yaml` 中的 `highgo` 数据卷挂载目录。 | |
| 113 | 113 | |
| 114 | -③ 启动完成后,需要手动导入 Quartz 和项目 SQL。瀚高兼容 PostgreSQL,具体客户端命令以当前镜像为准,可使用 `psql` 或瀚高镜像内置的兼容客户端执行 `/tmp/quartz.sql`、`/tmp/schema.sql`。 | |
| 114 | +③ 初始化数据库:使用 `postgres:14.2` 镜像中的 `psql` 客户端,创建 `ruoyi-vue-pro` 数据库,并依次导入 `sql/highgo/quartz.sql`、`sql/highgo/ruoyi-vue-pro.sql`: | |
| 115 | + | |
| 116 | +```Bash | |
| 117 | +HIGHGO_PASSWORD='数据库密码' docker compose run --rm highgo-init | |
| 118 | +``` | |
| 119 | + | |
| 120 | +> 注意:默认使用瀚高的 `highgo` 账号连接 `highgo` 数据库执行建库,可以通过 `HIGHGO_USER`、`HIGHGO_MAINTENANCE_DB` 环境变量修改;密码以镜像或安装时的实际设置为准,脚本不会修改数据库的认证配置。初始化只允许创建全新的数据库:数据库已存在(包括空库)或重复执行时,脚本拒绝导入并返回非零状态;导入失败时保留数据库便于排查。该入口只适用于 PostgreSQL 客户端支持的认证方式(例如 md5、scram-sha-256),数据库开启 SM3 等专有认证时,请使用瀚高客户端手动执行上述两个 SQL 文件。 | |
| 121 | + | |
| 122 | +④ 项目可以使用 PostgreSQL JDBC 驱动(`jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro`),也可以使用瀚高 JDBC 驱动(`jdbc:highgo://127.0.0.1:5866/ruoyi-vue-pro`),两者都按 PostgreSQL 处理序列主键、Quartz 等差异,`url` 需要与 `driver-class-name` 配对。驱动需要引入到 `yudao-server/pom.xml` 的 `<dependencies>` 中:`yudao-spring-boot-starter-mybatis` 中的 `org.postgresql:postgresql` 是 `optional` 依赖,只在 `yudao-dependencies` 中声明版本也不会引入 jar 包。详见 [《国产信创数据库》](https://doc.iocoder.cn/xinchuang-db/#_4-highgo-瀚高数据库) 文档。 | |
| 115 | 123 | |
| 116 | 124 | ### 1.9 OceanBase |
| 117 | 125 | ... | ... |
sql/tools/docker-compose.yaml
| ... | ... | @@ -142,6 +142,7 @@ services: |
| 142 | 142 | # 使用瀚高官方提供的 Docker 镜像,加载后打成本地标签: |
| 143 | 143 | # docker tag <image>:<tag> highgo:local |
| 144 | 144 | image: highgo:local |
| 145 | + profiles: ["highgo"] | |
| 145 | 146 | restart: unless-stopped |
| 146 | 147 | ports: |
| 147 | 148 | - "5866:5866" |
| ... | ... | @@ -150,6 +151,26 @@ services: |
| 150 | 151 | - ../highgo/quartz.sql:/tmp/quartz.sql:ro |
| 151 | 152 | - ../highgo/ruoyi-vue-pro.sql:/tmp/schema.sql:ro |
| 152 | 153 | |
| 154 | + # 瀚高初始化:使用 PostgreSQL 客户端创建 ruoyi-vue-pro 数据库并导入 sql/highgo 脚本,只允许创建全新数据库 | |
| 155 | + # 只支持 PostgreSQL 客户端可用的认证方式(例如 md5、scram-sha-256),SM3 等专有认证请使用瀚高客户端手动导入 | |
| 156 | + # 执行:HIGHGO_PASSWORD='数据库密码' docker compose run --rm highgo-init | |
| 157 | + highgo-init: | |
| 158 | + image: postgres:14.2 | |
| 159 | + profiles: ["highgo-init"] | |
| 160 | + restart: "no" | |
| 161 | + environment: | |
| 162 | + HIGHGO_HOST: ${HIGHGO_HOST:-highgo} | |
| 163 | + HIGHGO_PORT: ${HIGHGO_PORT:-5866} | |
| 164 | + HIGHGO_USER: ${HIGHGO_USER:-highgo} | |
| 165 | + HIGHGO_PASSWORD: ${HIGHGO_PASSWORD:-} | |
| 166 | + HIGHGO_MAINTENANCE_DB: ${HIGHGO_MAINTENANCE_DB:-highgo} | |
| 167 | + HIGHGO_DATABASE: ruoyi-vue-pro | |
| 168 | + entrypoint: ["bash", "/tmp/create_schema.sh"] | |
| 169 | + volumes: | |
| 170 | + - ../highgo/quartz.sql:/tmp/quartz.sql:ro | |
| 171 | + - ../highgo/ruoyi-vue-pro.sql:/tmp/schema.sql:ro | |
| 172 | + - ./highgo/create_schema.sh:/tmp/create_schema.sh:ro | |
| 173 | + | |
| 153 | 174 | oceanbase: |
| 154 | 175 | image: oceanbase/oceanbase-ce:4.4.2-lts |
| 155 | 176 | restart: unless-stopped | ... | ... |
sql/tools/highgo/create_schema.sh
0 → 100644
| 1 | +#!/bin/bash | |
| 2 | +# 初始化瀚高测试库:使用 PostgreSQL 客户端 psql 创建全新的数据库并导入 sql/highgo 脚本,数据库已存在(包括空库)时拒绝导入;任一步骤失败都以非零状态退出 | |
| 3 | +# 只支持 PostgreSQL 客户端可用的认证方式(例如 md5、scram-sha-256);数据库开启 SM3 等瀚高专有认证时,请使用瀚高客户端手动导入 | |
| 4 | +set -euo pipefail | |
| 5 | + | |
| 6 | +host="${HIGHGO_HOST:-highgo}" | |
| 7 | +port="${HIGHGO_PORT:-5866}" | |
| 8 | +user="${HIGHGO_USER:-highgo}" | |
| 9 | +maintenance_db="${HIGHGO_MAINTENANCE_DB:-highgo}" | |
| 10 | +database="${HIGHGO_DATABASE:-ruoyi-vue-pro}" | |
| 11 | +export PGPASSWORD="${HIGHGO_PASSWORD:?HIGHGO_PASSWORD 未设置,请设置为瀚高数据库账号的实际密码}" | |
| 12 | +export PGCONNECT_TIMEOUT=5 | |
| 13 | +export PGOPTIONS="-c client_min_messages=warning" | |
| 14 | + | |
| 15 | +if [[ ! "${database}" =~ ^[A-Za-z0-9_-]+$ ]]; then | |
| 16 | + echo "数据库名 ${database} 不合法,只允许字母、数字、下划线和中划线" >&2 | |
| 17 | + exit 1 | |
| 18 | +fi | |
| 19 | + | |
| 20 | +client=(psql -h "${host}" -p "${port}" -U "${user}" -X -q -v ON_ERROR_STOP=1) | |
| 21 | + | |
| 22 | +# 1. 等待瀚高可连接 | |
| 23 | +for i in $(seq 1 60); do | |
| 24 | + if pg_isready -h "${host}" -p "${port}" -U "${user}" -d "${maintenance_db}" -q; then | |
| 25 | + break | |
| 26 | + fi | |
| 27 | + if [ "${i}" -eq 60 ]; then | |
| 28 | + echo "等待瀚高 ${host}:${port} 超时,请执行 docker compose logs highgo 检查启动日志" >&2 | |
| 29 | + exit 1 | |
| 30 | + fi | |
| 31 | + sleep 5 | |
| 32 | +done | |
| 33 | + | |
| 34 | +# 2. 校验账号、密码及认证方式 | |
| 35 | +if ! "${client[@]}" -d "${maintenance_db}" -c 'SELECT 1' >/dev/null; then | |
| 36 | + echo "无法使用账号 ${user} 登录 ${maintenance_db} 数据库:请检查 HIGHGO_USER、HIGHGO_PASSWORD、HIGHGO_MAINTENANCE_DB;如果数据库使用 SM3 等专有认证,请使用瀚高客户端手动导入" >&2 | |
| 37 | + exit 1 | |
| 38 | +fi | |
| 39 | + | |
| 40 | +# 3. 创建全新数据库:不判断是否存在,数据库已存在时直接失败,避免项目 SQL 中的 DROP TABLE 重建已有的同名表 | |
| 41 | +if ! "${client[@]}" -d "${maintenance_db}" -c "CREATE DATABASE \"${database}\";"; then | |
| 42 | + echo "创建数据库 ${database} 失败:只允许初始化全新的数据库,数据库已存在(包括空库)时拒绝导入;如需重新初始化,请删除瀚高数据卷后重建" >&2 | |
| 43 | + exit 1 | |
| 44 | +fi | |
| 45 | + | |
| 46 | +# 4. 按 quartz、ruoyi-vue-pro 的顺序导入脚本(ON_ERROR_STOP 遇到错误立即退出,失败时保留数据库,便于排查) | |
| 47 | +"${client[@]}" -d "${database}" -f /tmp/quartz.sql | |
| 48 | +"${client[@]}" -d "${database}" -f /tmp/schema.sql | |
| 49 | + | |
| 50 | +# 注意:瀚高的 information_schema.tables 对同名表可能返回多行,这里直接查 pg_class(每张表一行),只统计普通表、分区表 | |
| 51 | +table_count=$("${client[@]}" -d "${database}" -At -c "SELECT COUNT(*) FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = current_schema() AND c.relkind IN ('r', 'p');") | |
| 52 | +echo "瀚高初始化完成:数据库 ${database} 共 ${table_count} 张表" | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/util/JdbcUtils.java
| ... | ... | @@ -38,11 +38,14 @@ public class JdbcUtils { |
| 38 | 38 | /** |
| 39 | 39 | * 获得 URL 对应的 DB 类型 |
| 40 | 40 | * |
| 41 | + * 特殊:瀚高 HighGo 原生驱动(jdbc:highgo:)兼容 PostgreSQL,按 PostgreSQL 处理,复用其序列主键、Quartz 等适配 | |
| 42 | + * | |
| 41 | 43 | * @param url URL |
| 42 | 44 | * @return DB 类型 |
| 43 | 45 | */ |
| 44 | 46 | public static DbType getDbType(String url) { |
| 45 | - return com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url); | |
| 47 | + DbType dbType = com.baomidou.mybatisplus.extension.toolkit.JdbcUtils.getDbType(url); | |
| 48 | + return dbType == DbType.HIGH_GO ? DbType.POSTGRE_SQL : dbType; | |
| 46 | 49 | } |
| 47 | 50 | |
| 48 | 51 | /** | ... | ... |
yudao-framework/yudao-spring-boot-starter-mybatis/src/test/java/cn/iocoder/yudao/framework/mybatis/config/IdTypeEnvironmentPostProcessorTest.java
0 → 100644
| 1 | +package cn.iocoder.yudao.framework.mybatis.config; | |
| 2 | + | |
| 3 | +import cn.iocoder.yudao.framework.mybatis.core.util.JdbcUtils; | |
| 4 | +import com.baomidou.mybatisplus.annotation.DbType; | |
| 5 | +import com.baomidou.mybatisplus.extension.incrementer.PostgreKeyGenerator; | |
| 6 | +import org.junit.jupiter.api.AfterEach; | |
| 7 | +import org.junit.jupiter.api.BeforeEach; | |
| 8 | +import org.junit.jupiter.api.Test; | |
| 9 | +import org.springframework.core.env.MapPropertySource; | |
| 10 | +import org.springframework.core.env.StandardEnvironment; | |
| 11 | + | |
| 12 | +import java.util.HashMap; | |
| 13 | +import java.util.Map; | |
| 14 | + | |
| 15 | +import static org.junit.jupiter.api.Assertions.assertEquals; | |
| 16 | +import static org.junit.jupiter.api.Assertions.assertInstanceOf; | |
| 17 | +import static org.junit.jupiter.api.Assertions.assertNull; | |
| 18 | + | |
| 19 | +/** | |
| 20 | + * {@link IdTypeEnvironmentPostProcessor} 的单元测试 | |
| 21 | + * | |
| 22 | + * @author 芋道源码 | |
| 23 | + */ | |
| 24 | +public class IdTypeEnvironmentPostProcessorTest { | |
| 25 | + | |
| 26 | + private static final String ID_TYPE_KEY = "mybatis-plus.global-config.db-config.id-type"; | |
| 27 | + private static final String QUARTZ_DELEGATE_KEY = "spring.quartz.properties.org.quartz.jobStore.driverDelegateClass"; | |
| 28 | + private static final String POSTGRESQL_DELEGATE = "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate"; | |
| 29 | + | |
| 30 | + private final IdTypeEnvironmentPostProcessor processor = new IdTypeEnvironmentPostProcessor(); | |
| 31 | + | |
| 32 | + @BeforeEach | |
| 33 | + @AfterEach | |
| 34 | + public void clearQuartzDelegate() { | |
| 35 | + // Quartz Delegate 写入的是 JVM 系统属性,需要清理,避免影响其它用例 | |
| 36 | + System.clearProperty(QUARTZ_DELEGATE_KEY); | |
| 37 | + } | |
| 38 | + | |
| 39 | + @Test | |
| 40 | + public void testPostProcessEnvironment_highGoNativeUrl() { | |
| 41 | + // 准备参数 | |
| 42 | + StandardEnvironment environment = buildEnvironment("jdbc:highgo://127.0.0.1:5866/ruoyi-vue-pro", null); | |
| 43 | + | |
| 44 | + // 调用 | |
| 45 | + processor.postProcessEnvironment(environment, null); | |
| 46 | + | |
| 47 | + // 断言:与 PostgreSQL 一致,使用序列主键及 PostgreSQLDelegate | |
| 48 | + assertEquals("INPUT", environment.getProperty(ID_TYPE_KEY)); | |
| 49 | + assertEquals(POSTGRESQL_DELEGATE, environment.getProperty(QUARTZ_DELEGATE_KEY)); | |
| 50 | + assertInstanceOf(PostgreKeyGenerator.class, new YudaoMybatisAutoConfiguration().keyGenerator(environment)); | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Test | |
| 54 | + public void testPostProcessEnvironment_postgresqlUrl() { | |
| 55 | + // 准备参数 | |
| 56 | + StandardEnvironment environment = buildEnvironment("jdbc:postgresql://127.0.0.1:5866/ruoyi-vue-pro", null); | |
| 57 | + | |
| 58 | + // 调用 | |
| 59 | + processor.postProcessEnvironment(environment, null); | |
| 60 | + | |
| 61 | + // 断言 | |
| 62 | + assertEquals("INPUT", environment.getProperty(ID_TYPE_KEY)); | |
| 63 | + assertEquals(POSTGRESQL_DELEGATE, environment.getProperty(QUARTZ_DELEGATE_KEY)); | |
| 64 | + assertInstanceOf(PostgreKeyGenerator.class, new YudaoMybatisAutoConfiguration().keyGenerator(environment)); | |
| 65 | + } | |
| 66 | + | |
| 67 | + @Test | |
| 68 | + public void testPostProcessEnvironment_mysqlUrl() { | |
| 69 | + // 准备参数 | |
| 70 | + StandardEnvironment environment = buildEnvironment("jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro", null); | |
| 71 | + | |
| 72 | + // 调用 | |
| 73 | + processor.postProcessEnvironment(environment, null); | |
| 74 | + | |
| 75 | + // 断言:MySQL 保持自增主键,且不设置 Quartz Delegate | |
| 76 | + assertEquals("AUTO", environment.getProperty(ID_TYPE_KEY)); | |
| 77 | + assertNull(environment.getProperty(QUARTZ_DELEGATE_KEY)); | |
| 78 | + } | |
| 79 | + | |
| 80 | + @Test | |
| 81 | + public void testPostProcessEnvironment_highGoNativeUrlWithExplicitConfig() { | |
| 82 | + // 准备参数:用户显式配置主键策略及 Quartz Delegate | |
| 83 | + Map<String, Object> explicit = new HashMap<>(); | |
| 84 | + explicit.put(ID_TYPE_KEY, "ASSIGN_ID"); | |
| 85 | + explicit.put(QUARTZ_DELEGATE_KEY, "org.quartz.impl.jdbcjobstore.StdJDBCDelegate"); | |
| 86 | + StandardEnvironment environment = buildEnvironment("jdbc:highgo://127.0.0.1:5866/ruoyi-vue-pro", explicit); | |
| 87 | + | |
| 88 | + // 调用 | |
| 89 | + processor.postProcessEnvironment(environment, null); | |
| 90 | + | |
| 91 | + // 断言:不覆盖用户配置 | |
| 92 | + assertEquals("ASSIGN_ID", environment.getProperty(ID_TYPE_KEY)); | |
| 93 | + assertEquals("org.quartz.impl.jdbcjobstore.StdJDBCDelegate", environment.getProperty(QUARTZ_DELEGATE_KEY)); | |
| 94 | + assertNull(System.getProperty(QUARTZ_DELEGATE_KEY)); | |
| 95 | + } | |
| 96 | + | |
| 97 | + @Test | |
| 98 | + public void testGetDbType_onlyNormalizeHighGo() { | |
| 99 | + assertEquals(DbType.POSTGRE_SQL, JdbcUtils.getDbType("jdbc:highgo://127.0.0.1:5866/ruoyi-vue-pro")); | |
| 100 | + assertEquals(DbType.POSTGRE_SQL, JdbcUtils.getDbType("jdbc:postgresql://127.0.0.1:5432/ruoyi-vue-pro")); | |
| 101 | + assertEquals(DbType.MYSQL, JdbcUtils.getDbType("jdbc:mysql://127.0.0.1:3306/ruoyi-vue-pro")); | |
| 102 | + assertEquals(DbType.KINGBASE_ES, JdbcUtils.getDbType("jdbc:kingbase8://127.0.0.1:54321/test")); | |
| 103 | + assertEquals(DbType.DM, JdbcUtils.getDbType("jdbc:dm://127.0.0.1:5236?schema=RUOYI_VUE_PRO")); | |
| 104 | + } | |
| 105 | + | |
| 106 | + private static StandardEnvironment buildEnvironment(String url, Map<String, Object> extra) { | |
| 107 | + Map<String, Object> properties = new HashMap<>(); | |
| 108 | + properties.put("spring.datasource.dynamic.primary", "master"); | |
| 109 | + properties.put("spring.datasource.dynamic.datasource.master.url", url); | |
| 110 | + properties.put(ID_TYPE_KEY, "NONE"); | |
| 111 | + if (extra != null) { | |
| 112 | + properties.putAll(extra); | |
| 113 | + } | |
| 114 | + StandardEnvironment environment = new StandardEnvironment(); | |
| 115 | + environment.getPropertySources().addLast(new MapPropertySource("test", properties)); | |
| 116 | + return environment; | |
| 117 | + } | |
| 118 | + | |
| 119 | +} | ... | ... |