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.
Files changed (313) hide show
  1. package/.claude/agents/code-reviewer.md +139 -0
  2. package/.claude/agents/project-manager.md +159 -0
  3. package/.claude/audio/completed.wav +0 -0
  4. package/.claude/commands/add-todo.md +255 -0
  5. package/.claude/commands/check.md +210 -0
  6. package/.claude/commands/crud.md +454 -0
  7. package/.claude/commands/dev.md +503 -0
  8. package/.claude/commands/init-docs.md +681 -0
  9. package/.claude/commands/next.md +251 -0
  10. package/.claude/commands/progress.md +242 -0
  11. package/.claude/commands/start.md +199 -0
  12. package/.claude/commands/sync.md +307 -0
  13. package/.claude/commands/update-status.md +428 -0
  14. package/.claude/docs/Mixin/344/275/277/347/224/250/346/214/207/345/215/227.md +299 -0
  15. package/.claude/docs/README.md +167 -0
  16. package/.claude/docs//345/211/215/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +599 -0
  17. package/.claude/docs//345/220/216/347/253/257/345/274/200/345/217/221/346/214/207/345/215/227.md +726 -0
  18. 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
  19. 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
  20. 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
  21. 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
  22. 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
  23. package/.claude/docs//346/241/206/346/236/266/350/257/264/346/230/216.md +393 -0
  24. package/.claude/docs//350/267/257/347/224/261/351/205/215/347/275/256/346/214/207/345/215/227.md +246 -0
  25. package/.claude/framework-config.json +73 -0
  26. package/.claude/hooks/pre-tool-use.js +117 -0
  27. package/.claude/hooks/skill-forced-eval.js +167 -0
  28. package/.claude/hooks/stop.js +58 -0
  29. package/.claude/settings.json +41 -0
  30. package/.claude/skills/add-skill/SKILL.md +352 -0
  31. package/.claude/skills/api-development/SKILL.md +560 -0
  32. package/.claude/skills/architecture-design/SKILL.md +756 -0
  33. package/.claude/skills/backend-annotations/SKILL.md +674 -0
  34. package/.claude/skills/banana-image/CHANGELOG.md +37 -0
  35. package/.claude/skills/banana-image/README.md +146 -0
  36. package/.claude/skills/banana-image/SKILL.md +164 -0
  37. package/.claude/skills/banana-image/assets/logo.png +0 -0
  38. package/.claude/skills/banana-image/references/advanced-usage.md +189 -0
  39. package/.claude/skills/banana-image/scripts/apply_template.py +125 -0
  40. package/.claude/skills/banana-image/scripts/banana_image_exec.ts +412 -0
  41. package/.claude/skills/banana-image/scripts/batch_prep.py +82 -0
  42. package/.claude/skills/banana-image/scripts/package-lock.json +1437 -0
  43. package/.claude/skills/banana-image/scripts/package.json +18 -0
  44. package/.claude/skills/banana-image/scripts/requirements.txt +10 -0
  45. package/.claude/skills/banana-image/templates/poster.json +22 -0
  46. package/.claude/skills/banana-image/templates/product.json +17 -0
  47. package/.claude/skills/banana-image/templates/social.json +22 -0
  48. package/.claude/skills/banana-image/templates/thumbnail.json +17 -0
  49. package/.claude/skills/brainstorm/SKILL.md +648 -0
  50. package/.claude/skills/bug-detective/SKILL.md +1206 -0
  51. package/.claude/skills/code-patterns/SKILL.md +590 -0
  52. package/.claude/skills/collaborating-with-codex/SKILL.md +174 -0
  53. package/.claude/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
  54. package/.claude/skills/collaborating-with-gemini/SKILL.md +194 -0
  55. package/.claude/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
  56. package/.claude/skills/crud-development/SKILL.md +649 -0
  57. package/.claude/skills/data-permission/SKILL.md +599 -0
  58. package/.claude/skills/database-ops/SKILL.md +407 -0
  59. package/.claude/skills/error-handler/SKILL.md +371 -0
  60. package/.claude/skills/file-oss-management/SKILL.md +863 -0
  61. package/.claude/skills/git-workflow/SKILL.md +375 -0
  62. package/.claude/skills/json-serialization/SKILL.md +357 -0
  63. package/.claude/skills/leniu-api-development/SKILL.md +803 -0
  64. package/.claude/skills/leniu-architecture-design/SKILL.md +598 -0
  65. package/.claude/skills/leniu-backend-annotations/SKILL.md +664 -0
  66. package/.claude/skills/leniu-code-patterns/SKILL.md +365 -0
  67. package/.claude/skills/leniu-crud-development/SKILL.md +1110 -0
  68. package/.claude/skills/leniu-data-permission/SKILL.md +256 -0
  69. package/.claude/skills/leniu-database-ops/SKILL.md +426 -0
  70. package/.claude/skills/leniu-error-handler/SKILL.md +462 -0
  71. package/.claude/skills/leniu-java-amount-handling/SKILL.md +461 -0
  72. package/.claude/skills/leniu-java-code-style/SKILL.md +510 -0
  73. package/.claude/skills/leniu-java-concurrent/SKILL.md +400 -0
  74. package/.claude/skills/leniu-java-entity/SKILL.md +751 -0
  75. package/.claude/skills/leniu-java-export/SKILL.md +560 -0
  76. package/.claude/skills/leniu-java-logging/SKILL.md +832 -0
  77. package/.claude/skills/leniu-java-mq/SKILL.md +338 -0
  78. package/.claude/skills/leniu-java-mybatis/SKILL.md +640 -0
  79. package/.claude/skills/leniu-java-report-query-param/SKILL.md +291 -0
  80. package/.claude/skills/leniu-java-task/SKILL.md +367 -0
  81. package/.claude/skills/leniu-java-total-line/SKILL.md +195 -0
  82. package/.claude/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
  83. package/.claude/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
  84. package/.claude/skills/leniu-mealtime/SKILL.md +215 -0
  85. package/.claude/skills/leniu-redis-cache/SKILL.md +316 -0
  86. package/.claude/skills/leniu-security-guard/SKILL.md +520 -0
  87. package/.claude/skills/leniu-utils-toolkit/SKILL.md +380 -0
  88. package/.claude/skills/openspec-apply-change/SKILL.md +156 -0
  89. package/.claude/skills/openspec-archive-change/SKILL.md +114 -0
  90. package/.claude/skills/openspec-bulk-archive-change/SKILL.md +246 -0
  91. package/.claude/skills/openspec-continue-change/SKILL.md +118 -0
  92. package/.claude/skills/openspec-explore/SKILL.md +290 -0
  93. package/.claude/skills/openspec-ff-change/SKILL.md +101 -0
  94. package/.claude/skills/openspec-new-change/SKILL.md +74 -0
  95. package/.claude/skills/openspec-onboard/SKILL.md +529 -0
  96. package/.claude/skills/openspec-sync-specs/SKILL.md +138 -0
  97. package/.claude/skills/openspec-verify-change/SKILL.md +168 -0
  98. package/.claude/skills/performance-doctor/SKILL.md +627 -0
  99. package/.claude/skills/project-navigator/SKILL.md +305 -0
  100. package/.claude/skills/redis-cache/SKILL.md +839 -0
  101. package/.claude/skills/scheduled-jobs/SKILL.md +633 -0
  102. package/.claude/skills/security-guard/SKILL.md +748 -0
  103. package/.claude/skills/sms-mail/SKILL.md +766 -0
  104. package/.claude/skills/social-login/SKILL.md +668 -0
  105. package/.claude/skills/store-pc/SKILL.md +366 -0
  106. package/.claude/skills/task-tracker/SKILL.md +307 -0
  107. package/.claude/skills/tech-decision/SKILL.md +393 -0
  108. package/.claude/skills/tenant-management/SKILL.md +603 -0
  109. package/.claude/skills/test-development/SKILL.md +755 -0
  110. package/.claude/skills/ui-pc/SKILL.md +438 -0
  111. package/.claude/skills/utils-toolkit/SKILL.md +615 -0
  112. package/.claude/skills/websocket-sse/SKILL.md +716 -0
  113. package/.claude/skills/workflow-engine/SKILL.md +676 -0
  114. package/.claude/templates//345/276/205/345/212/236/346/270/205/345/215/225/346/250/241/346/235/277.md +56 -0
  115. package/.claude/templates//351/234/200/346/261/202/346/226/207/346/241/243/346/250/241/346/235/277.md +85 -0
  116. package/.claude/templates//351/241/271/347/233/256/347/212/266/346/200/201/346/250/241/346/235/277.md +43 -0
  117. package/.codex/skills/add-skill/SKILL.md +352 -0
  118. package/.codex/skills/add-todo/SKILL.md +269 -0
  119. package/.codex/skills/api-development/SKILL.md +693 -0
  120. package/.codex/skills/architecture-design/SKILL.md +628 -0
  121. package/.codex/skills/backend-annotations/SKILL.md +664 -0
  122. package/.codex/skills/banana-image/CHANGELOG.md +37 -0
  123. package/.codex/skills/banana-image/README.md +146 -0
  124. package/.codex/skills/banana-image/SKILL.md +164 -0
  125. package/.codex/skills/banana-image/assets/logo.png +0 -0
  126. package/.codex/skills/banana-image/references/advanced-usage.md +189 -0
  127. package/.codex/skills/banana-image/scripts/apply_template.py +125 -0
  128. package/.codex/skills/banana-image/scripts/banana_image_exec.ts +412 -0
  129. package/.codex/skills/banana-image/scripts/batch_prep.py +82 -0
  130. package/.codex/skills/banana-image/scripts/package-lock.json +1437 -0
  131. package/.codex/skills/banana-image/scripts/package.json +18 -0
  132. package/.codex/skills/banana-image/scripts/requirements.txt +10 -0
  133. package/.codex/skills/banana-image/templates/poster.json +22 -0
  134. package/.codex/skills/banana-image/templates/product.json +17 -0
  135. package/.codex/skills/banana-image/templates/social.json +22 -0
  136. package/.codex/skills/banana-image/templates/thumbnail.json +17 -0
  137. package/.codex/skills/brainstorm/SKILL.md +648 -0
  138. package/.codex/skills/bug-detective/SKILL.md +1206 -0
  139. package/.codex/skills/check/SKILL.md +367 -0
  140. package/.codex/skills/code-patterns/SKILL.md +442 -0
  141. package/.codex/skills/collaborating-with-codex/SKILL.md +174 -0
  142. package/.codex/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
  143. package/.codex/skills/collaborating-with-gemini/SKILL.md +194 -0
  144. package/.codex/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
  145. package/.codex/skills/crud/SKILL.md +265 -0
  146. package/.codex/skills/crud-development/SKILL.md +637 -0
  147. package/.codex/skills/data-permission/SKILL.md +591 -0
  148. package/.codex/skills/database-ops/SKILL.md +553 -0
  149. package/.codex/skills/dev/SKILL.md +187 -0
  150. package/.codex/skills/error-handler/SKILL.md +361 -0
  151. package/.codex/skills/file-oss-management/SKILL.md +863 -0
  152. package/.codex/skills/git-workflow/SKILL.md +375 -0
  153. package/.codex/skills/init-docs/SKILL.md +194 -0
  154. package/.codex/skills/json-serialization/SKILL.md +357 -0
  155. package/.codex/skills/leniu-api-development/SKILL.md +803 -0
  156. package/.codex/skills/leniu-architecture-design/SKILL.md +594 -0
  157. package/.codex/skills/leniu-backend-annotations/SKILL.md +662 -0
  158. package/.codex/skills/leniu-code-patterns/SKILL.md +365 -0
  159. package/.codex/skills/leniu-crud-development/SKILL.md +1110 -0
  160. package/.codex/skills/leniu-data-permission/SKILL.md +256 -0
  161. package/.codex/skills/leniu-database-ops/SKILL.md +426 -0
  162. package/.codex/skills/leniu-error-handler/SKILL.md +462 -0
  163. package/.codex/skills/leniu-java-amount-handling/SKILL.md +461 -0
  164. package/.codex/skills/leniu-java-code-style/SKILL.md +510 -0
  165. package/.codex/skills/leniu-java-concurrent/SKILL.md +400 -0
  166. package/.codex/skills/leniu-java-entity/SKILL.md +751 -0
  167. package/.codex/skills/leniu-java-export/SKILL.md +560 -0
  168. package/.codex/skills/leniu-java-logging/SKILL.md +832 -0
  169. package/.codex/skills/leniu-java-mq/SKILL.md +338 -0
  170. package/.codex/skills/leniu-java-mybatis/SKILL.md +640 -0
  171. package/.codex/skills/leniu-java-report-query-param/SKILL.md +291 -0
  172. package/.codex/skills/leniu-java-task/SKILL.md +367 -0
  173. package/.codex/skills/leniu-java-total-line/SKILL.md +195 -0
  174. package/.codex/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
  175. package/.codex/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
  176. package/.codex/skills/leniu-mealtime/SKILL.md +215 -0
  177. package/.codex/skills/leniu-redis-cache/SKILL.md +316 -0
  178. package/.codex/skills/leniu-security-guard/SKILL.md +520 -0
  179. package/.codex/skills/leniu-utils-toolkit/SKILL.md +378 -0
  180. package/.codex/skills/next/SKILL.md +137 -0
  181. package/.codex/skills/openspec-apply-change/SKILL.md +156 -0
  182. package/.codex/skills/openspec-archive-change/SKILL.md +114 -0
  183. package/.codex/skills/openspec-bulk-archive-change/SKILL.md +246 -0
  184. package/.codex/skills/openspec-continue-change/SKILL.md +118 -0
  185. package/.codex/skills/openspec-explore/SKILL.md +290 -0
  186. package/.codex/skills/openspec-ff-change/SKILL.md +101 -0
  187. package/.codex/skills/openspec-new-change/SKILL.md +74 -0
  188. package/.codex/skills/openspec-onboard/SKILL.md +529 -0
  189. package/.codex/skills/openspec-sync-specs/SKILL.md +138 -0
  190. package/.codex/skills/openspec-verify-change/SKILL.md +168 -0
  191. package/.codex/skills/performance-doctor/SKILL.md +627 -0
  192. package/.codex/skills/progress/SKILL.md +193 -0
  193. package/.codex/skills/project-navigator/SKILL.md +286 -0
  194. package/.codex/skills/redis-cache/SKILL.md +829 -0
  195. package/.codex/skills/scheduled-jobs/SKILL.md +633 -0
  196. package/.codex/skills/security-guard/SKILL.md +739 -0
  197. package/.codex/skills/sms-mail/SKILL.md +766 -0
  198. package/.codex/skills/social-login/SKILL.md +668 -0
  199. package/.codex/skills/start/SKILL.md +154 -0
  200. package/.codex/skills/store-pc/SKILL.md +491 -0
  201. package/.codex/skills/sync/SKILL.md +149 -0
  202. package/.codex/skills/task-tracker/SKILL.md +307 -0
  203. package/.codex/skills/tech-decision/SKILL.md +393 -0
  204. package/.codex/skills/tenant-management/SKILL.md +603 -0
  205. package/.codex/skills/test-development/SKILL.md +755 -0
  206. package/.codex/skills/ui-pc/SKILL.md +475 -0
  207. package/.codex/skills/update-status/SKILL.md +159 -0
  208. package/.codex/skills/utils-toolkit/SKILL.md +593 -0
  209. package/.codex/skills/websocket-sse/SKILL.md +716 -0
  210. package/.codex/skills/workflow-engine/SKILL.md +676 -0
  211. package/.cursor/agents/code-reviewer.md +139 -0
  212. package/.cursor/agents/project-manager.md +159 -0
  213. package/.cursor/commands/opsx-apply.md +152 -0
  214. package/.cursor/commands/opsx-archive.md +157 -0
  215. package/.cursor/commands/opsx-bulk-archive.md +242 -0
  216. package/.cursor/commands/opsx-continue.md +114 -0
  217. package/.cursor/commands/opsx-explore.md +174 -0
  218. package/.cursor/commands/opsx-ff.md +94 -0
  219. package/.cursor/commands/opsx-new.md +69 -0
  220. package/.cursor/commands/opsx-onboard.md +525 -0
  221. package/.cursor/commands/opsx-sync.md +134 -0
  222. package/.cursor/commands/opsx-verify.md +164 -0
  223. package/.cursor/mcp.json +22 -0
  224. package/.cursor/skills/add-skill/SKILL.md +352 -0
  225. package/.cursor/skills/api-development/SKILL.md +560 -0
  226. package/.cursor/skills/architecture-design/SKILL.md +756 -0
  227. package/.cursor/skills/backend-annotations/SKILL.md +674 -0
  228. package/.cursor/skills/banana-image/CHANGELOG.md +37 -0
  229. package/.cursor/skills/banana-image/README.md +146 -0
  230. package/.cursor/skills/banana-image/SKILL.md +164 -0
  231. package/.cursor/skills/banana-image/assets/logo.png +0 -0
  232. package/.cursor/skills/banana-image/references/advanced-usage.md +189 -0
  233. package/.cursor/skills/banana-image/scripts/apply_template.py +125 -0
  234. package/.cursor/skills/banana-image/scripts/banana_image_exec.ts +412 -0
  235. package/.cursor/skills/banana-image/scripts/batch_prep.py +82 -0
  236. package/.cursor/skills/banana-image/scripts/package-lock.json +1437 -0
  237. package/.cursor/skills/banana-image/scripts/package.json +18 -0
  238. package/.cursor/skills/banana-image/scripts/requirements.txt +10 -0
  239. package/.cursor/skills/banana-image/templates/poster.json +22 -0
  240. package/.cursor/skills/banana-image/templates/product.json +17 -0
  241. package/.cursor/skills/banana-image/templates/social.json +22 -0
  242. package/.cursor/skills/banana-image/templates/thumbnail.json +17 -0
  243. package/.cursor/skills/brainstorm/SKILL.md +648 -0
  244. package/.cursor/skills/bug-detective/SKILL.md +1206 -0
  245. package/.cursor/skills/code-patterns/SKILL.md +590 -0
  246. package/.cursor/skills/collaborating-with-codex/SKILL.md +174 -0
  247. package/.cursor/skills/collaborating-with-codex/scripts/codex_bridge.py +275 -0
  248. package/.cursor/skills/collaborating-with-gemini/SKILL.md +194 -0
  249. package/.cursor/skills/collaborating-with-gemini/scripts/gemini_bridge.py +275 -0
  250. package/.cursor/skills/crud-development/SKILL.md +649 -0
  251. package/.cursor/skills/data-permission/SKILL.md +599 -0
  252. package/.cursor/skills/database-ops/SKILL.md +407 -0
  253. package/.cursor/skills/error-handler/SKILL.md +371 -0
  254. package/.cursor/skills/file-oss-management/SKILL.md +863 -0
  255. package/.cursor/skills/git-workflow/SKILL.md +375 -0
  256. package/.cursor/skills/json-serialization/SKILL.md +357 -0
  257. package/.cursor/skills/leniu-api-development/SKILL.md +803 -0
  258. package/.cursor/skills/leniu-architecture-design/SKILL.md +598 -0
  259. package/.cursor/skills/leniu-backend-annotations/SKILL.md +664 -0
  260. package/.cursor/skills/leniu-code-patterns/SKILL.md +365 -0
  261. package/.cursor/skills/leniu-crud-development/SKILL.md +1110 -0
  262. package/.cursor/skills/leniu-data-permission/SKILL.md +256 -0
  263. package/.cursor/skills/leniu-database-ops/SKILL.md +426 -0
  264. package/.cursor/skills/leniu-error-handler/SKILL.md +462 -0
  265. package/.cursor/skills/leniu-java-amount-handling/SKILL.md +461 -0
  266. package/.cursor/skills/leniu-java-code-style/SKILL.md +510 -0
  267. package/.cursor/skills/leniu-java-concurrent/SKILL.md +400 -0
  268. package/.cursor/skills/leniu-java-entity/SKILL.md +751 -0
  269. package/.cursor/skills/leniu-java-export/SKILL.md +560 -0
  270. package/.cursor/skills/leniu-java-logging/SKILL.md +832 -0
  271. package/.cursor/skills/leniu-java-mq/SKILL.md +338 -0
  272. package/.cursor/skills/leniu-java-mybatis/SKILL.md +640 -0
  273. package/.cursor/skills/leniu-java-report-query-param/SKILL.md +291 -0
  274. package/.cursor/skills/leniu-java-task/SKILL.md +367 -0
  275. package/.cursor/skills/leniu-java-total-line/SKILL.md +195 -0
  276. package/.cursor/skills/leniu-marketing-price-rule-customizer/SKILL.md +301 -0
  277. package/.cursor/skills/leniu-marketing-recharge-rule-customizer/SKILL.md +285 -0
  278. package/.cursor/skills/leniu-mealtime/SKILL.md +215 -0
  279. package/.cursor/skills/leniu-redis-cache/SKILL.md +316 -0
  280. package/.cursor/skills/leniu-security-guard/SKILL.md +520 -0
  281. package/.cursor/skills/leniu-utils-toolkit/SKILL.md +380 -0
  282. package/.cursor/skills/openspec-apply-change/SKILL.md +156 -0
  283. package/.cursor/skills/openspec-archive-change/SKILL.md +114 -0
  284. package/.cursor/skills/openspec-bulk-archive-change/SKILL.md +246 -0
  285. package/.cursor/skills/openspec-continue-change/SKILL.md +118 -0
  286. package/.cursor/skills/openspec-explore/SKILL.md +290 -0
  287. package/.cursor/skills/openspec-ff-change/SKILL.md +101 -0
  288. package/.cursor/skills/openspec-new-change/SKILL.md +74 -0
  289. package/.cursor/skills/openspec-onboard/SKILL.md +529 -0
  290. package/.cursor/skills/openspec-sync-specs/SKILL.md +138 -0
  291. package/.cursor/skills/openspec-verify-change/SKILL.md +168 -0
  292. package/.cursor/skills/performance-doctor/SKILL.md +627 -0
  293. package/.cursor/skills/project-navigator/SKILL.md +305 -0
  294. package/.cursor/skills/redis-cache/SKILL.md +839 -0
  295. package/.cursor/skills/scheduled-jobs/SKILL.md +633 -0
  296. package/.cursor/skills/security-guard/SKILL.md +748 -0
  297. package/.cursor/skills/sms-mail/SKILL.md +766 -0
  298. package/.cursor/skills/social-login/SKILL.md +668 -0
  299. package/.cursor/skills/store-pc/SKILL.md +366 -0
  300. package/.cursor/skills/task-tracker/SKILL.md +307 -0
  301. package/.cursor/skills/tech-decision/SKILL.md +393 -0
  302. package/.cursor/skills/tenant-management/SKILL.md +603 -0
  303. package/.cursor/skills/test-development/SKILL.md +755 -0
  304. package/.cursor/skills/ui-pc/SKILL.md +438 -0
  305. package/.cursor/skills/utils-toolkit/SKILL.md +615 -0
  306. package/.cursor/skills/websocket-sse/SKILL.md +716 -0
  307. package/.cursor/skills/workflow-engine/SKILL.md +676 -0
  308. package/AGENTS.md +669 -0
  309. package/CLAUDE.md +205 -0
  310. package/README.md +205 -0
  311. package/bin/index.js +179 -0
  312. package/init.sh +178 -0
  313. package/package.json +27 -0
