# springboot **Repository Path**: my919/springboot ## Basic Information - **Project Name**: springboot - **Description**: No description available - **Primary Language**: Unknown - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-05-16 - **Last Updated**: 2026-05-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # Springboot Demo 基于 **Spring Boot 4** 的后端示例项目:MyBatis-Flex 通用 CRUD、动态多数据源、全局枚举与字典、统一异常与校验、AOP 日志、防重与幂等、Redis/缓存、RustFS 对象存储、Spring Boot Admin 监控等。 ## 搭建文档(分模块) 按功能拆分的搭建流程与博客式说明见 **[docs/](./docs/springboot.md)**(各 md 含 Hexo Front Matter,可复制至 `_posts`),例如: - [集成 RustFS](./docs/集成RustFS.md) · [集成 Redis 与缓存](./docs/集成Redis与缓存.md) - [全局枚举与字典 API](./docs/全局枚举与字典API.md) · [防重提交与接口幂等](./docs/防重提交与接口幂等.md) - [多环境配置](./docs/多环境配置.md) · [springboot 总览与索引](./docs/springboot.md) ## 项目简介 标准三层架构(Controller → Service → Mapper)。业务 Controller 继承 `BaseFlexCrudController` 提供分页与 CRUD;HTTP 统一使用 `Result`,异常由 `GlobalExceptionHandler` 转为相同结构;跨域、多环境、操作/请求日志、防重复提交与接口幂等均已内置。 ### 技术栈 | 类别 | 技术 | |----------|------------------------------------------------------| | 核心 | Spring Boot 4.0.6、Java 21、Gradle | | Web | Spring WebMVC、Validation、SpringDoc OpenAPI 3、全局 CORS | | 持久层 | MyBatis-Flex、dynamic-datasource、HikariCP | | 数据库 | MySQL、PostgreSQL(动态数据源切换) | | 缓存 / 分布式 | Spring Cache、Redis、Redisson | | AOP | Spring AspectJ(请求日志、操作日志、防重、幂等) | | 对象存储 | RustFS(S3 兼容,AWS SDK for Java v2) | | 监控 | Spring Boot Actuator、Spring Boot Admin 4 | | JSON | Jackson 3(`tools.jackson`) | | 工具 | Lombok、Hutool | ### 目录结构 ``` src/main/java/org/my919/springboot/ ├── annotation/ # @OperLog、@RepeatSubmit、@Idempotent ├── aspect/ # 请求日志、操作日志、防重、幂等切面 ├── config/ # CORS、枚举 Jackson、异步线程池、RustFS、Admin 等 ├── controller/ # REST API(含 EnumController、TestController 探针) ├── domain/ # 实体 ├── enums/ # BaseEnum、注册表、Jackson 序列化 ├── exception/ # BusinessException、GlobalExceptionHandler ├── mapper/ # MyBatis-Flex Mapper ├── service/ # 业务服务 └── util/ # Servlet 等工具 ``` ## 基础设施 ### 统一返回体 `Result` | 字段 | 说明 | |--------|-----------------| | `code` | 业务码,成功一般为 `200` | | `msg` | 提示信息 | | `data` | 载荷,可为 `null` | ```json { "code": 200, "msg": "success", "data": {} } ``` Controller 显式返回 `Result.success(data)` / `Result.fail(code, msg)`;异常由全局处理器写入 `Result`,HTTP 状态与 `code` 对应(如 400/409/429/500)。 ### 全局异常 `GlobalExceptionHandler` | 类型 | HTTP | 说明 | |-----------------------------------|--------|----------------------| | `BusinessException` | 按 code | 业务错误,可自定义 code | | `MethodArgumentNotValidException` | 400 | `@Valid` 请求体校验 | | `ConstraintViolationException` | 400 | `@Validated` 方法/参数校验 | | `BindException` | 400 | 绑定失败 | | `InvalidFormatException` | 400 | JSON 反序列化(含枚举格式错误) | | 其他未捕获异常 | 500 | 统一「服务器内部错误」 | 业务侧:`throw new BusinessException("消息")` 或 `new BusinessException(409, "冲突")`。 ### 全局跨域 CORS `WebMvcConfiguration` + `app.cors.*`(见 `application.yaml`)。 | 配置项 | 说明 | |------------------------------------|----------------------------------------| | `app.cors.enabled` | 是否启用 | | `app.cors.allowed-origin-patterns` | 允许源(dev 默认较宽,prod 建议配置域名) | | `app.cors.allow-credentials` | 是否携带 Cookie | | `app.cors.exposed-headers` | 暴露头(含 `Idempotency-Key`、`X-Oper-Name`) | 生产可通过环境变量 `APP_CORS_ORIGINS` 覆盖(见 `application-prod.yaml`)。 ### 参数校验 - 依赖:`spring-boot-starter-validation` - Controller 类上加 `@Validated`;Query 参数用 `@Min` 等;请求体用 `@Valid @RequestBody Dto` - 校验失败自动返回 `Result`,`code=400`,`msg` 为首个字段错误信息 示例 DTO:`ValidateDemoRequest`;探针见 `POST /test/validate-body`。 ### 枚举统一处理 | 能力 | 说明 | |-------------|----------------------------------------------------------| | **数据库** | 实体字段为 `BaseEnum` 子类,`getCode()` 标注 `@EnumValue`,存数字 code | | **JSON 响应** | `{"code":1,"desc":"正常"}` | | **JSON 请求** | 支持数字、字符串、枚举名、`{code,desc}` | | **字典 API** | `EnumController` 供前端下拉 | **注册新枚举**(一处注册,Jackson + 字典 API 同步): 1. 新建枚举实现 `BaseEnum`,`getCode()` 加 `@EnumValue` 2. 在 `BaseEnumRegistry.DESCRIPTORS` 追加:`new EnumDescriptor("key", XxxEnum.class, "中文说明")` | 方法 | 路径 | 说明 | |-----|----------------------|---------------------------------------------------| | GET | `/api/enums` | 全部枚举 `{ userStatus: [...], commonStatus: [...] }` | | GET | `/api/enums/catalog` | 带 label 的目录列表 | | GET | `/api/enums/{key}` | 单个枚举,如 `userStatus` | 选项项:`{ "code", "desc", "name" }`(`name` 为枚举常量名)。 ### 多环境配置 | Profile | 文件 | 说明 | |-----------|-------------------------|---------------------------------| | `dev`(默认) | `application-dev.yaml` | Swagger、DEBUG、MyBatis SQL 控制台 | | `test` | `application-test.yaml` | 联调:Swagger 开启,SQL 走 Slf4j | | `prod` | `application-prod.yaml` | 关闭 Swagger,收紧 Actuator,CORS 白名单 | ```bash # 默认 dev gradlew.bat bootRun # 生产 gradlew.bat bootRun --args="--spring.profiles.active=prod" # 或环境变量 set SPRING_PROFILES_ACTIVE=prod ``` 公共配置在 `application.yaml`;敏感信息请用环境变量,勿提交仓库。 ### AOP 日志 | 组件 | 说明 | 配置 | |--------------------|----------------------------------------------|---------------------| | `RequestLogAspect` | 所有 `@RestController` 请求:方法、URI、IP、耗时、参数(可截断) | `app.log.request.*` | | `@OperLog` | 标注方法后写入 `sys_oper_log`(可异步) | `app.log.oper.*` | **`@OperLog` 示例:** ```java @OperLog(title = "修改用户", businessType = BusinessType.UPDATE) @PutMapping("/{id}") public Result update(...) { ... } ``` - `businessType`:`BusinessType` 枚举(INSERT/UPDATE/DELETE 等) - 操作人:请求头 `X-Oper-Name`(缺省为 `anonymous`) - 异步落库:`OperLogRecordService` + `@Async`(`app.log.oper.async=true`) ### 防重复提交与接口幂等(Redis) | 注解 | 说明 | 依赖 | |-----------------|-----------------------------------|----------------| | `@RepeatSubmit` | 同用户+接口+参数指纹,在 `interval` 毫秒内仅允许一次 | Redis `SET NX` | | `@Idempotent` | 请求头幂等键,相同键在有效期内返回首次成功 `Result` | Redis 缓存 JSON | | 配置前缀 | 说明 | |-----------------------------------------|------------------------------| | `app.repeat-submit.enabled` | 是否启用防重 | | `app.repeat-submit.default-interval-ms` | 默认间隔(毫秒) | | `app.repeat-submit.token-header` | 参与指纹的登录头(默认 `Authorization`) | | `app.idempotent.enabled` | 是否启用幂等 | | `app.idempotent.header` | 幂等键请求头(默认 `Idempotency-Key`) | | `app.idempotent.expire-seconds` | 结果缓存 TTL | **示例:** ```java @RepeatSubmit(interval = 5000, message = "请勿重复提交") @PostMapping("/order") public Result create(...) { ... } @Idempotent @PostMapping("/pay") public Result pay(...) { ... } ``` 幂等请求需携带头:`Idempotency-Key: `。重复提交返回 `code=429`;处理中冲突返回 `409`。 单元测试默认关闭防重/幂等(见 `src/test/resources/application.yaml`)。 ## 功能模块 ### 电商 - 商品 (Goods)、SKU (GoodsSku) - 订单 (OrderMain)、订单明细 (OrderItem) - 用户地址 (UserAddress)、通用分类 (CommonCategory) ### 系统(RBAC) - 用户/角色/菜单/部门 (SysUser、SysRole、SysMenu、SysDept) - 字典 (SysDictType、SysDictData) - 日志 (SysLoginLog、SysOperLog) - 关联 (SysUserRole、SysRoleMenu) ## 业务 API 各业务 Controller 继承 `BaseFlexCrudController`,路径因类上的 `@RequestMapping` 而异: | 方法 | 路径 | 说明 | |--------|---------|---------| | GET | `/page` | 分页 | | GET | `/{id}` | 按 ID 查询 | | GET | `/` | 列表 | | POST | `/` | 新增 | | PUT | `/` | 更新 | | DELETE | `/{id}` | 删除 | ## 探针接口 `/test` 用于联调环境,默认端口 **8082**。 | 方法 | 路径 | 说明 | |------|-----------------------|---------------------------------------------| | GET | `/test/test` | 存活 | | GET | `/test/db` | MyBatis-Flex + 数据源 | | GET | `/test/redis` | Spring Data Redis | | GET | `/test/redisson` | Redisson | | GET | `/test/cache` | Spring Cache | | GET | `/test/oss` | RustFS OSS(需 `app.rustfs.oss.enabled=true`) | | GET | `/test/hutool` | Hutool | | GET | `/test/validate?n=1` | Query 参数校验 | | POST | `/test/validate-body` | `@Valid` 请求体校验 | | POST | `/test/repeat-submit` | `@RepeatSubmit` 演示 | | POST | `/test/idempotent` | `@Idempotent` 演示(需头 `Idempotency-Key`) | | POST | `/test/oper-log` | `@OperLog` 演示 | | GET | `/test/status` | 汇总探针结果 | ## RustFS 对象存储 RustFS 与 S3 API 兼容,客户端使用 **AWS SDK v2**,须配置 **`forcePathStyle: true`**。 - **控制台**(管理密钥):`http://:/rustfs/console/access-keys` - **SDK Endpoint**:`http://:`(不要带 `/rustfs/console/...`) ### 配置项 `app.rustfs.oss` | 配置 / 环境变量 | 说明 | |------------------------------------|------------| | `enabled` / `RUSTFS_OSS_ENABLED` | 是否启用 | | `endpoint` / `RUSTFS_ENDPOINT` | S3 API 地址 | | `access-key` / `RUSTFS_ACCESS_KEY` | Access Key | | `secret-key` / `RUSTFS_SECRET_KEY` | Secret Key | | `bucket` / `RUSTFS_BUCKET` | 默认 Bucket | ### OSS API `/api/oss`(启用后) | 方法 | 路径 | 说明 | |--------|--------------------------|--------------------------------| | GET | `/api/oss/probe` | 读写探测 | | POST | `/api/oss/upload` | `multipart`,字段 `file`,可选 `key` | | GET | `/api/oss/download?key=` | 下载 | | DELETE | `/api/oss?key=` | 删除 | | GET | `/api/oss/list?prefix=` | 列举 | | GET | `/api/oss/presign?key=` | 预签名下载 URL | 若探针返回 `KMS encryption service is not initialized`,需在 RustFS 服务端处理 KMS/SSE 配置。 ## 文档与监控 ### Swagger / OpenAPI | 说明 | 地址 | |--------------|---------------------------------------| | Swagger UI | http://localhost:8082/swagger-ui.html | | OpenAPI JSON | http://localhost:8082/v3/api-docs | `dev` / `test` Profile 默认开启;`prod` 默认关闭。 ### Spring Boot Actuator 根路径 `/actuator`。`dev` 下暴露较全;`prod` 仅 `health,info,metrics,prometheus`。**生产请加认证。** | 说明 | 地址 | |------|---------------------------------------| | 端点索引 | http://localhost:8082/actuator | | 健康检查 | http://localhost:8082/actuator/health | ### Spring Boot Admin 本工程集成 **Admin Server + Client**(单机演示):**http://localhost:8082/**。生产建议独立 Admin Server + Client + Security。 ## 异步线程池 `AsyncExecutorConfiguration` 注册 `taskExecutor`,供 `@Async`(如异步操作日志)使用;参数见 `app.async.executor.*`。 ## 快速开始 ### 环境要求 - JDK **21** - Gradle 8+(可使用 `gradlew`) - MySQL / PostgreSQL、Redis(按 `application.yaml`) - 可选:RustFS ### 构建与运行 ```bash gradlew.bat build gradlew.bat bootRun ``` 默认端口 **8082**;默认 Profile **dev**。 ## 配置说明 | 文件 | 用途 | |---------------------------------------|----------------------------------------| | `application.yaml` | 公共配置(数据源、Redis、CORS、日志、防重/幂等、RustFS 等) | | `application-dev.yaml` | 开发环境 | | `application-test.yaml` | 联调/测试环境 | | `application-prod.yaml` | 生产环境 | | `src/test/resources/application.yaml` | 单元测试:H2、Mock Redis、关闭 RustFS/防重/幂等 | **安全建议**:生产环境使用环境变量注入数据库、Redis、RustFS、CORS 等密钥与地址。 ## 测试 ```bash gradlew.bat test ``` - 默认不连真实 Redis / RustFS;使用 H2 与 Mock Bean。 - 真实 RustFS 联调(可选): ```bash set RUSTFS_LIVE_TEST=true gradlew.bat test --tests org.my919.springboot.RustFsOssLiveTest ``` ## License MIT License