v2.0.0(20260529)
IMPORTANT
v2.0.0 基于 v1.3.4-beta 之后的实际代码变化整理。本版本包含大量不兼容升级,涉及后端模块结构、数据库 ID、Liquibase、密码加密、前端依赖升级、前端 API 前缀和动态路由。存量系统升级前必须先完成备份和测试库演练。
1. 升级前检查
1.1 必备备份
升级前至少备份以下内容:
- 生产数据库完整备份。
config/{profile}下所有后端配置。- 上传资源目录或 OSS bucket 关键对象。
- 前端
.env*配置和 Nginx 配置。 - 所有自定义后端业务代码、前端页面和生成器模板。
- 当前运行版本 tag、commit、构建产物和回滚脚本。
1.2 推荐升级策略
v2.0.0 不建议直接在生产库原地执行迁移。推荐流程:
- 使用 v2.0.0 代码创建全新测试库。
- 通过 Liquibase 初始化 v2.0.0 表结构和初始化数据。
- 将 v1.3.4-beta 生产库数据导入影子库。
- 编写或人工执行数据映射脚本,重点处理 ID、用户、角色、菜单、部门、字典、资源、生成器表。
- 在影子环境完成后端启动、前端登录、权限、菜单、字典、数据权限、上传、导入导出、生成器回归。
- 通过演练结果决定生产迁移窗口和回滚方案。
- 如需同步角色授权和数据权限范围,可在完成菜单、角色基础数据迁移后,使用角色管理中的 SQL 导出能力生成
sys_role_menu/sys_data_role_relation辅助脚本。
2. 后端模块结构迁移
v2.0.0 后端主结构调整为:
sz-boot-parent
├── sz-common # 通用技术能力
├── sz-module # 业务模块
└── sz-service # 启动服务关键变化:
| v1.3.4-beta | v2.0.0 | 说明 |
|---|---|---|
sz-service/sz-service-admin 承载大量业务实现 | sz-module/sz-module-admin 承载 admin 业务实现 | 服务层职责收敛为启动装配 |
sz-common-generator | sz-module/sz-module-generator | 代码生成器迁移到业务模块层 |
MySQL 数据库能力集中在 sz-common-db-mysql | sz-common-db-core + sz-common-db-mysql / sz-common-db-postgresql | 公共流程与方言实现拆分 |
| 业务常量散落 | sz-module-common | 统一承载跨模块契约、配置 key、字典常量 |
自定义业务迁移建议:
- 不要继续把新业务写入
sz-service-admin。 sz-module-admin是官方核心模块,主要承载 RBAC、系统管理、认证授权、菜单、角色、字典等基础能力。客户自有业务不建议直接改入该模块,否则后续同步官方版本时更容易产生冲突。- 独立业务域建议新建
sz-module-*,再由sz-service-admin或自定义服务引入。这样官方核心、客户业务和派生产品组合入口可以保持清晰边界。 - 跨模块共享 DTO、接口、字典常量、配置 key 放入
sz-module-common。
独立业务模块的完整接入流程见 独立业务模块接入指南。
3. Spring Boot 4 与依赖升级
后端已升级到 Spring Boot 4.0.6,并同步调整依赖:
| 组件 | v2.0.0 当前值 |
|---|---|
| Java | 21 |
| Spring Boot | 4.0.6 |
| Sa-Token | 1.45.0 |
| Jackson | 3.1.3 |
| MyBatis-Flex | 1.11.7 |
| HikariCP | 7.0.2 |
| Springdoc OpenAPI | 2.8.14 |
迁移注意:
- 自定义 starter、拦截器、Jackson 序列化配置需要按 Spring Boot 4 / Jackson 3 检查。
- 旧依赖若只支持 Spring Boot 3,需要升级或替换。
- 后端编译建议先执行
mvn -pl sz-service/sz-service-admin -am compile -DskipTests。
4. Liquibase 与数据库迁移
v2.0.0 使用模块级 Liquibase:
sz-service/sz-service-admin/src/main/resources/db/changelog/changelog-master.xml
sz-module/sz-module-admin/src/main/resources/db/changelog/module-admin-changelog.xml
sz-module/sz-module-audit/src/main/resources/db/changelog/module-audit-changelog.xml
sz-module/sz-module-generator/src/main/resources/db/changelog/module-generator-changelog.xml目录按能力拆分:
framework:框架核心表和必要初始化数据。audit:操作审计、性能日志、异常日志相关表和菜单权限。generator:代码生成器表和初始化数据。demo:演示数据,可按环境决定是否启用。
升级存量库时重点检查:
- 旧表是否已存在,是否会与 v2.0.0 初始化 changeSet 冲突。
- 主键和关联字段是否需要从自增/字符串迁移为
Long。 sys_menu、sys_role_menu、sys_dept、sys_user_role、sys_user_dept、sys_dict、sys_dict_type、sys_resource是否有自定义数据。- 审计表
sys_operation_log、sys_operation_log_detail是 v2.0.0 新增能力,存量库通常不需要迁移历史数据,但需要评估表空间、保留周期和清理策略。 - 生成器相关表是否需要重建或导入。
WARNING
v2.0.0 的 changelog 更适合初始化新库。存量库建议先在影子库中验证“初始化新库 + 数据迁移”的方案,不建议未经演练直接在生产库执行。
4.1 数据库迁移脚本免责声明
CAUTION
下方脚本是辅助脚本,用于帮助你在测试库中盘点差异、补齐 v2.0.0 必要基础结构或生成迁移映射。它们无法覆盖所有用户的二开字段、历史数据、索引命名、约束命名和业务规则。请务必先在备份库或影子库执行,确认结果后再决定是否用于生产。不要在未备份的生产库直接执行。
建议执行顺序:
- 先备份旧库。
- 在测试环境执行“结构盘点脚本”。
- 使用 v2.0.0 初始化一个新库。
- 对比旧库与新库结构。
- 按业务数据情况选择“保留旧 ID”或“重建雪花 ID 映射”。
- 执行字典来源补齐脚本。
- 检查字典静态缓存与动态字典按需加载是否符合预期,必要时清理 Redis 中的
sys_dict、sys_dict:static_loaded、sys_dict:static_types。 - 手工检查菜单、角色、部门、字典、用户、资源、生成器表。
4.2 备份命令
MySQL:
mysqldump -h 127.0.0.1 -P 3306 -u root -p \
--single-transaction --routines --triggers --events \
--databases sz_admin_preview \
> sz_admin_preview_v134_backup.sqlPostgreSQL:
pg_dump -h 127.0.0.1 -p 5432 -U postgres \
--format=custom --blobs --verbose \
--file=sz_admin_preview_v134_backup.dump \
sz_admin_preview4.3 结构盘点脚本
MySQL 8:
-- v2_precheck_mysql.sql
-- 用途:盘点 v1.3.4-beta 存量库中 v2.0.0 重点关注的表和字段。
-- 执行:mysql -h127.0.0.1 -uroot -p sz_admin_preview < v2_precheck_mysql.sql
SELECT DATABASE() AS current_database, VERSION() AS mysql_version;
SELECT table_name
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name IN (
'sys_user', 'sys_role', 'sys_menu', 'sys_role_menu',
'sys_dept', 'sys_dept_closure', 'sys_user_role', 'sys_user_dept',
'sys_dict', 'sys_dict_type', 'sys_dict_source',
'sys_resource', 'generator_table', 'generator_table_column'
)
ORDER BY table_name;
SELECT table_name, column_name, column_type, is_nullable, column_key
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name IN ('sys_dict_type', 'sys_dict', 'sys_user', 'sys_menu', 'sys_role')
AND column_name IN ('id', 'source_code', 'sys_dict_type_id', 'pwd', 'password', 'component', 'parent_id')
ORDER BY table_name, ordinal_position;
SELECT 'sys_dict_type without source_code' AS item, COUNT(*) AS count_value
FROM sys_dict_type
WHERE NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'sys_dict_type'
AND column_name = 'source_code'
);PostgreSQL:
-- v2_precheck_postgresql.sql
-- 执行:psql -h 127.0.0.1 -U postgres -d sz_admin_preview -f v2_precheck_postgresql.sql
SELECT current_database() AS current_database, version() AS postgresql_version;
SELECT table_name
FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name IN (
'sys_user', 'sys_role', 'sys_menu', 'sys_role_menu',
'sys_dept', 'sys_dept_closure', 'sys_user_role', 'sys_user_dept',
'sys_dict', 'sys_dict_type', 'sys_dict_source',
'sys_resource', 'generator_table', 'generator_table_column'
)
ORDER BY table_name;
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name IN ('sys_dict_type', 'sys_dict', 'sys_user', 'sys_menu', 'sys_role')
AND column_name IN ('id', 'source_code', 'sys_dict_type_id', 'pwd', 'password', 'component', 'parent_id')
ORDER BY table_name, ordinal_position;4.4 迁移映射表脚本
如果你的旧库 ID 已经是 BIGINT 且没有冲突,可以优先保留旧 ID,降低关系表迁移成本。若必须重排 ID,请先建立映射表,再按映射更新关系表。
MySQL 8:
-- v2_id_map_mysql.sql
-- 用途:为后续人工或脚本化迁移准备 ID 映射表。
-- new_id 默认先等于 old_id;如需重排雪花 ID,请先更新本表 new_id,再迁移关系表。
CREATE TABLE IF NOT EXISTS sz_migration_id_map (
table_name VARCHAR(64) NOT NULL,
old_id VARCHAR(64) NOT NULL,
new_id BIGINT NOT NULL,
remark VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (table_name, old_id)
);
INSERT IGNORE INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_user', CAST(id AS CHAR), id, '用户'
FROM sys_user
WHERE id IS NOT NULL;
INSERT IGNORE INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_role', CAST(id AS CHAR), id, '角色'
FROM sys_role
WHERE id IS NOT NULL;
INSERT IGNORE INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_menu', CAST(id AS CHAR), id, '菜单'
FROM sys_menu
WHERE id IS NOT NULL;
INSERT IGNORE INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_dept', CAST(id AS CHAR), id, '部门'
FROM sys_dept
WHERE id IS NOT NULL;
INSERT IGNORE INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_dict_type', CAST(id AS CHAR), id, '字典类型'
FROM sys_dict_type
WHERE id IS NOT NULL;PostgreSQL:
-- v2_id_map_postgresql.sql
CREATE TABLE IF NOT EXISTS sz_migration_id_map (
table_name VARCHAR(64) NOT NULL,
old_id VARCHAR(64) NOT NULL,
new_id BIGINT NOT NULL,
remark VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (table_name, old_id)
);
INSERT INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_user', id::text, id, '用户'
FROM sys_user
WHERE id IS NOT NULL
ON CONFLICT (table_name, old_id) DO NOTHING;
INSERT INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_role', id::text, id, '角色'
FROM sys_role
WHERE id IS NOT NULL
ON CONFLICT (table_name, old_id) DO NOTHING;
INSERT INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_menu', id::text, id, '菜单'
FROM sys_menu
WHERE id IS NOT NULL
ON CONFLICT (table_name, old_id) DO NOTHING;
INSERT INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_dept', id::text, id, '部门'
FROM sys_dept
WHERE id IS NOT NULL
ON CONFLICT (table_name, old_id) DO NOTHING;
INSERT INTO sz_migration_id_map (table_name, old_id, new_id, remark)
SELECT 'sys_dict_type', id::text, id, '字典类型'
FROM sys_dict_type
WHERE id IS NOT NULL
ON CONFLICT (table_name, old_id) DO NOTHING;5. 全局 ID 迁移
v2.0.0 将大量 ID 统一为雪花 Long,由 sz-common-db-core 中的 SzIdGenerator 提供。
雪花 ID 的运行期参数位于各环境 config/{profile}/mybatis-flex.yml:
sz:
id:
worker-id: ${SZ_WORKER_ID:1}
datacenter-id: ${SZ_DATACENTER_ID:1}这两个配置会被 SzSnowflakeProperties 读取,并在 MybatisFlexConfiguration 中创建全局 Snowflake 与 MyBatis-Flex KeyGenerator。它们只影响升级后新写入数据的 ID 生成,不会自动改造旧库 ID。配置细节见 配置 - mybatis-flex.yml,实体主键写法见 规范 - 主键ID 与全局雪花ID策略。
CAUTION
生产或预览环境多节点部署时,必须为每个节点显式设置不同的 SZ_WORKER_ID / SZ_DATACENTER_ID 组合。升级演练时也建议按真实部署拓扑配置,避免上线后才暴露雪花 ID 冲突。
需要重点处理:
- Java 实体、DTO、VO 中的 ID 类型。
- 前端 API 类型中的 ID 类型。
- 数据库主键、外键和关系表字段。
- 菜单、角色、部门、用户、字典、资源、生成器等初始化数据。
如果旧系统中有字符串 ID 或自增 ID,建议建立 ID 映射表:
| old_id | new_id | table_name | remark |
|---|
迁移关系表时必须使用映射后的新 ID,避免角色菜单、用户角色、用户部门、部门闭包关系断裂。
6. 密码加密迁移
v2.0.0 密码加密切换为 BcryptUtils,旧密码规则与新规则不兼容。
可选方案:
| 方案 | 说明 | 适用场景 |
|---|---|---|
| 全员重置密码 | 升级后统一重置为临时密码,用户首次登录后修改 | 内部系统、用户量可控 |
| 管理员按需重置 | 保留账号,用户登录失败后由管理员重置 | 用户量较少 |
| 临时兼容旧密码 | 登录时先校验 BCrypt,失败后尝试旧算法,成功后重写为 BCrypt | 用户量较大,但需要额外开发 |
当前官方代码已切换为新规则,升级文档不假设存在旧密码兼容逻辑。
7. MySQL / PostgreSQL 切换
v2.0.0 支持 MySQL 和 PostgreSQL,但二者不是运行时随意混用。
7.1 配置数据库类型
application.yml:
DB_TYPE: mysql # 可选 mysql / postgresql
spring:
config:
import:
- file:config/${spring.profiles.active}/${DB_TYPE}.yml7.2 选择数据库模块
sz-service/sz-service-admin/pom.xml 中只保留一个数据库实现:
<!-- MySQL -->
<dependency>
<groupId>com.sz</groupId>
<artifactId>sz-common-db-mysql</artifactId>
<version>${project.version}</version>
</dependency>
<!-- PostgreSQL:使用时启用,并注释 MySQL 依赖 -->
<!--
<dependency>
<groupId>com.sz</groupId>
<artifactId>sz-common-db-postgresql</artifactId>
<version>${project.version}</version>
</dependency>
-->WARNING
sz-common-db-mysql 和 sz-common-db-postgresql 不应同时启用,否则数据权限方言可能冲突。
8. 数据权限迁移与行为变化
v2.0.0 的数据权限主流程已经合并到 系统角色授权 中。旧版若曾使用独立数据角色、数据权限管理菜单或自定义数据角色表,需要按新模型重新梳理。
核心变化:
| 旧口径 | v2.0.0 当前口径 | 迁移建议 |
|---|---|---|
| 独立数据角色 / 数据权限角色 | 系统角色在具体菜单上的数据范围配置 | 将旧数据角色能力映射到 sys_role_menu.permission_type = scope |
| 独立数据权限菜单 | 菜单管理 use_data_scope 开关 + 角色管理授权弹窗 | 需要数据权限的菜单设置 sys_menu.use_data_scope = 'T' |
| 自定义部门/用户范围 | sys_data_role_relation 保存角色 + 菜单 + 用户/部门关系 | 自定义范围迁移时必须同时写入 role_id、menu_id、relation_type_cd、relation_id |
| 手工控制数据过滤 | Service 层使用 DataScopeSession 或 SimpleDataScopeHelper 开启上下文 | 只对需要过滤的查询显式开启,避免误伤所有查询 |
WARNING
旧表中的 sys_data_role、sys_data_role_menu 如果仍存在,不应继续作为 v2.0.0 官网主流程描述。当前后端以 SysRoleMenuServiceImpl、sys_role_menu、sys_data_role_relation 为准。
8.1 数据权限结构检查脚本
以下脚本用于在测试库中盘点数据权限相关字段,不会修改数据。
MySQL 8:
SELECT table_name, column_name, column_type, is_nullable
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND (
(table_name = 'sys_menu' AND column_name = 'use_data_scope')
OR (table_name = 'sys_role_menu' AND column_name IN ('permission_type', 'data_scope_cd', 'menu_id', 'role_id'))
OR (table_name = 'sys_data_role_relation' AND column_name IN ('role_id', 'menu_id', 'relation_type_cd', 'relation_id'))
)
ORDER BY table_name, ordinal_position;
SELECT use_data_scope, COUNT(*) AS menu_count
FROM sys_menu
GROUP BY use_data_scope;
SELECT permission_type, data_scope_cd, COUNT(*) AS relation_count
FROM sys_role_menu
GROUP BY permission_type, data_scope_cd
ORDER BY permission_type, data_scope_cd;PostgreSQL:
SELECT table_name, column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_schema = 'public'
AND (
(table_name = 'sys_menu' AND column_name = 'use_data_scope')
OR (table_name = 'sys_role_menu' AND column_name IN ('permission_type', 'data_scope_cd', 'menu_id', 'role_id'))
OR (table_name = 'sys_data_role_relation' AND column_name IN ('role_id', 'menu_id', 'relation_type_cd', 'relation_id'))
)
ORDER BY table_name, ordinal_position;
SELECT use_data_scope, COUNT(*) AS menu_count
FROM sys_menu
GROUP BY use_data_scope;
SELECT permission_type, data_scope_cd, COUNT(*) AS relation_count
FROM sys_role_menu
GROUP BY permission_type, data_scope_cd
ORDER BY permission_type, data_scope_cd;8.2 迁移建议
- 先确认哪些菜单确实需要数据权限,将这些菜单的
use_data_scope设置为T。 - 将旧数据角色对应的范围映射到系统角色。如果一个旧数据角色被多个用户共用,建议先确认它应合并到哪个
sys_role。 - 对非自定义范围,在
sys_role_menu中写入一条permission_type = 'scope'、data_scope_cd = 1006001~1006004的记录。 - 对自定义范围,在
sys_role_menu中写入data_scope_cd = 1006005,并在sys_data_role_relation中写入部门/用户明细。 - 确认对应 Controller 方法存在
@SaCheckPermission,且权限标识能映射到开启数据权限的菜单。 - 确认 Service 查询中使用
DataScopeSession(YourEntity.class)或SimpleDataScopeHelper.start(YourEntity.class)。 - 迁移后清理 Redis 中旧的登录 Session,让用户重新登录后重新计算
LoginUser.dataScope。
TIP
代码生成器的“自动创建数据权限”默认会为生成菜单设置 use_data_scope,并在生成 Service 模板中写入 DataScopeSession。对手写模块,也应按同样规则补齐菜单开关、角色范围和 Service 查询上下文。
8.3 角色-权限 SQL 迁移脚本便捷导出
v2.0.0 在角色管理中新增角色-权限脚本导出能力,对应后端接口 POST /sys-role/menu/script/export,权限点为 sys.role.sql_btn。该能力用于把某个角色当前已配置的功能权限、菜单级数据权限范围和自定义范围明细导出为可预览、可复制的 SQL / Liquibase XML。
导出脚本覆盖的核心表:
sys_role_menu:角色与菜单、按钮权限、菜单级数据权限范围的关系,包含role_id、permission_type、menu_id、data_scope_cd。sys_data_role_relation:当数据范围为“自定义”时,记录角色在指定菜单下关联的部门或用户明细,包含role_id、menu_id、relation_type_cd、relation_id。
推荐使用方式:
- 先完成目标环境的
sys_role、sys_menu、sys_dept、sys_user等基础数据迁移或初始化。 - 确认目标环境与导出环境的角色 ID、菜单 ID、部门 ID、用户 ID 是否一致;如果不一致,先使用迁移映射表或人工映射方案修正脚本中的 ID。
- 在源环境的角色管理中选择目标角色,导出角色-权限脚本,并按目标数据库选择 SQL 方言。
- 检查脚本中的
sys_role_menu和sys_data_role_relation是否符合预期,尤其是permission_type = 'scope'与自定义范围数据。 - 先在影子库或测试库回放脚本,确认菜单显示、按钮权限、数据权限查询都正确后,再决定是否用于生产迁移。
CAUTION
角色-权限导出脚本不是全量 RBAC 迁移工具。它不会创建角色、菜单、部门或用户,只负责辅助迁移角色与权限、数据范围之间的关系。若目标库 ID 与源库 ID 不一致,必须先完成 ID 映射,否则可能把权限授给错误的角色、菜单或部门。生产环境执行前仍需备份并在影子库验证。
回放后可使用下面的检查 SQL 做基础核对:
-- v2_role_permission_after_import_check.sql
-- 用途:核对角色权限脚本回放后,sys_role_menu 与 sys_data_role_relation 的基础分布。
SELECT role_id, permission_type, data_scope_cd, COUNT(*) AS row_count
FROM sys_role_menu
GROUP BY role_id, permission_type, data_scope_cd
ORDER BY role_id, permission_type, data_scope_cd;
SELECT
srm.role_id,
srm.menu_id,
srm.data_scope_cd,
COUNT(sdr.id) AS custom_relation_count
FROM sys_role_menu srm
LEFT JOIN sys_data_role_relation sdr
ON sdr.role_id = srm.role_id
AND sdr.menu_id = srm.menu_id
WHERE srm.permission_type = 'scope'
GROUP BY srm.role_id, srm.menu_id, srm.data_scope_cd
ORDER BY srm.role_id, srm.menu_id;9. 字典来源(sys_dict_source)迁移与新功能
v2.0.0 新增 sys_dict_source 字典来源管理,用于给字典类型划分来源和 ID 区间。它解决的是“框架内置字典”和“业务自定义字典”混在一起后难以治理的问题。
默认来源:
| source_code | source_name | ID 区间 | 说明 |
|---|---|---|---|
framework | 框架内置 | 1000-1999 | 官方保留字典来源 |
custom | 业务自定义 | 2000-2999 | 默认业务字典来源 |
相关变化:
- 新增表
sys_dict_source。 sys_dict_type新增source_code字段。- 官方内置字典类型默认归属
framework。 - 业务新增字典建议归属
custom或自行扩展新的来源区间。 - 字典类型 ID 建议继续采用“4 位类型 ID + 3 位字典项序号”的可读规则,例如类型
2001下的字典项可使用2001001。
TIP
截图占位:后续可补充“字典来源列表页”“新增/编辑字典来源弹窗”“字典类型关联来源字段”的截图。
9.1 MySQL 补齐脚本
-- v2_dict_source_mysql.sql
-- 用途:在存量库中补齐 sys_dict_source 表和 sys_dict_type.source_code 字段。
-- 执行前必须备份数据库,并确认 sys_dict_type 不存在自定义同名字段。
START TRANSACTION;
CREATE TABLE IF NOT EXISTS sys_dict_source (
id BIGINT NOT NULL COMMENT '主键ID',
source_code VARCHAR(64) NOT NULL COMMENT '来源编码',
source_name VARCHAR(64) NOT NULL COMMENT '来源名称',
start_id BIGINT NOT NULL COMMENT '起始ID',
end_id BIGINT NOT NULL COMMENT '结束ID',
status VARCHAR(1) NOT NULL DEFAULT 'T' COMMENT '状态',
remark VARCHAR(255) NOT NULL DEFAULT '' COMMENT '备注',
create_time DATETIME NULL COMMENT '创建时间',
update_time DATETIME NULL COMMENT '更新时间',
create_id BIGINT NULL COMMENT '创建人ID',
update_id BIGINT NULL COMMENT '更新人ID',
PRIMARY KEY (id),
UNIQUE KEY uk_sys_dict_source_code (source_code)
) COMMENT='字典来源表';
INSERT INTO sys_dict_source
(id, source_code, source_name, start_id, end_id, status, remark, create_time, update_time, create_id, update_id)
VALUES
(1, 'framework', '框架内置', 1000, 1999, 'T', '框架保留来源,对应 1000-1999 区间', NOW(), NOW(), 1, 1),
(2, 'custom', '业务自定义', 2000, 2999, 'T', '业务默认来源,对应 2000-2999 区间', NOW(), NOW(), 1, 1)
ON DUPLICATE KEY UPDATE
source_name = VALUES(source_name),
start_id = VALUES(start_id),
end_id = VALUES(end_id),
status = VALUES(status),
remark = VALUES(remark),
update_time = NOW();
DELIMITER //
CREATE PROCEDURE sz_add_dict_type_source_code()
BEGIN
IF NOT EXISTS (
SELECT 1
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 'sys_dict_type'
AND column_name = 'source_code'
) THEN
ALTER TABLE sys_dict_type
ADD COLUMN source_code VARCHAR(64) NOT NULL DEFAULT '' COMMENT '所属来源';
END IF;
END//
DELIMITER ;
CALL sz_add_dict_type_source_code();
DROP PROCEDURE sz_add_dict_type_source_code;
UPDATE sys_dict_type
SET source_code = CASE
WHEN id BETWEEN 1000 AND 1999 THEN 'framework'
WHEN id BETWEEN 2000 AND 2999 THEN 'custom'
ELSE 'custom'
END
WHERE source_code IS NULL OR source_code = '';
COMMIT;9.2 PostgreSQL 补齐脚本
-- v2_dict_source_postgresql.sql
BEGIN;
CREATE TABLE IF NOT EXISTS sys_dict_source (
id BIGINT PRIMARY KEY,
source_code VARCHAR(64) NOT NULL,
source_name VARCHAR(64) NOT NULL,
start_id BIGINT NOT NULL,
end_id BIGINT NOT NULL,
status VARCHAR(1) NOT NULL DEFAULT 'T',
remark VARCHAR(255) NOT NULL DEFAULT '',
create_time TIMESTAMP,
update_time TIMESTAMP,
create_id BIGINT,
update_id BIGINT
);
CREATE UNIQUE INDEX IF NOT EXISTS uk_sys_dict_source_code
ON sys_dict_source (source_code);
INSERT INTO sys_dict_source
(id, source_code, source_name, start_id, end_id, status, remark, create_time, update_time, create_id, update_id)
VALUES
(1, 'framework', '框架内置', 1000, 1999, 'T', '框架保留来源,对应 1000-1999 区间', NOW(), NOW(), 1, 1),
(2, 'custom', '业务自定义', 2000, 2999, 'T', '业务默认来源,对应 2000-2999 区间', NOW(), NOW(), 1, 1)
ON CONFLICT (source_code) DO UPDATE SET
source_name = EXCLUDED.source_name,
start_id = EXCLUDED.start_id,
end_id = EXCLUDED.end_id,
status = EXCLUDED.status,
remark = EXCLUDED.remark,
update_time = NOW();
ALTER TABLE sys_dict_type
ADD COLUMN IF NOT EXISTS source_code VARCHAR(64) NOT NULL DEFAULT '';
UPDATE sys_dict_type
SET source_code = CASE
WHEN id BETWEEN 1000 AND 1999 THEN 'framework'
WHEN id BETWEEN 2000 AND 2999 THEN 'custom'
ELSE 'custom'
END
WHERE source_code IS NULL OR source_code = '';
COMMIT;9.3 字典迁移建议
- 如果你的项目没有自定义字典,执行 v2.0.0 初始化数据即可。
- 如果已有自定义字典类型,建议将
id >= 2000的业务字典归属custom。 - 如果业务字典已经占用了 1000-1999 区间,需要先盘点冲突,再决定是否重排 ID。
- 如果多个业务模块各自维护字典,建议新增来源,例如
sso、shop、crm,并规划不同 ID 区间。
9.4 字典加载与缓存行为变化
v2.0.0 对字典加载链路做了进一步优化。当前推荐理解为:
| 能力 | 当前接口 / 实现 | 说明 |
|---|---|---|
| 查询全部字典 | GET /sys-dict/dict | 返回静态字典 + 动态字典,适合管理端全量需要的场景 |
| 查询静态字典 | GET /sys-dict/static | 只返回 sys_dict_type / sys_dict 维护的静态字典,前端路由初始化时用于预热 |
| 批量按类型查询 | GET /sys-dict/code?typeCode=account_status&typeCode=dynamic_user_options | 按需查询一个或多个 typeCode,动态字典也走该入口 |
| 后端加载器 | DictLoaderFactory | 动态字典按完整 dynamic_* typeCode 精确命中,静态字典交给默认 DefaultStaticDictLoader |
| Redis 标记 | sys_dict、sys_dict:static_loaded、sys_dict:static_types | 静态字典全量预热后记录已加载状态和静态类型列表 |
前端 optionsStore 也同步调整:
- 路由初始化时优先调用
getStaticDict(),预热静态字典。 - 页面调用
useDictOptions(typeCode)时,如果该类型未加载或已过期,会通过getDictByCode按需补拉。 - Store 内部维护
loadedTypes、expiredTypes、loadingTypes,避免同一个字典类型重复并发请求。 - 收到 WebSocket
SYNC_DICT后,会标记已加载字典过期,再重新预热静态字典。
迁移注意事项:
- 旧前端如果仍只依赖
GET /sys-dict/dict全量返回,短期仍可使用;新页面建议改为useDict/useDictOptions,让静态字典预热与动态字典按需加载协同工作。 - 自定义动态字典必须实现
DynamicDictLoader#getTypeCode()与getTypeName(),最终完整 typeCode 会自动加上dynamic_前缀;不同动态加载器的完整 typeCode 不能重复。 - 如果升级后发现字典下拉仍是旧数据,先清理 Redis 中的
sys_dict、sys_dict:static_loaded、sys_dict:static_types,再重新登录或等待 WebSocket 同步。
10. API 前缀与前端调用迁移
后端新增 API 前缀配置:
sz:
api-prefix:
modules:
admin:
enabled: true
prefix: /admin
audit:
enabled: true
prefix: /audit
generator:
enabled: true
prefix: /generator前端新增独立 HTTP 实例:
import { adminHttp } from '@/api/client';
import { auditHttp } from '@/api/client';
import { generatorHttp } from '@/api/client';旧写法:
import http from '@/api';
import { ADMIN_MODULE } from '@/api/helper/prefix';
export const getUserPage = params => http.get(ADMIN_MODULE + '/sys-user/page', params);新写法:
import { adminHttp } from '@/api/client';
export const getUserPage = params => adminHttp.get('/sys-user/page', params);生成器接口使用:
import { generatorHttp } from '@/api/client';
export const getGeneratorPage = params => generatorHttp.get('/generator-table/page', params);审计接口使用:
import { auditHttp } from '@/api/client';
export const getOperationLogPage = params => auditHttp.get('/sys-operation-log', params);后端模块前缀由各模块通过 ApiPrefixRegister 声明默认值,配置文件中的 sz.api-prefix.modules.<module>.prefix 用于按环境覆盖。新增自定义业务模块时,应同步补充后端前缀、前端 HTTP client、Vite proxy 和 Nginx location。
11. 前端环境变量迁移
旧版常见配置:
VITE_API_URL=http://127.0.0.1:9991/apiv2.0.0 改为:
VITE_ADMIN_API_BASE=/api/admin
VITE_AUDIT_API_BASE=/api/audit
VITE_GENERATOR_API_BASE=/api/generator
VITE_API_PROXY_TARGET=http://127.0.0.1:9991
VITE_SOCKET_URL=ws://127.0.0.1:9993/socket
VITE_APP_CLIENT_ID=195da9fcce574852b850068771cde034
VITE_ADMIN_BYPASS_PERMISSION=true生产环境需要同步 Nginx:
location /api/admin/ {
proxy_pass http://sz-service-admin:9991/api/admin/;
}
location /api/audit/ {
proxy_pass http://sz-service-admin:9991/api/audit/;
}
location /api/generator/ {
proxy_pass http://sz-service-admin:9991/api/generator/;
}11.1 前端依赖与构建环境升级
本次前端待提交代码包含一次集中依赖升级,升级后请先确认本机、CI 和部署环境的 Node / pnpm 版本,再安装依赖。
| 项目 | 旧版本/旧口径 | 新版本/新口径 | 迁移注意 |
|---|---|---|---|
| Node.js | Node 20 泛版本或 Node 18 类型配置 | >=20.19.0,CI 示例使用 20.19.5 | package.json 已声明 engines.node,低版本 Node 可能无法运行 Vite 7。 |
| pnpm | 未锁定或 9.x 口径 | pnpm@10.17.1 | package.json 已声明 packageManager,建议使用 Corepack 或全局安装指定版本。 |
| Vite | 6.4.2 | 7.3.3 | 本地开发、CI、Docker 构建需要同步 Node 版本;Vite proxy 仍按 API base 动态生成。 |
| @vitejs/plugin-vue | 6.0.6 | 6.0.7 | 与 Vite 7 配套。 |
| vite-plugin-vue-devtools | 7.7.9 | 8.1.2 | 仅影响开发调试能力。 |
| Vue | ^3.5.33 | ^3.5.35 | 保持 Vue 3.5 主线。 |
| Element Plus | ^2.13.7 | ^2.14.0 | 升级后重点回归表单、表格、弹窗和上传组件。 |
| Pinia | ^2.3.1 | ^3.0.4 | Store 写法保持 Composition API 风格。 |
| pinia-plugin-persistedstate | ^3.2.3 | ^4.7.1 | 持久化配置字段由 paths 调整为 pick,二开 store 若使用旧字段需要同步修改。 |
| Vue Router | ^4.6.4 | ^5.0.7 | 升级后重点回归动态路由、标签页、KeepAlive 和登录回跳。 |
| Axios | 1.15.2 | 1.16.1 | 继续通过统一 HTTP 实例处理业务码、401 和 blob 错误。 |
| @vueuse/core | ^10.11.1 | ^14.3.0 | 使用组合式工具的自定义页面需做类型检查。 |
| Sass | ~1.87.0 | ~1.100.0 | 当前 Vite 配置使用 api: 'modern-compiler'。 |
推荐本地处理步骤:
corepack enable
corepack prepare pnpm@10.17.1 --activate
pnpm install --frozen-lockfile
pnpm type-check
pnpm build如果你的二开项目维护了自定义 Pinia store,请重点搜索 paths:、PersistedStateOptions 等旧写法,并改为当前 pinia-plugin-persistedstate v4 的 pick / PersistenceOptions 口径。
12. 审计日志模块迁移与启用
v2.0.0 新增独立审计模块,用于沉淀操作审计、性能日志和异常日志。全新安装时,Liquibase 会创建 sys_operation_log、sys_operation_log_detail,并初始化“操作审计”菜单和按钮权限;存量升级时,一般不迁移历史操作日志,而是从启用 v2.0.0 后开始记录新数据。
启用步骤:
- 确认
sz-service-admin已引入sz-module-audit。 - 确认
application.yml导入config/${spring.profiles.active}/audit-log.yml。 - 在环境配置中保留或调整
sz.api-prefix.modules.audit.prefix=/audit。 - 前端配置
VITE_AUDIT_API_BASE=/api/audit,并同步 Vite proxy / Nginx / 网关。 - 为角色分配
sys.operation.log.query_table和sys.operation.log.detail权限。 - 进入“操作审计”页面,分别验证审计日志、性能日志、异常日志和详情抽屉。
生产注意:
record-response-body默认关闭,排障时再临时开启。sql-mode=all不建议长期用于生产,可优先使用off或临时slow。- 审计日志会持续增长,上线前应规划保留周期、归档或清理任务。
- 请求参数、响应体和异常堆栈可能包含敏感信息,二开接口仍应避免把密码、密钥、令牌等字段写入审计明细。
完整使用说明见 审计日志。
13. 前端模块化与路由迁移
v2.0.0 新增 src/core 和 src/editions:
src/core/ # 登录适配器、模块注册、菜单组件解析
src/editions/ # 产品组合入口
src/modules/ # 可组合业务模块动态路由解析顺序:
- 已注册模块的
components映射。 src/modules/<domain>/views/<rest>.vue。- 旧目录
src/views/<component>.vue。
迁移建议:
- 普通旧页面可以暂时保留在
src/views。 - 新增较大业务模块建议放入
src/modules/<domain>。 - 派生项目需要在 edition 中注册业务模块。
- 后端菜单
component字段必须与前端可解析路径一致。
14. WebSocket 迁移
v2.0.0 前后端 WebSocket 均有重构:
- 前端增加心跳和鉴权关闭码处理。
- 后端使用
Sec-WebSocket-Protocol传递 token。 - 鉴权失效关闭码为
4401。 - 心跳消息使用
PING/PONG。 - 前端将 axios 业务码
C105、blob 下载错误中的登录失效、HTTP 401 和 WebSocket4401收敛到src/core/authSession.ts,避免多处重复清理登录态。
升级后需要验证:
- 未配置
VITE_SOCKET_URL时前端不应建立连接。 - token 失效时前端能停止重连、清理登录态并跳转登录页。
- 登录失效跳转是否带上
back参数,重新登录后是否能回到原目标页面。 - 字典、权限、配置同步消息能被正确处理。
15. 代码生成器迁移
后端配置示例:
sz:
generator:
path:
web:
api:
module-name: sz-module
service-name: sz-module-admin
global:
author: sz-admin
packages: com.sz.admin变化点:
- 后端模块从
sz-common-generator迁移为sz-module-generator。 - 生成目标模块默认从
sz-service调整为sz-module。 - 生成服务名默认从
sz-service-admin调整为sz-module-admin。 - 前端生成器页面位于
src/modules/toolbox。 - 支持 MySQL / PostgreSQL 元数据读取和 Liquibase 初始化脚本生成。
16. 新功能与行为变化速览
本节帮助你快速理解 v2.0.0 不只是“改目录”,还新增或改变了哪些面向使用者的能力。
| 类型 | 变化 | 迁移/使用建议 |
|---|---|---|
| 新功能 | 字典来源管理 sys_dict_source | 先补齐来源表和 sys_dict_type.source_code,再规划业务字典区间 |
| 新功能 | 审计日志 | 启用 sz-module-audit、audit-log.yml 和 VITE_AUDIT_API_BASE,上线前规划日志保留周期 |
| 新功能 | 脚本预览与导出 | 用于菜单、字典、角色-权限等初始化或迁移脚本确认;角色-权限导出重点核对 sys_role_menu 与 sys_data_role_relation |
| 新功能 | PostgreSQL 支持 | 通过 DB_TYPE + 数据库模块二选一启用 |
| 新功能 | 前端 edition / module 注册 | 派生项目通过 edition 注册登录适配器和业务模块 |
| 改变 | 前端构建链升级到 Vite 7 / Node 20.19+ / pnpm 10.17.1 | 先升级本机和 CI 环境,再执行 pnpm install --frozen-lockfile、pnpm type-check、pnpm build |
| 改变 | API 前缀拆分为 admin/audit/generator | 前端接口迁移为 adminHttp / auditHttp / generatorHttp |
| 改变 | 字典加载拆分为静态预热 + 按类型按需加载 | 自定义动态字典需保证完整 dynamic_* typeCode 唯一;升级后可清理字典 Redis 缓存验证 |
| 改变 | 数据权限合并到系统角色授权 | 不再按独立数据角色作为官网主流程,重点迁移 sys_role_menu 与 sys_data_role_relation |
| 改变 | WebSocket 心跳、关闭码与会话过期统一处理 | 重点验证 axios C105 / HTTP 401 / WebSocket 4401 都能清理登录态并跳转登录 |
| 改变 | 全局错误码前缀 | 通用错误为 C,Admin 为 A,Resource 为 R |
| 兼容 | 旧 src/views 页面仍可兜底解析 | 新业务建议迁移到 src/modules/<domain> |
| 不兼容 | 密码加密改为 BCrypt | 存量用户需重置或开发兼容登录 |
TIP
截图占位:后续可补充“脚本预览弹窗”“字典来源管理”“审计日志三页签”“前端模块路由未命中 warn”“WebSocket 鉴权失效重登”的截图。
17. 验证清单
后端:
mvn -pl sz-service/sz-service-admin -am compile -DskipTests前端:
pnpm install --frozen-lockfile
pnpm type-check
pnpm build重点业务回归:
- 登录、退出、token 失效。
- 菜单加载、动态路由、按钮权限。
- 用户、角色、部门、菜单、字典、参数管理。
- 字典静态预热、指定类型按需加载、WebSocket 字典同步与 Redis 字典缓存清理。
- 审计日志、性能日志、异常日志列表与详情;确认
traceId、慢操作阈值、异常堆栈和权限按钮可用。 - 数据权限范围查询。
- 角色-权限脚本导出、SQL 方言切换、目标库回放和权限重新登录生效。
- 文件上传、资源访问、导入导出。
- WebSocket 鉴权、心跳、字典/权限/配置同步、会话过期统一跳转和
back参数回跳。 - 代码生成器导入表、预览、生成、菜单初始化。