@@ -0,0 +1,766 @@
1
+ ---
2
+ name: sms-mail
3
+ description: |
4
+ 当需要发送短信、邮件通知时自动使用此 Skill。
5
+
6
+ 触发场景:
7
+ - 需要发送短信验证码
8
+ - 需要发送邮件通知(文本/HTML)
9
+ - 需要配置短信服务商(阿里云/腾讯云/华为云等)
10
+ - 需要配置邮件服务器(SMTP)
11
+ - 需要实现多渠道消息通知
12
+
13
+ 触发词:短信、邮件、SMS、验证码、通知、SMS4j、MailUtils、邮件发送、短信发送、SmsBlend、SmsFactory、SMTP、模板消息
14
+ ---
15
+
16
+ # 短信与邮件开发指南
17
+
18
+ > **适用模块**:`ruoyi-common-sms`(SMS4j)、`ruoyi-common-mail`(Hutool Mail)
19
+
20
+ ## 概述
21
+
22
+ 本框架提供两种消息通知方案:
23
+
24
+ | 方案 | 模块 | 技术栈 | 适用场景 |
25
+ |------|------|--------|---------|
26
+ | **短信** | `ruoyi-common-sms` | SMS4j | 验证码、营销短信、通知短信 |
27
+ | **邮件** | `ruoyi-common-mail` | Hutool JakartaMail | 系统通知、报表发送、验证邮件 |
28
+
29
+ **共同特性**:
30
+ - ✅ 多供应商支持
31
+ - ✅ 模板消息
32
+ - ✅ 配置热更新
33
+
34
+ ---
35
+
36
+ ## 一、短信开发指南(SMS4j)
37
+
38
+ ### 1.1 支持的短信服务商
39
+
40
+ SMS4j 支持多种短信服务商,开箱即用:
41
+
42
+ | 服务商 | 配置标识 | 说明 |
43
+ |--------|---------|------|
44
+ | 阿里云 | `alibaba` | 阿里云短信服务 |
45
+ | 腾讯云 | `tencent` | 腾讯云短信 |
46
+ | 华为云 | `huawei` | 华为云短信 |
47
+ | 云片 | `yunpian` | 云片短信 |
48
+ | 合一 | `unisms` | 合一短信 |
49
+ | 京东云 | `jdcloud` | 京东云短信 |
50
+ | 容联云 | `cloopen` | 容联云通讯 |
51
+ | 亿美软通 | `emay` | 亿美短信 |
52
+ | 天翼云 | `ctyun` | 天翼云短信 |
53
+
54
+ ### 1.2 配置短信服务
55
+
56
+ ```yaml
57
+ # application.yml
58
+ sms:
59
+ # 配置源类型:yaml(默认)、接口、数据库
60
+ config-type: yaml
61
+
62
+ # 短信配置列表
63
+ blends:
64
+ # 配置标识(可自定义,用于 SmsFactory.getSmsBlend("config1"))
65
+ config1:
66
+ # 供应商类型
67
+ supplier: alibaba
68
+ # AccessKey ID
69
+ access-key-id: your-access-key-id
70
+ # AccessKey Secret
71
+ access-key-secret: your-access-key-secret
72
+ # 短信签名
73
+ signature: 若依框架
74
+ # SDK AppId(腾讯云需要)
75
+ sdk-app-id: ""
76
+
77
+ # 可配置多个供应商
78
+ config2:
79
+ supplier: tencent
80
+ access-key-id: your-tencent-secret-id
81
+ access-key-secret: your-tencent-secret-key
82
+ signature: 若依框架
83
+ sdk-app-id: "1400000000"
84
+ ```
85
+
86
+ ### 1.3 核心 API:SmsBlend
87
+
88
+ **位置**:`org.dromara.sms4j.api.SmsBlend`(SMS4j 库)
89
+
90
+ ```java
91
+ import org.dromara.sms4j.api.SmsBlend;
92
+ import org.dromara.sms4j.api.entity.SmsResponse;
93
+ import org.dromara.sms4j.core.factory.SmsFactory;
94
+
95
+ // ========== 获取短信实例 ==========
96
+
97
+ // 1. 获取默认配置的短信实例
98
+ SmsBlend smsBlend = SmsFactory.getSmsBlend();
99
+
100
+ // 2. 获取指定配置的短信实例
101
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); // 阿里云
102
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config2"); // 腾讯云
103
+
104
+ // ========== 发送短信 ==========
105
+
106
+ // 3. 发送模板短信(推荐)
107
+ Map<String, String> templateParams = new LinkedHashMap<>();
108
+ templateParams.put("code", "123456");
109
+ templateParams.put("time", "5");
110
+
111
+ SmsResponse response = smsBlend.sendMessage(
112
+ "13800138000", // 手机号
113
+ "SMS_123456789", // 模板ID
114
+ templateParams // 模板参数
115
+ );
116
+
117
+ // 4. 检查发送结果
118
+ if (response.isSuccess()) {
119
+ log.info("短信发送成功,msgId: {}", response.getBizId());
120
+ } else {
121
+ log.error("短信发送失败:{}", response.getMessage());
122
+ }
123
+
124
+ // 5. 批量发送短信
125
+ List<String> phones = Arrays.asList("13800138001", "13800138002");
126
+ SmsResponse response = smsBlend.sendMessage(phones, "SMS_123456789", templateParams);
127
+ ```
128
+
129
+ ### 1.4 发送验证码短信示例
130
+
131
+ ```java
132
+ @RestController
133
+ @RequestMapping("/captcha")
134
+ @RequiredArgsConstructor
135
+ public class CaptchaController {
136
+
137
+ private final RedisUtils redisUtils;
138
+
139
+ /**
140
+ * 发送短信验证码
141
+ */
142
+ @GetMapping("/sms")
143
+ public R<Void> sendSmsCode(@RequestParam String phonenumber) {
144
+ // 1. 生成验证码
145
+ String code = RandomUtil.randomNumbers(6);
146
+
147
+ // 2. 存入 Redis(5分钟有效)
148
+ String cacheKey = "sms:code:" + phonenumber;
149
+ RedisUtils.setCacheObject(cacheKey, code, Duration.ofMinutes(5));
150
+
151
+ // 3. 构建模板参数
152
+ Map<String, String> map = new LinkedHashMap<>();
153
+ map.put("code", code);
154
+
155
+ // 4. 发送短信
156
+ String templateId = "SMS_123456789"; // 短信模板ID
157
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
158
+ SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
159
+
160
+ // 5. 处理结果
161
+ if (!smsResponse.isSuccess()) {
162
+ log.error("短信发送失败:{}", smsResponse.getMessage());
163
+ return R.fail("短信发送失败");
164
+ }
165
+
166
+ return R.ok("验证码已发送");
167
+ }
168
+
169
+ /**
170
+ * 验证短信验证码
171
+ */
172
+ @PostMapping("/verify")
173
+ public R<Boolean> verifySmsCode(@RequestParam String phonenumber,
174
+ @RequestParam String code) {
175
+ String cacheKey = "sms:code:" + phonenumber;
176
+ String cachedCode = RedisUtils.getCacheObject(cacheKey);
177
+
178
+ if (cachedCode == null) {
179
+ return R.fail("验证码已过期");
180
+ }
181
+
182
+ if (!cachedCode.equals(code)) {
183
+ return R.fail("验证码错误");
184
+ }
185
+
186
+ // 验证成功,删除缓存
187
+ RedisUtils.deleteObject(cacheKey);
188
+ return R.ok(true);
189
+ }
190
+ }
191
+ ```
192
+
193
+ ### 1.5 业务通知短信示例
194
+
195
+ ```java
196
+ @Service
197
+ @RequiredArgsConstructor
198
+ public class OrderNotifyService {
199
+
200
+ /**
201
+ * 订单发货通知
202
+ */
203
+ public void notifyShipment(Order order) {
204
+ Map<String, String> params = new LinkedHashMap<>();
205
+ params.put("orderNo", order.getOrderNo());
206
+ params.put("expressNo", order.getExpressNo());
207
+ params.put("expressCompany", order.getExpressCompany());
208
+
209
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
210
+ SmsResponse response = smsBlend.sendMessage(
211
+ order.getPhone(),
212
+ "SMS_SHIPMENT_NOTIFY", // 发货通知模板
213
+ params
214
+ );
215
+
216
+ if (!response.isSuccess()) {
217
+ log.error("发货通知短信发送失败,订单号:{},错误:{}",
218
+ order.getOrderNo(), response.getMessage());
219
+ }
220
+ }
221
+
222
+ /**
223
+ * 批量发送营销短信
224
+ */
225
+ public void sendMarketingSms(List<String> phones, String content) {
226
+ Map<String, String> params = new LinkedHashMap<>();
227
+ params.put("content", content);
228
+
229
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
230
+ SmsResponse response = smsBlend.sendMessage(
231
+ phones,
232
+ "SMS_MARKETING",
233
+ params
234
+ );
235
+
236
+ log.info("营销短信发送结果:成功={}, 消息={}",
237
+ response.isSuccess(), response.getMessage());
238
+ }
239
+ }
240
+ ```
241
+
242
+ ---
243
+
244
+ ## 二、邮件开发指南(Hutool Mail)
245
+
246
+ ### 2.1 配置邮件服务
247
+
248
+ ```yaml
249
+ # application.yml
250
+ mail:
251
+ enabled: true
252
+ # SMTP 服务器
253
+ host: smtp.163.com
254
+ # SMTP 端口
255
+ port: 465
256
+ # 是否需要认证
257
+ auth: true
258
+ # 发件人邮箱
259
+ from: xxx@163.com
260
+ # 用户名(通常与发件人相同)
261
+ user: xxx@163.com
262
+ # 密码(授权码,非登录密码)
263
+ pass: your-smtp-password
264
+ # 使用 SSL
265
+ sslEnable: true
266
+ # 使用 STARTTLS
267
+ starttlsEnable: false
268
+ # 超时时间(毫秒)
269
+ timeout: 10000
270
+ connectionTimeout: 10000
271
+ ```
272
+
273
+ ### 2.2 常用 SMTP 服务器配置
274
+
275
+ | 邮箱服务商 | SMTP 服务器 | SSL 端口 | 非 SSL 端口 |
276
+ |-----------|-------------|---------|------------|
277
+ | 163 邮箱 | smtp.163.com | 465 | 25 |
278
+ | QQ 邮箱 | smtp.qq.com | 465 | 587 |
279
+ | 阿里企业邮箱 | smtp.mxhichina.com | 465 | 25 |
280
+ | 腾讯企业邮箱 | smtp.exmail.qq.com | 465 | 587 |
281
+ | Gmail | smtp.gmail.com | 465 | 587 |
282
+ | Outlook | smtp.office365.com | 587 | 587 |
283
+
284
+ ### 2.3 核心工具类:MailUtils
285
+
286
+ **位置**:`org.dromara.common.mail.utils.MailUtils`
287
+
288
+ ```java
289
+ import org.dromara.common.mail.utils.MailUtils;
290
+
291
+ // ========== 发送文本邮件 ==========
292
+
293
+ // 1. 发送简单文本邮件
294
+ String messageId = MailUtils.sendText(
295
+ "recipient@example.com", // 收件人
296
+ "邮件标题", // 标题
297
+ "这是邮件正文内容" // 正文
298
+ );
299
+
300
+ // 2. 发送文本邮件(带附件)
301
+ File attachment = new File("/path/to/file.pdf");
302
+ String messageId = MailUtils.sendText(
303
+ "recipient@example.com",
304
+ "带附件的邮件",
305
+ "请查看附件",
306
+ attachment
307
+ );
308
+
309
+ // ========== 发送 HTML 邮件 ==========
310
+
311
+ // 3. 发送 HTML 邮件
312
+ String htmlContent = """
313
+ <h1>欢迎注册</h1>
314
+ <p>您的验证码是:<strong>123456</strong></p>
315
+ <p>有效期5分钟</p>
316
+ """;
317
+
318
+ String messageId = MailUtils.sendHtml(
319
+ "recipient@example.com",
320
+ "验证码邮件",
321
+ htmlContent
322
+ );
323
+
324
+ // 4. 发送 HTML 邮件(带内嵌图片)
325
+ Map<String, InputStream> imageMap = new HashMap<>();
326
+ imageMap.put("logo", new FileInputStream("/path/to/logo.png"));
327
+
328
+ String htmlWithImage = """
329
+ <h1>欢迎使用若依系统</h1>
330
+ <img src="cid:logo" alt="Logo"/>
331
+ """;
332
+
333
+ String messageId = MailUtils.sendHtml(
334
+ "recipient@example.com",
335
+ "带图片的邮件",
336
+ htmlWithImage,
337
+ imageMap
338
+ );
339
+
340
+ // ========== 发送给多人 ==========
341
+
342
+ // 5. 发送给多个收件人
343
+ List<String> recipients = Arrays.asList(
344
+ "user1@example.com",
345
+ "user2@example.com"
346
+ );
347
+
348
+ String messageId = MailUtils.sendHtml(
349
+ recipients,
350
+ "群发邮件",
351
+ "<p>这是群发的邮件内容</p>"
352
+ );
353
+
354
+ // 6. 发送邮件(带抄送、密送)
355
+ String messageId = MailUtils.send(
356
+ "recipient@example.com", // 收件人
357
+ "cc@example.com", // 抄送人
358
+ "bcc@example.com", // 密送人
359
+ "重要通知", // 标题
360
+ "<p>这是重要通知内容</p>", // 正文
361
+ true // 是否 HTML
362
+ );
363
+ ```
364
+
365
+ ### 2.4 邮件验证码示例
366
+
367
+ ```java
368
+ @Service
369
+ @RequiredArgsConstructor
370
+ public class EmailService {
371
+
372
+ /**
373
+ * 发送邮箱验证码
374
+ */
375
+ public void sendEmailCode(String email) {
376
+ // 1. 生成验证码
377
+ String code = RandomUtil.randomNumbers(6);
378
+
379
+ // 2. 存入 Redis
380
+ String cacheKey = "email:code:" + email;
381
+ RedisUtils.setCacheObject(cacheKey, code, Duration.ofMinutes(10));
382
+
383
+ // 3. 构建邮件内容
384
+ String htmlContent = String.format("""
385
+ <div style="padding: 20px; background: #f5f5f5;">
386
+ <h2>验证码</h2>
387
+ <p>您的验证码是:<strong style="color: #1890ff; font-size: 24px;">%s</strong></p>
388
+ <p>有效期10分钟,请勿泄露给他人。</p>
389
+ <p style="color: #999;">如非本人操作,请忽略此邮件。</p>
390
+ </div>
391
+ """, code);
392
+
393
+ // 4. 发送邮件
394
+ try {
395
+ MailUtils.sendHtml(email, "【若依系统】验证码", htmlContent);
396
+ log.info("验证码邮件发送成功:{}", email);
397
+ } catch (Exception e) {
398
+ log.error("验证码邮件发送失败:{}", e.getMessage());
399
+ throw new ServiceException("邮件发送失败");
400
+ }
401
+ }
402
+
403
+ /**
404
+ * 验证邮箱验证码
405
+ */
406
+ public boolean verifyEmailCode(String email, String code) {
407
+ String cacheKey = "email:code:" + email;
408
+ String cachedCode = RedisUtils.getCacheObject(cacheKey);
409
+
410
+ if (cachedCode != null && cachedCode.equals(code)) {
411
+ RedisUtils.deleteObject(cacheKey);
412
+ return true;
413
+ }
414
+ return false;
415
+ }
416
+ }
417
+ ```
418
+
419
+ ### 2.5 业务通知邮件示例
420
+
421
+ ```java
422
+ @Service
423
+ @RequiredArgsConstructor
424
+ public class NotificationService {
425
+
426
+ /**
427
+ * 发送订单确认邮件
428
+ */
429
+ public void sendOrderConfirmation(Order order, User user) {
430
+ String htmlContent = String.format("""
431
+ <div style="max-width: 600px; margin: 0 auto; font-family: Arial;">
432
+ <h2>订单确认</h2>
433
+ <p>尊敬的 %s,您好!</p>
434
+ <p>您的订单已确认,订单信息如下:</p>
435
+ <table style="width: 100%%; border-collapse: collapse;">
436
+ <tr><td>订单号:</td><td>%s</td></tr>
437
+ <tr><td>下单时间:</td><td>%s</td></tr>
438
+ <tr><td>订单金额:</td><td>¥%s</td></tr>
439
+ </table>
440
+ <p>感谢您的购买!</p>
441
+ </div>
442
+ """,
443
+ user.getNickName(),
444
+ order.getOrderNo(),
445
+ DateUtils.parseDateToStr("yyyy-MM-dd HH:mm:ss", order.getCreateTime()),
446
+ order.getTotalAmount()
447
+ );
448
+
449
+ MailUtils.sendHtml(user.getEmail(), "【若依商城】订单确认", htmlContent);
450
+ }
451
+
452
+ /**
453
+ * 发送密码重置邮件
454
+ */
455
+ public void sendPasswordResetEmail(String email, String resetToken) {
456
+ String resetUrl = "https://example.com/reset-password?token=" + resetToken;
457
+
458
+ String htmlContent = String.format("""
459
+ <div style="padding: 20px;">
460
+ <h2>密码重置</h2>
461
+ <p>您正在重置密码,请点击下方链接完成操作:</p>
462
+ <p><a href="%s" style="color: #1890ff;">点击重置密码</a></p>
463
+ <p>链接有效期30分钟。</p>
464
+ <p style="color: #999;">如非本人操作,请忽略此邮件。</p>
465
+ </div>
466
+ """, resetUrl);
467
+
468
+ MailUtils.sendHtml(email, "【若依系统】密码重置", htmlContent);
469
+ }
470
+
471
+ /**
472
+ * 发送报表邮件(带附件)
473
+ */
474
+ public void sendReportEmail(String email, String reportName, File reportFile) {
475
+ String htmlContent = String.format("""
476
+ <div style="padding: 20px;">
477
+ <h2>%s</h2>
478
+ <p>请查看附件中的报表文件。</p>
479
+ <p>报表生成时间:%s</p>
480
+ </div>
481
+ """, reportName, DateUtils.getTime());
482
+
483
+ MailUtils.sendHtml(email, reportName, htmlContent, reportFile);
484
+ }
485
+ }
486
+ ```
487
+
488
+ ---
489
+
490
+ ## 三、多渠道消息通知
491
+
492
+ ### 3.1 统一消息服务
493
+
494
+ ```java
495
+ @Service
496
+ @RequiredArgsConstructor
497
+ public class MessageService {
498
+
499
+ /**
500
+ * 消息类型枚举
501
+ */
502
+ public enum MessageType {
503
+ SMS, // 短信
504
+ EMAIL, // 邮件
505
+ WECHAT, // 微信(需额外实现)
506
+ SITE // 站内信(需额外实现)
507
+ }
508
+
509
+ /**
510
+ * 发送多渠道消息
511
+ */
512
+ public void sendMessage(List<MessageType> types, String userId,
513
+ String subject, String content) {
514
+ // 获取用户信息
515
+ SysUser user = userService.selectUserById(Long.valueOf(userId));
516
+
517
+ for (MessageType type : types) {
518
+ try {
519
+ switch (type) {
520
+ case SMS -> sendSms(user.getPhonenumber(), content);
521
+ case EMAIL -> sendEmail(user.getEmail(), subject, content);
522
+ // case WECHAT -> sendWechat(user.getOpenId(), content);
523
+ // case SITE -> sendSiteMessage(userId, subject, content);
524
+ }
525
+ } catch (Exception e) {
526
+ log.error("消息发送失败,类型:{},用户:{},错误:{}",
527
+ type, userId, e.getMessage());
528
+ }
529
+ }
530
+ }
531
+
532
+ private void sendSms(String phone, String content) {
533
+ if (StringUtils.isBlank(phone)) return;
534
+
535
+ Map<String, String> params = new LinkedHashMap<>();
536
+ params.put("content", content);
537
+
538
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
539
+ smsBlend.sendMessage(phone, "SMS_NOTIFY", params);
540
+ }
541
+
542
+ private void sendEmail(String email, String subject, String content) {
543
+ if (StringUtils.isBlank(email)) return;
544
+
545
+ MailUtils.sendHtml(email, subject,
546
+ "<div style='padding:20px;'>" + content + "</div>");
547
+ }
548
+ }
549
+ ```
550
+
551
+ ### 3.2 工作流消息通知示例
552
+
553
+ ```java
554
+ /**
555
+ * 工作流消息服务(参考框架实现)
556
+ */
557
+ @Service
558
+ @RequiredArgsConstructor
559
+ public class FlwCommonServiceImpl implements IFlwCommonService {
560
+
561
+ /**
562
+ * 发送审批通知
563
+ */
564
+ @Override
565
+ public void sendMessage(List<String> messageType, String message,
566
+ String subject, List<UserDTO> userList) {
567
+ if (CollUtil.isEmpty(messageType) || CollUtil.isEmpty(userList)) {
568
+ return;
569
+ }
570
+
571
+ for (UserDTO user : userList) {
572
+ // 短信通知
573
+ if (messageType.contains("sms") && StringUtils.isNotBlank(user.getPhone())) {
574
+ Map<String, String> params = new LinkedHashMap<>();
575
+ params.put("content", message);
576
+
577
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
578
+ smsBlend.sendMessage(user.getPhone(), "SMS_APPROVAL", params);
579
+ }
580
+
581
+ // 邮件通知
582
+ if (messageType.contains("email") && StringUtils.isNotBlank(user.getEmail())) {
583
+ String htmlContent = String.format("""
584
+ <div style="padding: 20px;">
585
+ <h3>%s</h3>
586
+ <p>%s</p>
587
+ <p>请登录系统处理。</p>
588
+ </div>
589
+ """, subject, message);
590
+
591
+ MailUtils.sendHtml(user.getEmail(), subject, htmlContent);
592
+ }
593
+ }
594
+ }
595
+ }
596
+ ```
597
+
598
+ ---
599
+
600
+ ## 四、常见错误与最佳实践
601
+
602
+ ### ❌ 错误1:未配置短信/邮件服务就使用
603
+
604
+ ```java
605
+ // ❌ 错误:未配置 sms.blends 就调用
606
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1"); // 返回 null
607
+ smsBlend.sendMessage(...); // NullPointerException
608
+ ```
609
+
610
+ ```yaml
611
+ # ✅ 正确:先配置
612
+ sms:
613
+ blends:
614
+ config1:
615
+ supplier: alibaba
616
+ access-key-id: xxx
617
+ access-key-secret: xxx
618
+ signature: 若依框架
619
+ ```
620
+
621
+ ### ❌ 错误2:邮箱使用登录密码而非授权码
622
+
623
+ ```yaml
624
+ # ❌ 错误:使用登录密码
625
+ mail:
626
+ pass: my-login-password # 错误!
627
+
628
+ # ✅ 正确:使用授权码(在邮箱设置中生成)
629
+ mail:
630
+ pass: ABCDEFGHIJKLMNOP # 授权码
631
+ ```
632
+
633
+ ### ❌ 错误3:短信模板参数与模板不匹配
634
+
635
+ ```java
636
+ // ❌ 错误:参数名与模板中定义的不一致
637
+ Map<String, String> params = new LinkedHashMap<>();
638
+ params.put("verifyCode", "123456"); // 模板中是 ${code}
639
+
640
+ // ✅ 正确:参数名要与模板一致
641
+ Map<String, String> params = new LinkedHashMap<>();
642
+ params.put("code", "123456"); // 匹配模板 ${code}
643
+ ```
644
+
645
+ ### ❌ 错误4:未处理发送失败的情况
646
+
647
+ ```java
648
+ // ❌ 错误:直接发送,不处理结果
649
+ SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
650
+ smsBlend.sendMessage(phone, templateId, params);
651
+ // 如果失败,用户无感知
652
+
653
+ // ✅ 正确:检查发送结果
654
+ SmsResponse response = smsBlend.sendMessage(phone, templateId, params);
655
+ if (!response.isSuccess()) {
656
+ log.error("短信发送失败:{}", response.getMessage());
657
+ throw new ServiceException("短信发送失败,请稍后重试");
658
+ }
659
+ ```
660
+
661
+ ### ❌ 错误5:验证码明文存储或无过期时间
662
+
663
+ ```java
664
+ // ❌ 错误:无过期时间
665
+ RedisUtils.setCacheObject("sms:code:" + phone, code); // 永不过期
666
+
667
+ // ✅ 正确:设置合理的过期时间
668
+ RedisUtils.setCacheObject("sms:code:" + phone, code, Duration.ofMinutes(5));
669
+ ```
670
+
671
+ ---
672
+
673
+ ## 五、API 速查表
674
+
675
+ ### 短信 API(SMS4j)
676
+
677
+ | 方法 | 说明 |
678
+ |------|------|
679
+ | `SmsFactory.getSmsBlend()` | 获取默认短信实例 |
680
+ | `SmsFactory.getSmsBlend("config1")` | 获取指定配置的短信实例 |
681
+ | `smsBlend.sendMessage(phone, templateId, params)` | 发送模板短信 |
682
+ | `smsBlend.sendMessage(phones, templateId, params)` | 批量发送短信 |
683
+ | `response.isSuccess()` | 检查是否发送成功 |
684
+ | `response.getMessage()` | 获取错误信息 |
685
+ | `response.getBizId()` | 获取消息ID |
686
+
687
+ ### 邮件 API(MailUtils)
688
+
689
+ | 方法 | 说明 |
690
+ |------|------|
691
+ | `MailUtils.sendText(to, subject, content)` | 发送文本邮件 |
692
+ | `MailUtils.sendHtml(to, subject, content)` | 发送 HTML 邮件 |
693
+ | `MailUtils.sendText(to, subject, content, files...)` | 发送带附件的文本邮件 |
694
+ | `MailUtils.sendHtml(to, subject, content, files...)` | 发送带附件的 HTML 邮件 |
695
+ | `MailUtils.sendHtml(to, subject, content, imageMap)` | 发送带内嵌图片的邮件 |
696
+ | `MailUtils.send(to, cc, bcc, subject, content, isHtml)` | 发送带抄送/密送的邮件 |
697
+ | `MailUtils.sendHtml(tos, subject, content)` | 群发 HTML 邮件 |
698
+ | `MailUtils.getMailAccount()` | 获取邮件账户配置 |
699
+
700
+ ---
701
+
702
+ ## 六、配置参考
703
+
704
+ ### 短信完整配置
705
+
706
+ ```yaml
707
+ sms:
708
+ # 配置源类型:yaml、接口、数据库
709
+ config-type: yaml
710
+ # 短信拦截配置(可选)
711
+ restricted:
712
+ # 是否开启账号维度的每日发送上限
713
+ account-max: 0
714
+ # 是否开启手机号维度的每分钟发送上限
715
+ minute-max: 1
716
+ # 单账号每日发送上限
717
+ account-max-count: 10
718
+ # 单手机号每分钟发送上限
719
+ minute-max-count: 1
720
+
721
+ blends:
722
+ config1:
723
+ supplier: alibaba
724
+ access-key-id: ${ALIYUN_SMS_ACCESS_KEY_ID}
725
+ access-key-secret: ${ALIYUN_SMS_ACCESS_KEY_SECRET}
726
+ signature: 若依框架
727
+
728
+ config2:
729
+ supplier: tencent
730
+ access-key-id: ${TENCENT_SMS_SECRET_ID}
731
+ access-key-secret: ${TENCENT_SMS_SECRET_KEY}
732
+ signature: 若依框架
733
+ sdk-app-id: "1400000000"
734
+ ```
735
+
736
+ ### 邮件完整配置
737
+
738
+ ```yaml
739
+ mail:
740
+ enabled: true
741
+ host: smtp.163.com
742
+ port: 465
743
+ auth: true
744
+ from: system@example.com
745
+ user: system@example.com
746
+ pass: ${MAIL_PASSWORD}
747
+ sslEnable: true
748
+ starttlsEnable: false
749
+ timeout: 10000
750
+ connectionTimeout: 10000
751
+ ```
752
+
753
+ ---
754
+
755
+ ## 七、参考代码位置
756
+
757
+ | 类型 | 位置 |
758
+ |------|------|
759
+ | 短信配置 | `ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/config/SmsAutoConfiguration.java` |
760
+ | 短信缓存 | `ruoyi-common/ruoyi-common-sms/src/main/java/org/dromara/common/sms/core/dao/PlusSmsDao.java` |
761
+ | 邮件工具类 | `ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java` |
762
+ | 邮件配置 | `ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java` |
763
+ | 邮件属性 | `ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java` |
764
+ | 验证码示例 | `ruoyi-admin/src/main/java/org/dromara/web/controller/CaptchaController.java` |
765
+ | 短信演示 | `ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/SmsController.java` |
766
+ | 工作流消息 | `ruoyi-modules/ruoyi-workflow/src/main/java/org/dromara/workflow/service/impl/FlwCommonServiceImpl.java` |