# i-starter **Repository Path**: coder_hanbin/i-starter ## Basic Information - **Project Name**: i-starter - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-10-12 - **Last Updated**: 2026-10-15 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # i-starter **i-starter** 是一套面向中后台业务的**后端快速开发脚手架**,把「用户 / 角色 / 权限、组织架构、字典、系统配置、工作流审批、通知中心、监控运维」等每个项目都要重写一遍的能力沉淀为可直接复用的平台底座,让开发者只需专注业务模块本身。 它同时提供 PC 端与移动端两套前端工程,覆盖从本地开发到服务器部署的完整链路;业务模块按平台的分层规范手工开发,端到端步骤见 [如何从 0 手工新增一个带菜单的业务模块](docs/guides/add-menu-module-guide.md)。 > 本仓库是通用脚手架,不包含任何具体行业的业务代码。新增业务模块的方式见下文「[在脚手架上新增业务模块](#在脚手架上新增业务模块)」。 --- ## 技术栈 | 层级 | 技术 | 版本 | |------|------|------| | 后端框架 | Spring Boot | 3.4.4 | | ORM | Spring Data JPA (Hibernate) | 随 Spring Boot BOM | | 认证授权 | Sa-Token | 1.40.0 | | 数据库 | MySQL | 8.0 | | 连接池 / 监控 | Druid | 1.2.23 | | 缓存 | Redis(Spring Cache 唯一后端);Caffeine 仅用于限流 / 验证码 / 登录计数 | - | | 定时任务 | Quartz | 随 Spring Boot BOM | | Excel | EasyExcel | 4.0.3 | | API 文档 | SpringDoc OpenAPI | 2.8.6 | | 配置加密 | Jasypt | 3.0.5 | | 工具库 | Hutool | 5.8.36 | | PC 前端 | Umi 4 + React 18 + Ant Design + ProComponents | 4.x / 18.2 | | 移动端 | React + Vite + antd-mobile + TypeScript | 18.3 / 6.x / 5.x | | JDK | OpenJDK / Eclipse Temurin | 17 | --- ## 平台能力 **认证与权限** - 账号密码登录 / 登出,Sa-Token 令牌管理(`sa-token-redis-jackson` 在 classpath 上自动生效,会话存于 Redis) - 可选 CAS 单点登录(`app.cas.*` 配置,`login-mode` 支持 PC / 移动 / 双向,支持自动注册与角色白名单) - RBAC 权限模型:用户 / 角色 / 权限,接口级 `@SaCheckPermission` 鉴权 - 组织架构(部门树)、用户类型、数据字典、系统参数配置 - 移动端菜单配置、在线用户查询、密码重置与验证码 - 登录日志、操作审计日志、接口调用日志 **工作流引擎** - 流程定义 / 节点配置,发起流程、我的申请、我的待办 - 审批通过 / 驳回 / 转办、流程委托 - 业务回调(`WorkflowCallback` 扩展点,支持异步执行、重试与回调日志) - 超时提醒定时任务 **通知中心** - 通知模板、渠道配置、发送记录三件套 - 内置渠道:站内信、邮件、短信、微信模板消息、第三方渠道(`NotificationChannelSender` 可自行扩展) - WebSocket 实时推送 + 公告管理 **开发提效** - 异步任务中心:长任务异步执行、进度查询、启动恢复 - Excel 导入导出工具(EasyExcel 封装,支持必填列校验与样式) - 数据源管理:`sys_datasource` 表持久化 + `DatasourceRegistry` 运行时注册,支持列表查询与连接测试(详见 [数据源管理使用指南](docs/guides/multi-datasource-guide.md)) - 文件上传、大屏搭建(Big Screen 页面配置与数据接口) - 插件扩展点(`PluginRegistry`) **安全与运维** - XSS 过滤(`@XssIgnore` 可豁免)与接口限流(`@RateLimiter`) - 安全响应头、CORS 白名单、密码强度校验、敏感字段脱敏 - 服务器监控(CPU / 内存 / JVM / 磁盘,OSHI) - 缓存监控(Caffeine + Redis 缓存管理)、Druid SQL 监控 - Quartz 定时任务管理(在线新增 / 启停 / 立即执行 / 执行日志) - 数据库自动备份任务(备份结果可走通知中心邮件渠道推送) --- ## 模块结构 ``` i-starter/ ├── i-starter-core/ # 通用基础层:统一响应/异常、BaseEntity/BaseService、 │ # 审计与用户上下文、Redis/Jackson/CORS/限流/XSS 配置、 │ # 上传、Excel 基础组件、插件 SPI ├── i-starter-app/ # 应用启动层(Spring Boot 主类 + 平台功能模块) │ └── src/main/java/cn/qinsky/istarter/ │ ├── auth/ # 登录、CAS 单点登录、密码重置 │ ├── system/ # 用户/角色/权限/部门/字典/配置/用户类型/移动菜单/反馈/日志/公告/在线用户 │ ├── workflow/ # 工作流引擎(定义、实例、待办、回调、委托、超时任务) │ ├── notification/ # 通知中心(模板、渠道、记录、渠道发送器) │ ├── async/ # 异步任务中心 │ ├── job/ # Quartz 定时任务 + 数据库备份任务 │ ├── monitor/ # 服务器 / 缓存 / Druid 监控 │ ├── screen/ # 大屏页面搭建 │ ├── excel/ # 通用 Excel 导入导出接口 │ └── plugin/ # 插件接口 ├── frontend/ # PC 端:Umi 4 + React 18 + Ant Design + ProComponents(npm start / npm run build) ├── mobile/ # 移动端:React + Vite + antd-mobile + TypeScript(npm run dev / npm run build) ├── deploy/ # 传统部署脚本与配置(nginx / systemd / Windows bat / 打包脚本) ├── docker/ # Docker Compose 一键部署(MySQL + Redis + 后端 + Nginx 前端) ├── scripts/ # 构建、部署、备份、性能检查等辅助脚本;含数据库清理脚本(reset-factory-data.sql / system_clean.sql) ├── init.sql # 数据库一键初始化脚本(建表 + 出厂种子数据,可重复执行) └── docs/ # 架构与使用文档 ``` --- ## 快速开始 ### 1. 环境要求 | 依赖 | 版本 | |------|------| | JDK | 17(必需,Spring Boot 3.x 不支持 8/11) | | Maven | 3.8+ | | MySQL | 8.0 | | Node.js | 18+(前端 / 移动端构建) | | Redis | 7.0+(**必需**:所有 Profile 的 Spring Cache 后端都是 Redis,本地开发也需先启动 Redis) | ### 2. 创建数据库并导入初始化脚本 ```sql CREATE DATABASE istarter DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; ``` 仓库根目录的 `init.sql` 是**完整的一键初始化脚本**(由 `scripts/gen-ddl.sh` 从 JPA 实体导出生成,请勿手工修改):一次性创建平台**全部 32 张表**(含唯一键、外键、索引),并写入出厂种子数据(`admin` 账户、角色、权限与菜单、字典、系统参数、通知模板 / 渠道、定时任务、流程定义等)。脚本**不会删除任何数据**,建表用 `CREATE TABLE IF NOT EXISTS`、种子数据用 `INSERT IGNORE` / `NOT EXISTS` 守卫,可重复执行: ```bash mysql -uroot -p istarter < init.sql # 库中已有表 / 索引时,重复执行会报「对象已存在」;用 --force 忽略即可 mysql --force -uroot -p istarter < init.sql ``` > 该脚本已在空库上端到端验证:执行后得到 32 张表;再以 `--spring.profiles.active=prod`(`ddl-auto: validate`)启动不会出现 schema 校验错误,`POST /api/auth/login`(`admin` / `admin123`)可正常返回带权限的令牌。 > ⚠️ **会清空数据的脚本不在仓库根目录,而在 `scripts/` 下**: > - `scripts/reset-factory-data.sql`(由原 `scripts/system_init.sql` 更名而来):`TRUNCATE` 运行数据并重置自增 ID 的「恢复出厂」脚本; > - `scripts/system_clean.sql`:`DELETE` 运行数据、不重置自增 ID、整体包在事务中的清理脚本。 > > 两者都会删除运行数据且不可恢复,**仅用于交付 / 出包场景,切勿在生产库直接执行**;它们**不是**初始化步骤。 ### 3. 配置数据源 开发环境的数据库连接默认写在 `i-starter-app/src/main/resources/application.yml` 的 `spring.datasource` 下(默认 `jdbc:mysql://localhost:3306/istarter`,用户 `root`,密码取环境变量 `DB_PASSWORD`,缺省 `123456`): ```yaml spring: datasource: url: jdbc:mysql://localhost:3306/istarter?... username: root password: ${DB_PASSWORD:123456} ``` 可以按需在 `i-starter-app/src/main/resources/application-dev.yml` 中覆盖(该文件是 `dev` profile 的增量配置,只需写要覆盖的键,例如数据源、日志级别、`spring.jpa.show-sql` 等): ```yaml # application-dev.yml 示例 spring: datasource: url: jdbc:mysql://127.0.0.1:3306/istarter?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true username: root password: your_password logging: level: cn.qinsky.istarter: DEBUG ``` 也可以通过环境变量注入,无需改文件:`SPRING_DATASOURCE_HOST` / `SPRING_DATASOURCE_PORT` / `SPRING_DATASOURCE_DB` / `SPRING_DATASOURCE_USERNAME` / `SPRING_DATASOURCE_PASSWORD`。 > ⚠️ 这组 `SPRING_DATASOURCE_*` 变量**只在 `prod` profile 生效**(由 `application-prod.yml` 用 `${...}` 引用,密码无默认值,必须提供)。`dev` profile 下 `application.yml` 直接写死 `localhost` / `3306` / `istarter` / `root`,只读取密码变量 `DB_PASSWORD`(缺省 `123456`);要在本地改地址、库名或用户名,请改 `application.yml` 或 `application-dev.yml`。 环境 Profile 说明: | Profile | 配置文件 | 用途 | |---------|----------|------| | `dev`(默认) | `application-dev.yml` | 本地开发,`ddl-auto: update`,每次启动执行 `schema.sql` + `data.sql`(`spring.sql.init.mode: always`;data.sql 会把菜单名称/图标/排序重置为种子值,需保留手工调整时设 `DEV_SQL_INIT_MODE=never`) | | `test` | `application-test.yml` | 单元/集成测试,使用 H2 内存库,端口 9998,`ddl-auto: create-drop` | | `prod` | `application-prod.yml` | JAR **内置**生产配置:`ddl-auto: validate`、`spring.sql.init.mode: never`、关闭 Swagger | > ⚠️ 上表 `prod` 行描述的是 **JAR 内置**配置。传统部署流程(`deploy/`)启动时会额外用 `--spring.config.additional-location=file:./application-prod.yml` 加载外部 [deploy/application-prod.yml](deploy/application-prod.yml),后者优先级更高,并把 `spring.jpa.hibernate.ddl-auto` 默认覆盖为 `update`(可用 `JPA_DDL_AUTO=validate` 改回),以便「只建库、不导建表脚本」的首次启动也能自动建表。所以真实生产环境的建表行为由外部配置决定,而不是 JAR 内的 `validate`。 ### 4. 构建并启动后端 ```bash mvn clean package -DskipTests ``` > ⚠️ 本工程打包为 **thin JAR**:第三方依赖位于 `i-starter-app/target/lib/`,项目模块在 JAR 内,因此启动时必须用 `-Dloader.path` 指向 `lib/`。 ```bash # 方式一:从 target 目录启动(推荐) cd i-starter-app/target java -Dloader.path=lib/ -jar i-starter-app-*.jar # 方式二:从项目根目录启动 java -Dloader.path=i-starter-app/target/lib/ -jar i-starter-app/target/i-starter-app-*.jar # 指定环境 java -Dloader.path=i-starter-app/target/lib/ -jar i-starter-app/target/i-starter-app-*.jar --spring.profiles.active=prod ``` > ⚠️ **上传目录注意**:`app.upload-dir` 默认是 `${user.dir}/uploads`,即**相对于启动时的工作目录**。按上面「方式一」从 `i-starter-app/target` 启动时,上传目录会变成 `i-starter-app/target/uploads`,而 `mvn clean` 会连它一起删除,已上传的文件随之丢失。请显式覆盖到一个仓库外的固定目录: > > ```bash > java -Dloader.path=lib/ -jar i-starter-app-*.jar --app.upload-dir=/data/istarter/uploads > ``` > > (`prod` profile 内置 `app.upload-dir: /data/istarter/uploads`;传统部署由外部 `deploy/application-prod.yml` 的 `UPLOAD_DIR` 覆盖。) 启动后: | 地址 | 说明 | |------|------| | | 后端接口根路径(`server.servlet.context-path=/api`) | | | SpringDoc 接口文档(`prod` 环境关闭) | | | 健康检查 | ### 5. 默认登录账号 | 用户名 | 密码 | 说明 | |--------|------|------| | `admin` | `admin123` | 超级管理员,拥有全部权限 | > 首次登录后请立即修改密码;生产环境务必通过系统配置或数据库修改默认密码。 ### 6. 启动前端 ```bash cd frontend npm install npm start # 开发模式,默认 http://localhost:8000 npm run build # 生产构建,产物在 frontend/dist ``` ### 7. 启动移动端 ```bash cd mobile npm install npm run dev # 开发模式(Vite) npm run build # 生产构建,产物在 mobile/dist ``` --- ## 在脚手架上新增业务模块 以新增一个「订单管理」模块为例,采用手工开发方式,整体流程如下: 1. **建表**:在 MySQL 中创建业务表(建议带 `create_time` / `update_time` / `is_deleted` 字段,便于复用审计与软删除能力)。 2. **写后端代码**:在 `i-starter-app/src/main/java/cn/qinsky/istarter//` 下按 `entity` / `dto` / `repository` / `service` / `controller` 分层新增代码(包名默认 `cn.qinsky.istarter`,平台包名之外的模块同样会被 Spring 扫描到);DTO 至少包含 `VO` / `CreateReq` / `UpdateReq` / `Query` 四类。 3. **加权限码与菜单 SQL**:在 Controller 接口上标注 `@SaCheckPermission(":list")` 等权限码,并在权限种子 SQL(`data.sql` / `init.sql`)中补充目录、菜单、按钮三级菜单权限记录。 4. **写前端页面与路由**:在 `frontend/src/pages///` 下新增 `index.tsx`(ProTable 列表页)与 `service.ts`(API 封装),并在 `frontend/.umirc.ts` 中补充对应路由(走后端动态菜单时由权限数据下发菜单项)。 5. **授权并清权限缓存**:在「系统管理 → 角色管理」中为角色分配新增的菜单与按钮权限,然后清理权限缓存(`user:permissions`,清理方式见文末常见问题),否则鉴权仍会按旧权限集返回 403。 6. **验证**:重新登录确认左侧菜单出现 → 打开列表页验证分页查询 → 逐一验证新增 / 编辑 / 删除按钮及其接口鉴权。 7. **接入平台能力(按需)**: - 需要审批:实现 `WorkflowCallback`(参考 `workflow/callback/AbstractWorkflowCallback`)并在流程定义中绑定业务类型; - 需要长耗时操作:实现 `AsyncTaskHandler` 并注册到 `AsyncTaskHandlerRegistry`; - 需要发通知:调用 `NotificationSendService`,或配置通知模板 + 渠道; - 需要新增配置项:在 `application.yml` 的 `app.*` 下追加,或写入系统参数表由后台维护。 8. **通用基类**:实体继承 `BaseEntity` / `AuditableEntity`,Service 继承 `BaseService`,Controller 继承 `BaseController`,即可自动获得审计字段、分页、统一响应等能力;统一返回结构为 `Result`,分页返回 `Result>`(`BaseController.page`,Spring Data `Page` 的 JSON)。`PageResult` 虽在 `i-starter-core` 中有定义与单测,但生产代码未使用。 > 上述流程的建表字段约定、分层代码模板、权限码与菜单 SQL 写法、前端页面与路由配置、授权与缓存清理命令等细节,见 [如何从 0 手工新增一个带菜单的业务模块](docs/guides/add-menu-module-guide.md)。 > 建议将业务代码与平台代码分目录维护(如 `cn.qinsky.istarter.order`),平台升级时可最大程度减少冲突。 --- ## 部署 > 第一次部署请按逐步操作手册执行: > **单机部署(多数客户)** → [首次部署指南](docs/deployment/首次部署指南.md); > **容器化部署** → [Docker Compose 部署指南](docs/deployment/Docker部署指南.md)。 脚手架提供两种部署方式: ### 单机部署(Linux systemd / Nginx,Windows bat)—— 多数客户场景 1. 修改 `deploy/config/deploy.conf`(域名、端口、SSL 目录、上传目录); 2. 执行 `./deploy/build.sh all` 生成 `dist/istarter-linux.tar.gz` 与 `dist/istarter-windows.zip`; 3. Linux:上传产物 → `tar xzf` → `sudo ./setup-env.sh` 安装基础环境(Java 17 / MySQL 8 / Redis / Nginx)→ `sudo ./deploy-app.sh` 部署应用并注册 `istarter.service`; 4. Windows:解压 zip → 运行 `setup.bat` 初始化环境 → `start.bat` 启动。 SSL 证书放在 `deploy/ssl/`,命名规则见 `deploy/ssl/README.md`。 ### Docker Compose ```bash cd docker cp .env.example .env # 然后修改 MYSQL_ROOT_PASSWORD / MYSQL_DATABASE 等 docker compose up -d --build ``` 包含 MySQL 8、Redis 7、后端(`docker/backend/Dockerfile`,thin JAR + `lib/`)与 Nginx + 前端(`docker/frontend/Dockerfile`)四个服务;数据库由 MySQL 容器在首次启动时自动执行 `init.sql`。HTTPS 配置模板见 `docker/nginx/ssl.conf.template`,完整步骤见 [Docker Compose 部署指南](docs/deployment/Docker部署指南.md)。 > 反向代理(含 `docker/nginx/default.conf` 与 `deploy/nginx/*.conf`)已经用 `location ^~ /api/druid/ { deny all; }` 封堵 Druid 控制台;管理员请使用受 Sa-Token 保护的 `/api/druid-monitor/**`。HTTPS 部署还需设置 `SA_TOKEN_COOKIE_SECURE=true`。 --- ## 常见问题 **Q:PC 端和移动端在同一浏览器登录会互相踢下线吗?** 不会。移动端已改用独立存储键(`mobile_auth_token` / `mobile_current_user`,见 `mobile/src/utils/storageKeys.ts`),与 PC 端的 `auth_token` / `current_user` 互不干扰。 此前两端同名键会导致 PC 的令牌刷新定时器与移动端互相覆盖,表现为随机 401 掉线、任一端登出连带清掉另一端。 > **升级提示**:移动端用户需**重新登录一次**。旧键刻意不迁移也不删除 —— > 迁移等于让移动端继承 PC 的登录态,删除则会把同一浏览器里的 PC 会话踢下线。 > 注意:改键名只解决「互相覆盖」,**不解决同源 XSS 互读**(同源下 localStorage 全量可读,与键名无关)。 > 若需彻底隔离,应把 PC 端与移动端部署到**不同域名**(不同 origin)。 **Q:新增了权限码,为什么管理员仍然报 403「无此权限」?** `UserService.getPermissions()` 带 `@Cacheable("user:permissions")`,权限集缓存在 Redis 中, **TTL 约 30 分钟**。新增/调整 `@SaCheckPermission` 权限码或权限种子后,需清理该缓存才能立即生效: ```bash redis-cli --scan --pattern "*user:permissions*" | xargs -r redis-cli del ``` 或调用 `DELETE /api/system/monitor/cache` 清理应用缓存。 注意:`/api/auth/me` 走的是不带缓存的查询,因此它可能已显示新权限、而实际鉴权仍按旧缓存拒绝。 **Q:接口传错参数为什么返回 400 而不是 500?** `GlobalExceptionHandler` 对参数类型转换失败返回 400、路径不存在返回 404、请求方法不支持返回 405, 只有真正的服务端异常才返回 500「系统繁忙」。这样调用方能区分「接口用错了」与「服务端故障」。 --- ## 文档 更多架构与使用说明见 `docs/` 目录(架构设计、安全、配置加载、多数据源、工作流、通知等)。 ## 许可证 见 [LICENSE](LICENSE)。