Skip to content

独立业务模块接入指南

sz-module-admin 是框架官方维护的核心模块,主要承载 RBAC、系统管理、认证授权、菜单、角色、字典等基础能力。二次开发时,不建议把客户自己的业务代码直接写进 sz-module-admin,否则后续同步官方版本时更容易产生冲突,也会让业务代码和框架核心耦合在一起。

推荐做法是:客户自有业务新建独立 sz-module-*,由 sz-service-admin 或自定义启动服务按需引入;前端较完整的业务域放到 src/modules/<domain>,再通过 edition 注册。这样官方核心、客户业务、派生产品组合入口都能保持清晰边界。

这套方式适合审计、代码生成器、SSO、商城、CRM、工单、物联网等具备独立边界的业务域。普通系统管理页面或很小的 CRUD 页面仍可继续放在 sz-module-admin 既有能力范围和前端 src/views 中,不需要为了模块化而强行拆分。

什么时候需要独立模块

判断是否要拆成独立模块,可以先看业务有没有“独立边界”。

适合独立模块的场景:

  • 可以按需启用或关闭,例如审计、代码生成器。
  • 有自己的 Controller、Service、Mapper、数据库表和初始化菜单。
  • 可能被不同派生项目复用。
  • 后续会由不同团队维护,或需要降低与官方核心模块的升级冲突。
  • 业务域比较完整,例如 SSO、CRM、商城、工单。

不一定要拆的场景:

  • 只是普通系统管理页面的小改动。
  • 只新增一两个轻量 CRUD,且明确属于现有后台管理能力。
  • 只是对已有 admin 页面做展示字段、查询条件或按钮调整。

官方 sz-module-audit 是一个很好的参考:它有自己的后端模块、API 前缀、表结构、菜单权限、前端页面和 HTTP client,但又不需要改动 sz-module-admin 的核心代码。

后端如何接入

模块放在哪里

审计模块位于 sz-module 下,与 sz-module-adminsz-module-generator 并列:

text
sz-module/
├── sz-module-admin       # 官方后台管理核心,客户业务不建议直接改这里
├── sz-module-audit       # 审计日志模块,独立维护 Controller / Mapper / Changelog
│   ├── pom.xml
│   └── src/main
│       ├── java/com/sz/audit
│       │   ├── config
│       │   └── controller
│       └── resources
│           ├── mapper
│           └── db/changelog
└── sz-module-generator   # 代码生成器模块

自有业务也按同样思路创建 sz-module-*。模块内放自己的业务实现,跨模块共享的接口、常量、轻量 DTO、事件和配置 key 再放到 sz-module-common

模块自己声明 API 前缀

独立模块不需要在 Controller 上手动拼全局前缀,而是通过 ApiPrefixRegister 声明模块编码、默认前缀和 Controller 扫描包。

审计模块的实际写法如下:

java
@Configuration
public class AuditApiPrefixConfiguration {

    @Bean
    public ApiPrefixRegister auditApiPrefixRegister() {
        return new ApiPrefixRegister() {
            @Override
            public String module() {
                // 对应 sz.api-prefix.modules.audit
                return "audit";
            }

            @Override
            public String prefix() {
                // 模块默认前缀,可在 application.yml 中覆盖
                return "/audit";
            }

            @Override
            public String[] basePackages() {
                // 只给审计模块自己的 Controller 加前缀
                return new String[] {"com.sz.audit.controller"};
            }
        };
    }
}

Controller 仍然只写模块内路径:

java
@RestController
@RequestMapping("sys-operation-log")
public class SysOperationLogController {
}

默认 server.servlet.context-path=/api 时,最终路径就是:

text
/api/audit/sys-operation-log

这种设计可以让每个模块维护自己的 API 命名空间,也方便前端、网关和权限按模块划分。

在启动服务里启用模块

独立模块本身不负责启动,它需要被 sz-service-admin 或其他启动服务装配。审计模块在 sz-service-admin/pom.xml 中引入:

xml
<dependency>
    <groupId>com.sz</groupId>
    <artifactId>sz-module-audit</artifactId>
    <version>${revision}</version>
</dependency>

模块前缀可以在 application.yml 中按环境覆盖:

yaml
sz:
  api-prefix:
    modules:
      audit:
        # 是否启用 audit 模块的 Controller 前缀注册
        enabled: true
        # 最终接口路径会叠加 server.servlet.context-path
        prefix: /audit

这里的 enabled: false 只是不注册该模块的 Controller 前缀,不等于完整卸载模块。如果项目明确不需要某个模块,应同时移除服务 POM 依赖、数据库 changelog、前端模块注册、菜单和代理配置。

模块维护自己的数据库脚本

独立模块建议维护自己的 Liquibase 入口。审计模块的入口是:

text
sz-module-audit/src/main/resources/db/changelog/module-audit-changelog.xml

启动服务的总 changelog 中按模块 include:

xml
<!-- sz-module-audit 模块,可选;如无需审计能力可注释该入口并移除模块依赖 -->
<include file="db/changelog/module-audit-changelog.xml" errorIfMissing="false"/>

