ai-engineering-init 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/agents/code-reviewer.md +139 -0
- package/.claude/agents/project-manager.md +159 -0
- package/.claude/audio/completed.wav +0 -0
- package/.claude/commands/add-todo.md +255 -0
- package/.claude/commands/check.md +210 -0
- package/.claude/commands/crud.md +454 -0
- package/.claude/commands/dev.md +503 -0
- package/.claude/commands/init-docs.md +681 -0
- package/.claude/commands/next.md +251 -0
- package/.claude/commands/progress.md +242 -0
- package/.claude/commands/start.md +199 -0
- package/.claude/commands/sync.md +307 -0
- package/.claude/commands/update-status.md +428 -0
- package/.claude/docs/Mixin/344/275/277/347/224/250/346/214/207/345/215/227.md +299 -0
- package/.claude/docs/README.md +167 -0
- package/.claude/docs//345/211/215/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +599 -0
- package/.claude/docs//345/220/216/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +726 -0
- package/.claude/docs//345/267/245/344/275/234/346/265/201/345/274/200/345/217/221/346/214/207/345/215/227.md +714 -0
- package/.claude/docs//345/267/245/345/205/267/347/261/273/344/275/277/347/224/250/346/214/207/345/215/227.md +463 -0
- package/.claude/docs//346/225/260/346/215/256/345/272/223/350/256/276/350/256/241/350/247/204/350/214/203.md +390 -0
- package/.claude/docs//346/226/260/345/212/237/350/203/275/345/274/200/345/217/221/346/265/201/347/250/213/350/247/204/350/214/203.md +688 -0
- package/.claude/docs//346/226/260/351/241/271/347/233/256/345/274/200/345/217/221/346/265/201/347/250/213.md +365 -0
- package/.claude/docs//346/241/206/346/236/266/350/257/264/346/230/216.md +393 -0
- package/.claude/docs//350/267/257/347/224/261/351/205/215/347/275/256/346/214/207/345/215/227.md +246 -0
- package/.claude/framework-config.json +73 -0
- package/.claude/hooks/pre-tool-use.js +117 -0
- package/.claude/hooks/skill-forced-eval.js +167 -0
- package/.claude/hooks/stop.js +58 -0
- package/.claude/settings.json +41 -0
- package/.claude/skills/add-skill/SKILL.md +352 -0
- package/.claude/skills/api-development/SKILL.md +560 -0
- package/.claude/skills/architecture-design/SKILL.md +756 -0
- package/.claude/skills/backend-annotations/SKILL.md +674 -0
- package/.claude/skills/banana-image/CHANGELOG.md +37 -0
- package/.claude/skills/banana-image/README.md +146 -0
- package/.claude/skills/banana-image/SKILL.md +164 -0
- package/.claude/skills/banana-image/assets/logo.png +0 -0
- package/.claude/skills/banana-image/references/advanced-usage.md +189 -0
- package/.claude/skills/banana-image/scripts/apply_template.py +125 -0
- package/.claude/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.claude/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.claude/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.claude/skills/banana-image/scripts/package.json +18 -0
- package/.claude/skills/banana-image/scripts/requirements.txt +10 -0
- package/.claude/skills/banana-image/templates/poster.json +22 -0
- package/.claude/skills/banana-image/templates/product.json +17 -0
- package/.claude/skills/banana-image/templates/social.json +22 -0
- package/.claude/skills/banana-image/templates/thumbnail.json +17 -0
- package/.claude/skills/brainstorm/SKILL.md +648 -0
- package/.claude/skills/bug-detective/SKILL.md +1206 -0
- package/.claude/skills/code-patterns/SKILL.md +590 -0
- package/.claude/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.claude/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.claude/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.claude/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.claude/skills/crud-development/SKILL.md +649 -0
- package/.claude/skills/data-permission/SKILL.md +599 -0
- package/.claude/skills/database-ops/SKILL.md +407 -0
- package/.claude/skills/error-handler/SKILL.md +371 -0
- package/.claude/skills/file-oss-management/SKILL.md +863 -0
- package/.claude/skills/git-workflow/SKILL.md +375 -0
- package/.claude/skills/json-serialization/SKILL.md +357 -0
- package/.claude/skills/leniu-api-development/SKILL.md +803 -0
- package/.claude/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.claude/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.claude/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.claude/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.claude/skills/leniu-data-permission/SKILL.md +256 -0
- package/.claude/skills/leniu-database-ops/SKILL.md +426 -0
- package/.claude/skills/leniu-error-handler/SKILL.md +462 -0
- package/.claude/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.claude/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.claude/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.claude/skills/leniu-java-entity/SKILL.md +751 -0
- package/.claude/skills/leniu-java-export/SKILL.md +560 -0
- package/.claude/skills/leniu-java-logging/SKILL.md +832 -0
- package/.claude/skills/leniu-java-mq/SKILL.md +338 -0
- package/.claude/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.claude/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.claude/skills/leniu-java-task/SKILL.md +367 -0
- package/.claude/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.claude/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.claude/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.claude/skills/leniu-mealtime/SKILL.md +215 -0
- package/.claude/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.claude/skills/leniu-security-guard/SKILL.md +520 -0
- package/.claude/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.claude/skills/openspec-apply-change/SKILL.md +156 -0
- package/.claude/skills/openspec-archive-change/SKILL.md +114 -0
- package/.claude/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.claude/skills/openspec-continue-change/SKILL.md +118 -0
- package/.claude/skills/openspec-explore/SKILL.md +290 -0
- package/.claude/skills/openspec-ff-change/SKILL.md +101 -0
- package/.claude/skills/openspec-new-change/SKILL.md +74 -0
- package/.claude/skills/openspec-onboard/SKILL.md +529 -0
- package/.claude/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.claude/skills/openspec-verify-change/SKILL.md +168 -0
- package/.claude/skills/performance-doctor/SKILL.md +627 -0
- package/.claude/skills/project-navigator/SKILL.md +305 -0
- package/.claude/skills/redis-cache/SKILL.md +839 -0
- package/.claude/skills/scheduled-jobs/SKILL.md +633 -0
- package/.claude/skills/security-guard/SKILL.md +748 -0
- package/.claude/skills/sms-mail/SKILL.md +766 -0
- package/.claude/skills/social-login/SKILL.md +668 -0
- package/.claude/skills/store-pc/SKILL.md +366 -0
- package/.claude/skills/task-tracker/SKILL.md +307 -0
- package/.claude/skills/tech-decision/SKILL.md +393 -0
- package/.claude/skills/tenant-management/SKILL.md +603 -0
- package/.claude/skills/test-development/SKILL.md +755 -0
- package/.claude/skills/ui-pc/SKILL.md +438 -0
- package/.claude/skills/utils-toolkit/SKILL.md +615 -0
- package/.claude/skills/websocket-sse/SKILL.md +716 -0
- package/.claude/skills/workflow-engine/SKILL.md +676 -0
- package/.claude/templates//345/276/205/345/212/236/346/270/205/345/215/225/346/250/241/346/235/277.md +56 -0
- package/.claude/templates//351/234/200/346/261/202/346/226/207/346/241/243/346/250/241/346/235/277.md +85 -0
- package/.claude/templates//351/241/271/347/233/256/347/212/266/346/200/201/346/250/241/346/235/277.md +43 -0
- package/.codex/skills/add-skill/SKILL.md +352 -0
- package/.codex/skills/add-todo/SKILL.md +269 -0
- package/.codex/skills/api-development/SKILL.md +693 -0
- package/.codex/skills/architecture-design/SKILL.md +628 -0
- package/.codex/skills/backend-annotations/SKILL.md +664 -0
- package/.codex/skills/banana-image/CHANGELOG.md +37 -0
- package/.codex/skills/banana-image/README.md +146 -0
- package/.codex/skills/banana-image/SKILL.md +164 -0
- package/.codex/skills/banana-image/assets/logo.png +0 -0
- package/.codex/skills/banana-image/references/advanced-usage.md +189 -0
- package/.codex/skills/banana-image/scripts/apply_template.py +125 -0
- package/.codex/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.codex/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.codex/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.codex/skills/banana-image/scripts/package.json +18 -0
- package/.codex/skills/banana-image/scripts/requirements.txt +10 -0
- package/.codex/skills/banana-image/templates/poster.json +22 -0
- package/.codex/skills/banana-image/templates/product.json +17 -0
- package/.codex/skills/banana-image/templates/social.json +22 -0
- package/.codex/skills/banana-image/templates/thumbnail.json +17 -0
- package/.codex/skills/brainstorm/SKILL.md +648 -0
- package/.codex/skills/bug-detective/SKILL.md +1206 -0
- package/.codex/skills/check/SKILL.md +367 -0
- package/.codex/skills/code-patterns/SKILL.md +442 -0
- package/.codex/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.codex/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.codex/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.codex/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.codex/skills/crud/SKILL.md +265 -0
- package/.codex/skills/crud-development/SKILL.md +637 -0
- package/.codex/skills/data-permission/SKILL.md +591 -0
- package/.codex/skills/database-ops/SKILL.md +553 -0
- package/.codex/skills/dev/SKILL.md +187 -0
- package/.codex/skills/error-handler/SKILL.md +361 -0
- package/.codex/skills/file-oss-management/SKILL.md +863 -0
- package/.codex/skills/git-workflow/SKILL.md +375 -0
- package/.codex/skills/init-docs/SKILL.md +194 -0
- package/.codex/skills/json-serialization/SKILL.md +357 -0
- package/.codex/skills/leniu-api-development/SKILL.md +803 -0
- package/.codex/skills/leniu-architecture-design/SKILL.md +594 -0
- package/.codex/skills/leniu-backend-annotations/SKILL.md +662 -0
- package/.codex/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.codex/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.codex/skills/leniu-data-permission/SKILL.md +256 -0
- package/.codex/skills/leniu-database-ops/SKILL.md +426 -0
- package/.codex/skills/leniu-error-handler/SKILL.md +462 -0
- package/.codex/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.codex/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.codex/skills/leniu-java-entity/SKILL.md +751 -0
- package/.codex/skills/leniu-java-export/SKILL.md +560 -0
- package/.codex/skills/leniu-java-logging/SKILL.md +832 -0
- package/.codex/skills/leniu-java-mq/SKILL.md +338 -0
- package/.codex/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.codex/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.codex/skills/leniu-java-task/SKILL.md +367 -0
- package/.codex/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.codex/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.codex/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.codex/skills/leniu-mealtime/SKILL.md +215 -0
- package/.codex/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.codex/skills/leniu-security-guard/SKILL.md +520 -0
- package/.codex/skills/leniu-utils-toolkit/SKILL.md +378 -0
- package/.codex/skills/next/SKILL.md +137 -0
- package/.codex/skills/openspec-apply-change/SKILL.md +156 -0
- package/.codex/skills/openspec-archive-change/SKILL.md +114 -0
- package/.codex/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.codex/skills/openspec-continue-change/SKILL.md +118 -0
- package/.codex/skills/openspec-explore/SKILL.md +290 -0
- package/.codex/skills/openspec-ff-change/SKILL.md +101 -0
- package/.codex/skills/openspec-new-change/SKILL.md +74 -0
- package/.codex/skills/openspec-onboard/SKILL.md +529 -0
- package/.codex/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.codex/skills/openspec-verify-change/SKILL.md +168 -0
- package/.codex/skills/performance-doctor/SKILL.md +627 -0
- package/.codex/skills/progress/SKILL.md +193 -0
- package/.codex/skills/project-navigator/SKILL.md +286 -0
- package/.codex/skills/redis-cache/SKILL.md +829 -0
- package/.codex/skills/scheduled-jobs/SKILL.md +633 -0
- package/.codex/skills/security-guard/SKILL.md +739 -0
- package/.codex/skills/sms-mail/SKILL.md +766 -0
- package/.codex/skills/social-login/SKILL.md +668 -0
- package/.codex/skills/start/SKILL.md +154 -0
- package/.codex/skills/store-pc/SKILL.md +491 -0
- package/.codex/skills/sync/SKILL.md +149 -0
- package/.codex/skills/task-tracker/SKILL.md +307 -0
- package/.codex/skills/tech-decision/SKILL.md +393 -0
- package/.codex/skills/tenant-management/SKILL.md +603 -0
- package/.codex/skills/test-development/SKILL.md +755 -0
- package/.codex/skills/ui-pc/SKILL.md +475 -0
- package/.codex/skills/update-status/SKILL.md +159 -0
- package/.codex/skills/utils-toolkit/SKILL.md +593 -0
- package/.codex/skills/websocket-sse/SKILL.md +716 -0
- package/.codex/skills/workflow-engine/SKILL.md +676 -0
- package/.cursor/agents/code-reviewer.md +139 -0
- package/.cursor/agents/project-manager.md +159 -0
- package/.cursor/commands/opsx-apply.md +152 -0
- package/.cursor/commands/opsx-archive.md +157 -0
- package/.cursor/commands/opsx-bulk-archive.md +242 -0
- package/.cursor/commands/opsx-continue.md +114 -0
- package/.cursor/commands/opsx-explore.md +174 -0
- package/.cursor/commands/opsx-ff.md +94 -0
- package/.cursor/commands/opsx-new.md +69 -0
- package/.cursor/commands/opsx-onboard.md +525 -0
- package/.cursor/commands/opsx-sync.md +134 -0
- package/.cursor/commands/opsx-verify.md +164 -0
- package/.cursor/mcp.json +22 -0
- package/.cursor/skills/add-skill/SKILL.md +352 -0
- package/.cursor/skills/api-development/SKILL.md +560 -0
- package/.cursor/skills/architecture-design/SKILL.md +756 -0
- package/.cursor/skills/backend-annotations/SKILL.md +674 -0
- package/.cursor/skills/banana-image/CHANGELOG.md +37 -0
- package/.cursor/skills/banana-image/README.md +146 -0
- package/.cursor/skills/banana-image/SKILL.md +164 -0
- package/.cursor/skills/banana-image/assets/logo.png +0 -0
- package/.cursor/skills/banana-image/references/advanced-usage.md +189 -0
- package/.cursor/skills/banana-image/scripts/apply_template.py +125 -0
- package/.cursor/skills/banana-image/scripts/banana_image_exec.ts +412 -0
- package/.cursor/skills/banana-image/scripts/batch_prep.py +82 -0
- package/.cursor/skills/banana-image/scripts/package-lock.json +1437 -0
- package/.cursor/skills/banana-image/scripts/package.json +18 -0
- package/.cursor/skills/banana-image/scripts/requirements.txt +10 -0
- package/.cursor/skills/banana-image/templates/poster.json +22 -0
- package/.cursor/skills/banana-image/templates/product.json +17 -0
- package/.cursor/skills/banana-image/templates/social.json +22 -0
- package/.cursor/skills/banana-image/templates/thumbnail.json +17 -0
- package/.cursor/skills/brainstorm/SKILL.md +648 -0
- package/.cursor/skills/bug-detective/SKILL.md +1206 -0
- package/.cursor/skills/code-patterns/SKILL.md +590 -0
- package/.cursor/skills/collaborating-with-codex/SKILL.md +174 -0
- package/.cursor/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
- package/.cursor/skills/collaborating-with-gemini/SKILL.md +194 -0
- package/.cursor/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
- package/.cursor/skills/crud-development/SKILL.md +649 -0
- package/.cursor/skills/data-permission/SKILL.md +599 -0
- package/.cursor/skills/database-ops/SKILL.md +407 -0
- package/.cursor/skills/error-handler/SKILL.md +371 -0
- package/.cursor/skills/file-oss-management/SKILL.md +863 -0
- package/.cursor/skills/git-workflow/SKILL.md +375 -0
- package/.cursor/skills/json-serialization/SKILL.md +357 -0
- package/.cursor/skills/leniu-api-development/SKILL.md +803 -0
- package/.cursor/skills/leniu-architecture-design/SKILL.md +598 -0
- package/.cursor/skills/leniu-backend-annotations/SKILL.md +664 -0
- package/.cursor/skills/leniu-code-patterns/SKILL.md +365 -0
- package/.cursor/skills/leniu-crud-development/SKILL.md +1110 -0
- package/.cursor/skills/leniu-data-permission/SKILL.md +256 -0
- package/.cursor/skills/leniu-database-ops/SKILL.md +426 -0
- package/.cursor/skills/leniu-error-handler/SKILL.md +462 -0
- package/.cursor/skills/leniu-java-amount-handling/SKILL.md +461 -0
- package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
- package/.cursor/skills/leniu-java-concurrent/SKILL.md +400 -0
- package/.cursor/skills/leniu-java-entity/SKILL.md +751 -0
- package/.cursor/skills/leniu-java-export/SKILL.md +560 -0
- package/.cursor/skills/leniu-java-logging/SKILL.md +832 -0
- package/.cursor/skills/leniu-java-mq/SKILL.md +338 -0
- package/.cursor/skills/leniu-java-mybatis/SKILL.md +640 -0
- package/.cursor/skills/leniu-java-report-query-param/SKILL.md +291 -0
- package/.cursor/skills/leniu-java-task/SKILL.md +367 -0
- package/.cursor/skills/leniu-java-total-line/SKILL.md +195 -0
- package/.cursor/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
- package/.cursor/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
- package/.cursor/skills/leniu-mealtime/SKILL.md +215 -0
- package/.cursor/skills/leniu-redis-cache/SKILL.md +316 -0
- package/.cursor/skills/leniu-security-guard/SKILL.md +520 -0
- package/.cursor/skills/leniu-utils-toolkit/SKILL.md +380 -0
- package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
- package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
- package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +246 -0
- package/.cursor/skills/openspec-continue-change/SKILL.md +118 -0
- package/.cursor/skills/openspec-explore/SKILL.md +290 -0
- package/.cursor/skills/openspec-ff-change/SKILL.md +101 -0
- package/.cursor/skills/openspec-new-change/SKILL.md +74 -0
- package/.cursor/skills/openspec-onboard/SKILL.md +529 -0
- package/.cursor/skills/openspec-sync-specs/SKILL.md +138 -0
- package/.cursor/skills/openspec-verify-change/SKILL.md +168 -0
- package/.cursor/skills/performance-doctor/SKILL.md +627 -0
- package/.cursor/skills/project-navigator/SKILL.md +305 -0
- package/.cursor/skills/redis-cache/SKILL.md +839 -0
- package/.cursor/skills/scheduled-jobs/SKILL.md +633 -0
- package/.cursor/skills/security-guard/SKILL.md +748 -0
- package/.cursor/skills/sms-mail/SKILL.md +766 -0
- package/.cursor/skills/social-login/SKILL.md +668 -0
- package/.cursor/skills/store-pc/SKILL.md +366 -0
- package/.cursor/skills/task-tracker/SKILL.md +307 -0
- package/.cursor/skills/tech-decision/SKILL.md +393 -0
- package/.cursor/skills/tenant-management/SKILL.md +603 -0
- package/.cursor/skills/test-development/SKILL.md +755 -0
- package/.cursor/skills/ui-pc/SKILL.md +438 -0
- package/.cursor/skills/utils-toolkit/SKILL.md +615 -0
- package/.cursor/skills/websocket-sse/SKILL.md +716 -0
- package/.cursor/skills/workflow-engine/SKILL.md +676 -0
- package/AGENTS.md +669 -0
- package/CLAUDE.md +205 -0
- package/README.md +205 -0
- package/bin/index.js +179 -0
- package/init.sh +178 -0
- package/package.json +27 -0
package/.claude/docs//345/220/216/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md
ADDED
|
@@ -0,0 +1,726 @@
|
|
|
1
|
+
# 后端开发指南
|
|
2
|
+
|
|
3
|
+
> **重要提示**: 本项目是 RuoYi-Vue-Plus **纯后端项目**,采用**三层架构**。
|
|
4
|
+
> 严格遵循本规范,参考 `ruoyi-demo` 模块的 TestDemo 实现。
|
|
5
|
+
|
|
6
|
+
最后更新: 2026-02-09
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## 🏗️ 核心架构(必须牢记)
|
|
11
|
+
|
|
12
|
+
| 项目 | 规范 |
|
|
13
|
+
|------|------|
|
|
14
|
+
| **包名** | `org.dromara.*`(禁止 `com.ruoyi.*`、`plus.ruoyi.*`) |
|
|
15
|
+
| **架构** | 三层:Controller → Service → Mapper(**无 DAO 层**) |
|
|
16
|
+
| **查询构建** | Service 层 `buildQueryWrapper()` |
|
|
17
|
+
| **Mapper 继承** | `BaseMapperPlus<Entity, VO>` |
|
|
18
|
+
| **对象转换** | `MapstructUtils.convert()`(禁止 BeanUtils) |
|
|
19
|
+
| **Entity 基类** | `TenantEntity`(多租户) |
|
|
20
|
+
| **BO 映射** | `@AutoMapper` 注解(**单数**,不是 `@AutoMappers`) |
|
|
21
|
+
| **主键策略** | 雪花 ID(不用 AUTO_INCREMENT) |
|
|
22
|
+
| **Controller 基类** | `extends BaseController` |
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 📁 项目结构
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
RuoYi-Vue-Plus/
|
|
30
|
+
├── ruoyi-admin/ # 后端启动入口
|
|
31
|
+
│ └── src/main/resources/
|
|
32
|
+
│ ├── application.yml # 主配置
|
|
33
|
+
│ └── application-dev.yml # 开发环境配置
|
|
34
|
+
│
|
|
35
|
+
├── ruoyi-common/ # 通用工具模块(24个子模块)
|
|
36
|
+
│ ├── ruoyi-common-core/ # 核心工具(MapstructUtils, StringUtils)
|
|
37
|
+
│ ├── ruoyi-common-mybatis/ # MyBatis-Plus 扩展(BaseMapperPlus)
|
|
38
|
+
│ ├── ruoyi-common-tenant/ # 多租户(TenantEntity)
|
|
39
|
+
│ ├── ruoyi-common-redis/ # Redis 缓存
|
|
40
|
+
│ ├── ruoyi-common-satoken/ # 权限认证
|
|
41
|
+
│ └── ... # 其他模块
|
|
42
|
+
│
|
|
43
|
+
├── ruoyi-modules/ # 业务功能模块
|
|
44
|
+
│ ├── ruoyi-system/ # 系统管理模块(sys_*)
|
|
45
|
+
│ ├── ruoyi-demo/ # 演示模块(test_*)⭐ 参考实现
|
|
46
|
+
│ ├── ruoyi-generator/ # 代码生成器
|
|
47
|
+
│ ├── ruoyi-job/ # 定时任务(SnailJob)
|
|
48
|
+
│ └── ruoyi-workflow/ # 工作流(WarmFlow)
|
|
49
|
+
│
|
|
50
|
+
└── script/sql/ # 数据库脚本
|
|
51
|
+
└── ry_vue_5.X.sql # 系统表初始化
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## 📐 三层架构详解
|
|
57
|
+
|
|
58
|
+
### 架构流程图
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
62
|
+
│ Controller 层 │
|
|
63
|
+
│ • 接收 HTTP 请求、参数校验、返回 R<T> 响应 │
|
|
64
|
+
│ • 路由:/list, /{id}, POST, PUT, DELETE/{ids} │
|
|
65
|
+
│ • 权限:@SaCheckPermission │
|
|
66
|
+
└──────────────────────────────┬───────────────────────────────┘
|
|
67
|
+
│
|
|
68
|
+
▼
|
|
69
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
70
|
+
│ Service 层 │
|
|
71
|
+
│ • 业务逻辑处理、事务管理 │
|
|
72
|
+
│ • buildQueryWrapper() 查询条件构建 ⭐ │
|
|
73
|
+
│ • 使用 MapstructUtils.convert() 对象转换 │
|
|
74
|
+
│ • 直接注入 Mapper(无 DAO 层) │
|
|
75
|
+
└──────────────────────────────┬───────────────────────────────┘
|
|
76
|
+
│
|
|
77
|
+
▼
|
|
78
|
+
┌──────────────────────────────────────────────────────────────┐
|
|
79
|
+
│ Mapper 层 │
|
|
80
|
+
│ • extends BaseMapperPlus<Entity, Vo> │
|
|
81
|
+
│ • 提供 selectVoById、selectVoPage、selectVoList 等方法 │
|
|
82
|
+
└──────────────────────────────────────────────────────────────┘
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 标准模块结构
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
ruoyi-modules/ruoyi-xxx/src/main/java/org/dromara/xxx/
|
|
89
|
+
├── controller/
|
|
90
|
+
│ └── XxxController.java # @RestController, extends BaseController
|
|
91
|
+
├── service/
|
|
92
|
+
│ ├── IXxxService.java # 服务接口
|
|
93
|
+
│ └── impl/
|
|
94
|
+
│ └── XxxServiceImpl.java # 服务实现(包含 buildQueryWrapper)
|
|
95
|
+
├── mapper/
|
|
96
|
+
│ └── XxxMapper.java # extends BaseMapperPlus<Xxx, XxxVo>
|
|
97
|
+
└── domain/
|
|
98
|
+
├── Xxx.java # Entity(extends TenantEntity)
|
|
99
|
+
├── bo/
|
|
100
|
+
│ └── XxxBo.java # 业务对象(@AutoMapper)
|
|
101
|
+
└── vo/
|
|
102
|
+
└── XxxVo.java # 视图对象
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## 📋 代码模板
|
|
108
|
+
|
|
109
|
+
### 1. Entity 实体类
|
|
110
|
+
|
|
111
|
+
```java
|
|
112
|
+
package org.dromara.demo.domain;
|
|
113
|
+
|
|
114
|
+
import com.baomidou.mybatisplus.annotation.*;
|
|
115
|
+
import lombok.Data;
|
|
116
|
+
import lombok.EqualsAndHashCode;
|
|
117
|
+
import org.dromara.common.tenant.core.TenantEntity;
|
|
118
|
+
import java.io.Serial;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* XXX 对象
|
|
122
|
+
*/
|
|
123
|
+
@Data
|
|
124
|
+
@EqualsAndHashCode(callSuper = true)
|
|
125
|
+
@TableName("test_xxx")
|
|
126
|
+
public class Xxx extends TenantEntity { // ✅ 继承 TenantEntity
|
|
127
|
+
|
|
128
|
+
@Serial
|
|
129
|
+
private static final long serialVersionUID = 1L;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* 主键 ID
|
|
133
|
+
*/
|
|
134
|
+
@TableId(value = "id")
|
|
135
|
+
private Long id;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* 名称
|
|
139
|
+
*/
|
|
140
|
+
private String xxxName;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* 状态(0停用 1正常)
|
|
144
|
+
*/
|
|
145
|
+
private String status;
|
|
146
|
+
}
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**关键点**:
|
|
150
|
+
- ✅ 继承 `TenantEntity`(包含租户ID、审计字段、逻辑删除)
|
|
151
|
+
- ✅ `@TableId(value = "id")` 使用雪花ID(全局配置)
|
|
152
|
+
- ✅ 字段名使用驼峰命名,自动映射蛇形数据库字段
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
### 2. BO 业务对象
|
|
157
|
+
|
|
158
|
+
```java
|
|
159
|
+
package org.dromara.demo.domain.bo;
|
|
160
|
+
|
|
161
|
+
import io.github.linpeilie.annotations.AutoMapper;
|
|
162
|
+
import jakarta.validation.constraints.*;
|
|
163
|
+
import lombok.Data;
|
|
164
|
+
import lombok.EqualsAndHashCode;
|
|
165
|
+
import org.dromara.common.core.validate.AddGroup;
|
|
166
|
+
import org.dromara.common.core.validate.EditGroup;
|
|
167
|
+
import org.dromara.common.mybatis.core.domain.BaseEntity;
|
|
168
|
+
import org.dromara.demo.domain.Xxx;
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* XXX 业务对象
|
|
172
|
+
*/
|
|
173
|
+
@Data
|
|
174
|
+
@EqualsAndHashCode(callSuper = true)
|
|
175
|
+
@AutoMapper(target = Xxx.class, reverseConvertGenerate = false) // ✅ 单数!
|
|
176
|
+
public class XxxBo extends BaseEntity {
|
|
177
|
+
|
|
178
|
+
@NotNull(message = "ID不能为空", groups = {EditGroup.class})
|
|
179
|
+
private Long id;
|
|
180
|
+
|
|
181
|
+
@NotBlank(message = "名称不能为空", groups = {AddGroup.class, EditGroup.class})
|
|
182
|
+
private String xxxName;
|
|
183
|
+
|
|
184
|
+
private String status;
|
|
185
|
+
}
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
**关键点**:
|
|
189
|
+
- ✅ `@AutoMapper`(**单数**,不是 `@AutoMappers`)
|
|
190
|
+
- ✅ 继承 `BaseEntity`(包含 params 查询参数)
|
|
191
|
+
- ✅ 使用分组校验:`AddGroup`、`EditGroup`
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### 3. VO 视图对象
|
|
196
|
+
|
|
197
|
+
```java
|
|
198
|
+
package org.dromara.demo.domain.vo;
|
|
199
|
+
|
|
200
|
+
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
|
201
|
+
import cn.idev.excel.annotation.ExcelProperty;
|
|
202
|
+
import io.github.linpeilie.annotations.AutoMapper;
|
|
203
|
+
import lombok.Data;
|
|
204
|
+
import org.dromara.demo.domain.Xxx;
|
|
205
|
+
import java.io.Serial;
|
|
206
|
+
import java.io.Serializable;
|
|
207
|
+
import java.util.Date;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* XXX 视图对象
|
|
211
|
+
*/
|
|
212
|
+
@Data
|
|
213
|
+
@ExcelIgnoreUnannotated
|
|
214
|
+
@AutoMapper(target = Xxx.class)
|
|
215
|
+
public class XxxVo implements Serializable {
|
|
216
|
+
|
|
217
|
+
@Serial
|
|
218
|
+
private static final long serialVersionUID = 1L;
|
|
219
|
+
|
|
220
|
+
@ExcelProperty(value = "ID")
|
|
221
|
+
private Long id;
|
|
222
|
+
|
|
223
|
+
@ExcelProperty(value = "名称")
|
|
224
|
+
private String xxxName;
|
|
225
|
+
|
|
226
|
+
@ExcelProperty(value = "状态")
|
|
227
|
+
private String status;
|
|
228
|
+
|
|
229
|
+
@ExcelProperty(value = "创建时间")
|
|
230
|
+
private Date createTime;
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
---
|
|
235
|
+
|
|
236
|
+
### 4. Mapper 接口
|
|
237
|
+
|
|
238
|
+
```java
|
|
239
|
+
package org.dromara.demo.mapper;
|
|
240
|
+
|
|
241
|
+
import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
|
|
242
|
+
import org.dromara.demo.domain.Xxx;
|
|
243
|
+
import org.dromara.demo.domain.vo.XxxVo;
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* XXX Mapper 接口
|
|
247
|
+
*/
|
|
248
|
+
public interface XxxMapper extends BaseMapperPlus<Xxx, XxxVo> {
|
|
249
|
+
// ✅ 继承 BaseMapperPlus,已提供 selectVoById、selectVoPage 等方法
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**BaseMapperPlus 提供的方法**:
|
|
254
|
+
|
|
255
|
+
| 方法 | 说明 |
|
|
256
|
+
|------|------|
|
|
257
|
+
| `selectVoById(id)` | 根据ID查询VO |
|
|
258
|
+
| `selectVoList(wrapper)` | 查询VO列表 |
|
|
259
|
+
| `selectVoPage(page, wrapper)` | 分页查询VO |
|
|
260
|
+
| `selectByIds(ids)` | 批量查询Entity |
|
|
261
|
+
| `deleteByIds(ids)` | 批量删除 |
|
|
262
|
+
| `exists(wrapper)` | 判断是否存在 |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### 5. Service 接口
|
|
267
|
+
|
|
268
|
+
```java
|
|
269
|
+
package org.dromara.demo.service;
|
|
270
|
+
|
|
271
|
+
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
272
|
+
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
273
|
+
import org.dromara.demo.domain.bo.XxxBo;
|
|
274
|
+
import org.dromara.demo.domain.vo.XxxVo;
|
|
275
|
+
import java.util.Collection;
|
|
276
|
+
import java.util.List;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* XXX 服务接口
|
|
280
|
+
*/
|
|
281
|
+
public interface IXxxService {
|
|
282
|
+
|
|
283
|
+
XxxVo queryById(Long id);
|
|
284
|
+
|
|
285
|
+
TableDataInfo<XxxVo> queryPageList(XxxBo bo, PageQuery pageQuery);
|
|
286
|
+
|
|
287
|
+
List<XxxVo> queryList(XxxBo bo);
|
|
288
|
+
|
|
289
|
+
Boolean insertByBo(XxxBo bo);
|
|
290
|
+
|
|
291
|
+
Boolean updateByBo(XxxBo bo);
|
|
292
|
+
|
|
293
|
+
Boolean deleteByIds(Collection<Long> ids);
|
|
294
|
+
}
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### 6. Service 实现类(⭐ 核心)
|
|
300
|
+
|
|
301
|
+
```java
|
|
302
|
+
package org.dromara.demo.service.impl;
|
|
303
|
+
|
|
304
|
+
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
305
|
+
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
|
306
|
+
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
307
|
+
import lombok.RequiredArgsConstructor;
|
|
308
|
+
import org.springframework.stereotype.Service;
|
|
309
|
+
import org.dromara.common.core.exception.ServiceException;
|
|
310
|
+
import org.dromara.common.core.utils.MapstructUtils;
|
|
311
|
+
import org.dromara.common.core.utils.StringUtils;
|
|
312
|
+
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
313
|
+
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
314
|
+
import org.dromara.demo.domain.Xxx;
|
|
315
|
+
import org.dromara.demo.domain.bo.XxxBo;
|
|
316
|
+
import org.dromara.demo.domain.vo.XxxVo;
|
|
317
|
+
import org.dromara.demo.mapper.XxxMapper;
|
|
318
|
+
import org.dromara.demo.service.IXxxService;
|
|
319
|
+
import java.util.Collection;
|
|
320
|
+
import java.util.List;
|
|
321
|
+
import java.util.Map;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* XXX 服务实现
|
|
325
|
+
*/
|
|
326
|
+
@Service
|
|
327
|
+
@RequiredArgsConstructor
|
|
328
|
+
public class XxxServiceImpl implements IXxxService { // ✅ 不继承任何基类
|
|
329
|
+
|
|
330
|
+
private final XxxMapper baseMapper; // ✅ 直接注入 Mapper(无 DAO 层)
|
|
331
|
+
|
|
332
|
+
@Override
|
|
333
|
+
public XxxVo queryById(Long id) {
|
|
334
|
+
return baseMapper.selectVoById(id);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
@Override
|
|
338
|
+
public TableDataInfo<XxxVo> queryPageList(XxxBo bo, PageQuery pageQuery) {
|
|
339
|
+
LambdaQueryWrapper<Xxx> lqw = buildQueryWrapper(bo); // ✅ Service 层构建查询
|
|
340
|
+
Page<XxxVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
|
|
341
|
+
return TableDataInfo.build(result);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
@Override
|
|
345
|
+
public List<XxxVo> queryList(XxxBo bo) {
|
|
346
|
+
return baseMapper.selectVoList(buildQueryWrapper(bo));
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
@Override
|
|
350
|
+
public Boolean insertByBo(XxxBo bo) {
|
|
351
|
+
Xxx add = MapstructUtils.convert(bo, Xxx.class); // ✅ MapstructUtils 转换
|
|
352
|
+
validEntityBeforeSave(add);
|
|
353
|
+
return baseMapper.insert(add) > 0;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
@Override
|
|
357
|
+
public Boolean updateByBo(XxxBo bo) {
|
|
358
|
+
Xxx update = MapstructUtils.convert(bo, Xxx.class);
|
|
359
|
+
validEntityBeforeSave(update);
|
|
360
|
+
return baseMapper.updateById(update) > 0;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
@Override
|
|
364
|
+
public Boolean deleteByIds(Collection<Long> ids) {
|
|
365
|
+
return baseMapper.deleteByIds(ids) > 0;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* 构建查询条件
|
|
370
|
+
* ⭐ 在 Service 层构建(不是 DAO 层)
|
|
371
|
+
*/
|
|
372
|
+
private LambdaQueryWrapper<Xxx> buildQueryWrapper(XxxBo bo) {
|
|
373
|
+
Map<String, Object> params = bo.getParams();
|
|
374
|
+
LambdaQueryWrapper<Xxx> lqw = Wrappers.lambdaQuery();
|
|
375
|
+
|
|
376
|
+
// 精确匹配
|
|
377
|
+
lqw.eq(bo.getId() != null, Xxx::getId, bo.getId());
|
|
378
|
+
lqw.eq(StringUtils.isNotBlank(bo.getStatus()), Xxx::getStatus, bo.getStatus());
|
|
379
|
+
|
|
380
|
+
// 模糊匹配
|
|
381
|
+
lqw.like(StringUtils.isNotBlank(bo.getXxxName()), Xxx::getXxxName, bo.getXxxName());
|
|
382
|
+
|
|
383
|
+
// 时间范围
|
|
384
|
+
lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
|
|
385
|
+
Xxx::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
|
|
386
|
+
|
|
387
|
+
// 排序
|
|
388
|
+
lqw.orderByDesc(Xxx::getCreateTime);
|
|
389
|
+
return lqw;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/**
|
|
393
|
+
* 保存前验证
|
|
394
|
+
*/
|
|
395
|
+
private void validEntityBeforeSave(Xxx entity) {
|
|
396
|
+
// 业务校验,如唯一性检查
|
|
397
|
+
if (isNameExists(entity.getXxxName(), entity.getId())) {
|
|
398
|
+
throw new ServiceException("名称已存在");
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private boolean isNameExists(String name, Long excludeId) {
|
|
403
|
+
return baseMapper.exists(Wrappers.<Xxx>lambdaQuery()
|
|
404
|
+
.eq(Xxx::getXxxName, name)
|
|
405
|
+
.ne(excludeId != null, Xxx::getId, excludeId));
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
**关键点**:
|
|
411
|
+
- ✅ **不继承任何基类**(`implements IXxxService`)
|
|
412
|
+
- ✅ **直接注入 Mapper**(无 DAO 层)
|
|
413
|
+
- ✅ **buildQueryWrapper() 在 Service 层**
|
|
414
|
+
- ✅ 使用 `MapstructUtils.convert()` 转换对象
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
### 7. Controller 控制器
|
|
419
|
+
|
|
420
|
+
```java
|
|
421
|
+
package org.dromara.demo.controller;
|
|
422
|
+
|
|
423
|
+
import cn.dev33.satoken.annotation.SaCheckPermission;
|
|
424
|
+
import jakarta.servlet.http.HttpServletResponse;
|
|
425
|
+
import jakarta.validation.constraints.*;
|
|
426
|
+
import lombok.RequiredArgsConstructor;
|
|
427
|
+
import org.dromara.common.core.domain.R;
|
|
428
|
+
import org.dromara.common.core.validate.AddGroup;
|
|
429
|
+
import org.dromara.common.core.validate.EditGroup;
|
|
430
|
+
import org.dromara.common.excel.utils.ExcelUtil;
|
|
431
|
+
import org.dromara.common.log.annotation.Log;
|
|
432
|
+
import org.dromara.common.log.enums.BusinessType;
|
|
433
|
+
import org.dromara.common.mybatis.core.page.PageQuery;
|
|
434
|
+
import org.dromara.common.mybatis.core.page.TableDataInfo;
|
|
435
|
+
import org.dromara.common.web.core.BaseController;
|
|
436
|
+
import org.dromara.demo.domain.bo.XxxBo;
|
|
437
|
+
import org.dromara.demo.domain.vo.XxxVo;
|
|
438
|
+
import org.dromara.demo.service.IXxxService;
|
|
439
|
+
import org.springframework.validation.annotation.Validated;
|
|
440
|
+
import org.springframework.web.bind.annotation.*;
|
|
441
|
+
import java.util.List;
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* XXX 管理控制器
|
|
445
|
+
*/
|
|
446
|
+
@Validated
|
|
447
|
+
@RequiredArgsConstructor
|
|
448
|
+
@RestController
|
|
449
|
+
@RequestMapping("/demo/xxx")
|
|
450
|
+
public class XxxController extends BaseController { // ✅ 继承 BaseController
|
|
451
|
+
|
|
452
|
+
private final IXxxService xxxService;
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* 查询列表
|
|
456
|
+
*/
|
|
457
|
+
@SaCheckPermission("demo:xxx:list")
|
|
458
|
+
@GetMapping("/list") // ✅ 标准路径
|
|
459
|
+
public TableDataInfo<XxxVo> list(XxxBo bo, PageQuery pageQuery) {
|
|
460
|
+
return xxxService.queryPageList(bo, pageQuery);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* 获取详情
|
|
465
|
+
*/
|
|
466
|
+
@SaCheckPermission("demo:xxx:query")
|
|
467
|
+
@GetMapping("/{id}") // ✅ 标准路径
|
|
468
|
+
public R<XxxVo> getInfo(@NotNull(message = "ID不能为空") @PathVariable Long id) {
|
|
469
|
+
return R.ok(xxxService.queryById(id));
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* 新增
|
|
474
|
+
*/
|
|
475
|
+
@SaCheckPermission("demo:xxx:add")
|
|
476
|
+
@Log(title = "XXX管理", businessType = BusinessType.INSERT)
|
|
477
|
+
@PostMapping // ✅ 空路径
|
|
478
|
+
public R<Void> add(@Validated(AddGroup.class) @RequestBody XxxBo bo) {
|
|
479
|
+
return toAjax(xxxService.insertByBo(bo));
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/**
|
|
483
|
+
* 修改
|
|
484
|
+
*/
|
|
485
|
+
@SaCheckPermission("demo:xxx:edit")
|
|
486
|
+
@Log(title = "XXX管理", businessType = BusinessType.UPDATE)
|
|
487
|
+
@PutMapping // ✅ 空路径
|
|
488
|
+
public R<Void> edit(@Validated(EditGroup.class) @RequestBody XxxBo bo) {
|
|
489
|
+
return toAjax(xxxService.updateByBo(bo));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
/**
|
|
493
|
+
* 删除
|
|
494
|
+
*/
|
|
495
|
+
@SaCheckPermission("demo:xxx:remove")
|
|
496
|
+
@Log(title = "XXX管理", businessType = BusinessType.DELETE)
|
|
497
|
+
@DeleteMapping("/{ids}") // ✅ 标准路径
|
|
498
|
+
public R<Void> remove(@NotEmpty(message = "ID不能为空") @PathVariable Long[] ids) {
|
|
499
|
+
return toAjax(xxxService.deleteByIds(List.of(ids)));
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* 导出
|
|
504
|
+
*/
|
|
505
|
+
@SaCheckPermission("demo:xxx:export")
|
|
506
|
+
@Log(title = "XXX管理", businessType = BusinessType.EXPORT)
|
|
507
|
+
@PostMapping("/export")
|
|
508
|
+
public void export(XxxBo bo, HttpServletResponse response) {
|
|
509
|
+
List<XxxVo> list = xxxService.queryList(bo);
|
|
510
|
+
ExcelUtil.exportExcel(list, "XXX数据", XxxVo.class, response);
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
**API 路径规范**:
|
|
516
|
+
|
|
517
|
+
| 操作 | HTTP方法 | 路径格式 |
|
|
518
|
+
|------|---------|---------|
|
|
519
|
+
| 分页查询 | GET | `/list` |
|
|
520
|
+
| 获取详情 | GET | `/{id}` |
|
|
521
|
+
| 新增 | POST | `/`(空) |
|
|
522
|
+
| 修改 | PUT | `/`(空) |
|
|
523
|
+
| 删除 | DELETE | `/{ids}` |
|
|
524
|
+
| 导出 | POST | `/export` |
|
|
525
|
+
|
|
526
|
+
---
|
|
527
|
+
|
|
528
|
+
## 🔧 核心工具类
|
|
529
|
+
|
|
530
|
+
### 对象转换(必须使用)
|
|
531
|
+
|
|
532
|
+
```java
|
|
533
|
+
import org.dromara.common.core.utils.MapstructUtils;
|
|
534
|
+
|
|
535
|
+
// ✅ 单个对象转换
|
|
536
|
+
XxxVo vo = MapstructUtils.convert(entity, XxxVo.class);
|
|
537
|
+
Xxx entity = MapstructUtils.convert(bo, Xxx.class);
|
|
538
|
+
|
|
539
|
+
// ✅ 集合转换
|
|
540
|
+
List<XxxVo> voList = MapstructUtils.convert(entityList, XxxVo.class);
|
|
541
|
+
|
|
542
|
+
// ❌ 禁止使用 BeanUtils
|
|
543
|
+
// BeanUtils.copyProperties(source, target); // 禁止!
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
### 字符串判空
|
|
547
|
+
|
|
548
|
+
```java
|
|
549
|
+
import org.dromara.common.core.utils.StringUtils;
|
|
550
|
+
|
|
551
|
+
// 推荐使用
|
|
552
|
+
StringUtils.isBlank(str); // null / "" / 空白 都返回 true
|
|
553
|
+
StringUtils.isNotBlank(str);
|
|
554
|
+
StringUtils.isEmpty(str); // null / "" 返回 true
|
|
555
|
+
StringUtils.isNotEmpty(str);
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
### 业务异常
|
|
559
|
+
|
|
560
|
+
```java
|
|
561
|
+
import org.dromara.common.core.exception.ServiceException;
|
|
562
|
+
|
|
563
|
+
// 抛出业务异常
|
|
564
|
+
throw new ServiceException("用户不存在");
|
|
565
|
+
throw new ServiceException("用户 {} 不存在", userId);
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
### 集合判空
|
|
569
|
+
|
|
570
|
+
```java
|
|
571
|
+
import cn.hutool.core.collection.CollUtil;
|
|
572
|
+
|
|
573
|
+
CollUtil.isEmpty(list);
|
|
574
|
+
CollUtil.isNotEmpty(list);
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
---
|
|
578
|
+
|
|
579
|
+
## 📊 数据库规范
|
|
580
|
+
|
|
581
|
+
### 建表模板
|
|
582
|
+
|
|
583
|
+
```sql
|
|
584
|
+
CREATE TABLE test_xxx (
|
|
585
|
+
-- 主键(雪花 ID,不用 AUTO_INCREMENT)
|
|
586
|
+
id BIGINT(20) NOT NULL COMMENT '主键ID',
|
|
587
|
+
|
|
588
|
+
-- 多租户字段(必须)
|
|
589
|
+
tenant_id VARCHAR(20) DEFAULT '000000' COMMENT '租户ID',
|
|
590
|
+
|
|
591
|
+
-- 业务字段
|
|
592
|
+
xxx_name VARCHAR(100) NOT NULL COMMENT '名称',
|
|
593
|
+
status CHAR(1) DEFAULT '1' COMMENT '状态(0停用 1正常)',
|
|
594
|
+
|
|
595
|
+
-- 审计字段(必须)
|
|
596
|
+
create_dept BIGINT(20) DEFAULT NULL COMMENT '创建部门',
|
|
597
|
+
create_by BIGINT(20) DEFAULT NULL COMMENT '创建人',
|
|
598
|
+
create_time DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
|
599
|
+
update_by BIGINT(20) DEFAULT NULL COMMENT '更新人',
|
|
600
|
+
update_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
|
601
|
+
|
|
602
|
+
-- 逻辑删除(必须)
|
|
603
|
+
del_flag CHAR(1) DEFAULT '0' COMMENT '删除标志(0正常 1已删除)',
|
|
604
|
+
|
|
605
|
+
PRIMARY KEY (id),
|
|
606
|
+
INDEX idx_tenant_id (tenant_id)
|
|
607
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='XXX表';
|
|
608
|
+
```
|
|
609
|
+
|
|
610
|
+
### 模块与表前缀
|
|
611
|
+
|
|
612
|
+
| 模块 | 表前缀 | 包路径 |
|
|
613
|
+
|------|--------|--------|
|
|
614
|
+
| system | `sys_` | `org.dromara.system` |
|
|
615
|
+
| demo | `test_` | `org.dromara.demo` |
|
|
616
|
+
| workflow | `flow_` | `org.dromara.workflow` |
|
|
617
|
+
| 自定义 | 自定义 | `org.dromara.xxx` |
|
|
618
|
+
|
|
619
|
+
---
|
|
620
|
+
|
|
621
|
+
## ✅ 开发检查清单
|
|
622
|
+
|
|
623
|
+
### 代码规范检查
|
|
624
|
+
|
|
625
|
+
- [ ] **包名是否是 `org.dromara.*`**?
|
|
626
|
+
- [ ] **Service 是否不继承任何基类**?
|
|
627
|
+
- [ ] **Service 是否直接注入 Mapper(无 DAO 层)**?
|
|
628
|
+
- [ ] **buildQueryWrapper() 是否在 Service 层**?
|
|
629
|
+
- [ ] **Entity 是否继承 `TenantEntity`**?
|
|
630
|
+
- [ ] **BO 是否使用 `@AutoMapper`(单数)**?
|
|
631
|
+
- [ ] **是否使用 `MapstructUtils.convert()` 转换对象**?
|
|
632
|
+
- [ ] **Mapper 是否继承 `BaseMapperPlus<Entity, VO>`**?
|
|
633
|
+
- [ ] **Controller 是否继承 `BaseController`**?
|
|
634
|
+
- [ ] **API 路径是否使用标准 RESTful 格式**?
|
|
635
|
+
|
|
636
|
+
### 数据库检查
|
|
637
|
+
|
|
638
|
+
- [ ] **主键是否使用雪花 ID(无 AUTO_INCREMENT)**?
|
|
639
|
+
- [ ] **是否包含 `tenant_id` 字段**?
|
|
640
|
+
- [ ] **是否包含审计字段**?
|
|
641
|
+
- [ ] **是否包含 `del_flag` 逻辑删除字段**?
|
|
642
|
+
|
|
643
|
+
---
|
|
644
|
+
|
|
645
|
+
## ❌ 常见错误
|
|
646
|
+
|
|
647
|
+
### 禁止的写法
|
|
648
|
+
|
|
649
|
+
```java
|
|
650
|
+
// ❌ 错误1: 错误的包名
|
|
651
|
+
package com.ruoyi.xxx; // 禁止!
|
|
652
|
+
package plus.ruoyi.xxx; // 禁止!
|
|
653
|
+
// ✅ 正确: org.dromara.xxx
|
|
654
|
+
|
|
655
|
+
// ❌ 错误2: 使用 DAO 层(本项目无 DAO 层)
|
|
656
|
+
private final IXxxDao xxxDao; // 禁止!
|
|
657
|
+
// ✅ 正确: private final XxxMapper baseMapper;
|
|
658
|
+
|
|
659
|
+
// ❌ 错误3: 使用 BeanUtils
|
|
660
|
+
BeanUtil.copyProperties(bo, entity); // 禁止!
|
|
661
|
+
// ✅ 正确: MapstructUtils.convert(bo, Xxx.class);
|
|
662
|
+
|
|
663
|
+
// ❌ 错误4: Service 继承基类
|
|
664
|
+
public class XxxServiceImpl extends ServiceImpl<XxxMapper, Xxx> { } // 禁止!
|
|
665
|
+
// ✅ 正确: public class XxxServiceImpl implements IXxxService { }
|
|
666
|
+
|
|
667
|
+
// ❌ 错误5: 使用 @AutoMappers(复数)
|
|
668
|
+
@AutoMappers({@AutoMapper(target = Xxx.class)}) // 禁止!
|
|
669
|
+
// ✅ 正确: @AutoMapper(target = Xxx.class)
|
|
670
|
+
|
|
671
|
+
// ❌ 错误6: 使用 Map 传递业务数据
|
|
672
|
+
public Map<String, Object> getXxx() { ... } // 禁止!
|
|
673
|
+
// ✅ 正确: public XxxVo getXxx() { ... }
|
|
674
|
+
|
|
675
|
+
// ❌ 错误7: 使用完整类型引用
|
|
676
|
+
public org.dromara.common.core.domain.R<XxxVo> getXxx() // 禁止!
|
|
677
|
+
// ✅ 正确: 先 import,再使用短类名
|
|
678
|
+
import org.dromara.common.core.domain.R;
|
|
679
|
+
public R<XxxVo> getXxx()
|
|
680
|
+
|
|
681
|
+
// ❌ 错误8: 错误的 API 路径
|
|
682
|
+
@GetMapping("/pageXxxs") // 禁止!
|
|
683
|
+
@GetMapping("/getXxx/{id}") // 禁止!
|
|
684
|
+
// ✅ 正确: @GetMapping("/list"), @GetMapping("/{id}")
|
|
685
|
+
|
|
686
|
+
// ❌ 错误9: 使用自增 ID
|
|
687
|
+
id BIGINT(20) AUTO_INCREMENT // 禁止!
|
|
688
|
+
// ✅ 正确: id BIGINT(20) NOT NULL(使用雪花ID)
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
---
|
|
692
|
+
|
|
693
|
+
## 📚 参考实现
|
|
694
|
+
|
|
695
|
+
查看项目中的标准实现:
|
|
696
|
+
|
|
697
|
+
| 类型 | 参考文件 |
|
|
698
|
+
|------|---------|
|
|
699
|
+
| Entity | `org.dromara.demo.domain.TestDemo` |
|
|
700
|
+
| BO | `org.dromara.demo.domain.bo.TestDemoBo` |
|
|
701
|
+
| VO | `org.dromara.demo.domain.vo.TestDemoVo` |
|
|
702
|
+
| Mapper | `org.dromara.demo.mapper.TestDemoMapper` |
|
|
703
|
+
| Service | `org.dromara.demo.service.impl.TestDemoServiceImpl` |
|
|
704
|
+
| Controller | `org.dromara.demo.controller.TestDemoController` |
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## 🎯 总结
|
|
709
|
+
|
|
710
|
+
**核心原则**:
|
|
711
|
+
|
|
712
|
+
```
|
|
713
|
+
1️⃣ 包名是 org.dromara.*
|
|
714
|
+
2️⃣ 三层架构:Controller → Service → Mapper(无 DAO 层)
|
|
715
|
+
3️⃣ Service 直接注入 Mapper
|
|
716
|
+
4️⃣ buildQueryWrapper() 在 Service 层
|
|
717
|
+
5️⃣ 使用 MapstructUtils.convert() 转换对象
|
|
718
|
+
6️⃣ 主键使用雪花 ID
|
|
719
|
+
7️⃣ RESTful API 路径规范
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**开发流程**:
|
|
723
|
+
|
|
724
|
+
```
|
|
725
|
+
需求分析 → 数据库设计 → Entity → BO/VO → Mapper → Service → Controller → 测试
|
|
726
|
+
```
|