审计模块初始化的内容包括 sys_operation_logsys_operation_log_detail、操作审计菜单、按钮权限和索引。自有模块也建议把表结构、菜单、按钮权限、字典来源、系统配置等初始化数据放进自己的 changelog,避免和官方 adminauditgenerator 数据混在一起。

前端如何接入

独立 HTTP client

后端拆了模块前缀后,前端也不要继续在业务 API 里手动拼模块前缀。审计模块使用独立的 auditHttp

ts
export const AUDIT_API_BASE = normalizeApiBase(import.meta.env.VITE_AUDIT_API_BASE, '/api/audit');

export const auditHttp = createHttp(AUDIT_API_BASE);

环境变量保持一致:

properties
VITE_AUDIT_API_BASE=/api/audit

业务 API 文件只写模块内路径:

ts
import { auditHttp } from '@/api/client';

export const getSysOperationLogListApi = (params: SysOperationLogQuery) => {
  // 实际请求路径:/api/audit/sys-operation-log
  return auditHttp.get<IPage<SysOperationLogRow>>('/sys-operation-log', params);
};

自有模块也按同样方式增加 xxxHttp,让 API 文件只关心模块内资源路径。

页面放到 src/modules

审计前端模块位于:

text
src/modules/audit/
├── api/sysOperationLog.ts
├── types/sysOperationLog.ts
├── views/sysOperationLog/index.vue
├── views/sysOperationLog/components/OperationLogDetail.vue
└── register.ts

src/modules/<domain> 适合放完整业务域。普通旧页面仍可留在 src/views,不用为了迁移而一次性改造。

用 register 连接菜单和页面

后端菜单里存的是 component 字段,前端需要把这个值解析到实际 Vue 页面。审计模块通过 register.ts 做显式映射:

ts
import { defineModule } from '@/core';

export const auditModule = defineModule({
  name: 'audit',
  components: {
    // 后端菜单 component 保持旧值,前端映射到新的模块页面
    '/system/sysOperationLog/index': () => import('./views/sysOperationLog/index.vue')
  }
});

显式映射适合兼容旧菜单。如果是全新的自有模块,也可以从一开始就让菜单 componentsrc/modules/<domain>/views/<rest>.vue 保持一致。

动态路由解析顺序是:

  1. 已注册模块的 components 显式映射。
  2. src/modules/<domain>/views/<rest>.vue 约定路径。
  3. src/views/<component>.vue 旧目录兜底。

在 edition 中启用模块

模块定义好之后,需要在当前产品 edition 中注册。默认后台 edition 文件位于:

text
src/editions/admin.ts

该文件导出前端产品组合对象 ADMIN_EDITIONsrc/main.ts 会导入 ADMIN_EDITION 并执行 ADMIN_EDITION.setup(),模块注册通常放在这个 setup() 方法里。

默认后台 edition 已注册 auditModule

ts
import { moduleRegistry } from '@/core';
import { auditModule } from '@/modules/audit/register';

export const ADMIN_EDITION = {
  id: 'admin',
  name: 'sz-admin',
  setup(): void {
    moduleRegistry.register(auditModule);
  }
};

edition 的作用是决定当前产品启用哪些登录适配器和业务模块。派生项目可以创建自己的 edition,只注册自己需要的模块,而不必改动框架主流程。

网关与部署同步

一个独立模块上线时,后端、前端和网关要保持同一套前缀。以审计模块为例:

位置审计模块配置
后端 sz.api-prefix.modules.audit.prefix/audit
前端 .env*VITE_AUDIT_API_BASE=/api/audit
Vite proxy代理 /api/audit/** 到后端
Nginx / 网关转发 /api/audit/**
菜单权限sys.operation.log.query_tablesys.operation.log.detail

如果线上出现 404,优先检查这几处是否一致。最常见的问题是后端前缀、前端 API base、Nginx location 三者只改了一部分。

不需要模块时怎么处理

独立模块可以按需启用,也可以按需移除。

如果只是临时不想开放菜单,可以不分配菜单权限或隐藏菜单。

如果不想启用某个模块的后端能力,应移除启动服务 POM 依赖,并同步处理 changelog、前端 edition 注册、菜单初始化数据和代理配置。

如果只是关闭模块前缀注册,可以设置:

yaml
sz:
  api-prefix:
    modules:
      audit:
        enabled: false

但要注意,这不是完整卸载模块,只是让该模块 Controller 不再注册对应前缀。

接入时核对

自有模块接入时,重点核对这些点即可:

  • 后端模块已加入聚合 POM,并被启动服务 POM 引入。
  • 模块提供 ApiPrefixRegistermodule()sz.api-prefix.modules.<module> 一致。
  • Controller 包名被 basePackages() 覆盖,最终路径符合 /api/<module>/** 预期。
  • Liquibase 入口已被服务 changelog include,初始化数据标明模块归属。
  • 前端新增对应 HTTP client、环境变量、API 文件和页面模块。
  • edition 已注册需要启用的业务模块。
  • 菜单 component 能命中模块注册表、src/modules 约定路径或 src/views 兜底路径。
  • Vite proxy、Nginx、Sa-Token 白名单、资源 base-url 和第三方回调已同步。

更多目录结构说明可阅读 目录结构,API 前缀配置可阅读 配置 - API 前缀说明,审计模块的业务功能说明可阅读 审计日志