ai-engineering-init 1.6.0 → 1.8.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 (187) hide show
  1. package/.claude/agents/code-reviewer.md +3 -130
  2. package/.claude/hooks/skill-forced-eval.js +46 -60
  3. package/.claude/hooks/stop.js +24 -1
  4. package/.claude/settings.json +10 -1
  5. package/.claude/skills/api-development/SKILL.md +179 -130
  6. package/.claude/skills/architecture-design/SKILL.md +102 -212
  7. package/.claude/skills/backend-annotations/SKILL.md +166 -220
  8. package/.claude/skills/bug-detective/SKILL.md +225 -186
  9. package/.claude/skills/code-patterns/SKILL.md +127 -244
  10. package/.claude/skills/codex-code-review/SKILL.md +327 -0
  11. package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
  12. package/.claude/skills/crud-development/SKILL.md +226 -307
  13. package/.claude/skills/data-permission/SKILL.md +131 -202
  14. package/.claude/skills/database-ops/SKILL.md +158 -355
  15. package/.claude/skills/error-handler/SKILL.md +224 -285
  16. package/.claude/skills/file-oss-management/SKILL.md +174 -169
  17. package/.claude/skills/git-workflow/SKILL.md +123 -341
  18. package/.claude/skills/json-serialization/SKILL.md +121 -137
  19. package/.claude/skills/leniu-report-customization/SKILL.md +82 -2
  20. package/.claude/skills/leniu-report-standard-customization/SKILL.md +65 -2
  21. package/.claude/skills/loki-log-query/SKILL.md +400 -0
  22. package/.claude/skills/mysql-debug/SKILL.md +58 -22
  23. package/.claude/skills/performance-doctor/SKILL.md +83 -89
  24. package/.claude/skills/redis-cache/SKILL.md +134 -185
  25. package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
  26. package/.claude/skills/security-guard/SKILL.md +168 -276
  27. package/.claude/skills/sms-mail/SKILL.md +266 -228
  28. package/.claude/skills/social-login/SKILL.md +257 -195
  29. package/.claude/skills/sync-back-merge/SKILL.md +66 -0
  30. package/.claude/skills/tenant-management/SKILL.md +172 -188
  31. package/.claude/skills/utils-toolkit/SKILL.md +214 -222
  32. package/.claude/skills/websocket-sse/SKILL.md +251 -172
  33. package/.claude/skills/workflow-engine/SKILL.md +178 -250
  34. package/.claude/skills/yunxiao-task-management/SKILL.md +489 -0
  35. package/.codex/skills/api-development/SKILL.md +179 -130
  36. package/.codex/skills/architecture-design/SKILL.md +102 -212
  37. package/.codex/skills/backend-annotations/SKILL.md +166 -220
  38. package/.codex/skills/bug-detective/SKILL.md +225 -186
  39. package/.codex/skills/code-patterns/SKILL.md +127 -244
  40. package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
  41. package/.codex/skills/crud-development/SKILL.md +226 -307
  42. package/.codex/skills/data-permission/SKILL.md +131 -202
  43. package/.codex/skills/database-ops/SKILL.md +158 -355
  44. package/.codex/skills/error-handler/SKILL.md +224 -285
  45. package/.codex/skills/file-oss-management/SKILL.md +174 -169
  46. package/.codex/skills/git-workflow/SKILL.md +123 -341
  47. package/.codex/skills/json-serialization/SKILL.md +121 -137
  48. package/.codex/skills/leniu-report-customization/SKILL.md +82 -2
  49. package/.codex/skills/leniu-report-standard-customization/SKILL.md +65 -2
  50. package/.codex/skills/loki-log-query/SKILL.md +400 -0
  51. package/.codex/skills/loki-log-query/environments.json +45 -0
  52. package/.codex/skills/mysql-debug/SKILL.md +58 -22
  53. package/.codex/skills/performance-doctor/SKILL.md +83 -89
  54. package/.codex/skills/redis-cache/SKILL.md +134 -185
  55. package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
  56. package/.codex/skills/security-guard/SKILL.md +168 -276
  57. package/.codex/skills/skill-creator/LICENSE.txt +202 -0
  58. package/.codex/skills/skill-creator/SKILL.md +479 -0
  59. package/.codex/skills/skill-creator/agents/analyzer.md +274 -0
  60. package/.codex/skills/skill-creator/agents/comparator.md +202 -0
  61. package/.codex/skills/skill-creator/agents/grader.md +223 -0
  62. package/.codex/skills/skill-creator/assets/eval_review.html +146 -0
  63. package/.codex/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  64. package/.codex/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  65. package/.codex/skills/skill-creator/references/schemas.md +430 -0
  66. package/.codex/skills/skill-creator/scripts/__init__.py +0 -0
  67. package/.codex/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  68. package/.codex/skills/skill-creator/scripts/generate_report.py +326 -0
  69. package/.codex/skills/skill-creator/scripts/improve_description.py +248 -0
  70. package/.codex/skills/skill-creator/scripts/package_skill.py +136 -0
  71. package/.codex/skills/skill-creator/scripts/quick_validate.py +103 -0
  72. package/.codex/skills/skill-creator/scripts/run_eval.py +310 -0
  73. package/.codex/skills/skill-creator/scripts/run_loop.py +332 -0
  74. package/.codex/skills/skill-creator/scripts/utils.py +47 -0
  75. package/.codex/skills/sms-mail/SKILL.md +266 -228
  76. package/.codex/skills/social-login/SKILL.md +257 -195
  77. package/.codex/skills/sync-back-merge/SKILL.md +66 -0
  78. package/.codex/skills/tenant-management/SKILL.md +172 -188
  79. package/.codex/skills/utils-toolkit/SKILL.md +214 -222
  80. package/.codex/skills/websocket-sse/SKILL.md +251 -172
  81. package/.codex/skills/workflow-engine/SKILL.md +178 -250
  82. package/.codex/skills/yunxiao-task-management/SKILL.md +489 -0
  83. package/.cursor/hooks/cursor-skill-eval.js +66 -6
  84. package/.cursor/hooks/stop.js +23 -1
  85. package/.cursor/skills/api-development/SKILL.md +179 -130
  86. package/.cursor/skills/architecture-design/SKILL.md +102 -212
  87. package/.cursor/skills/backend-annotations/SKILL.md +166 -220
  88. package/.cursor/skills/bug-detective/SKILL.md +225 -186
  89. package/.cursor/skills/code-patterns/SKILL.md +127 -244
  90. package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
  91. package/.cursor/skills/crud-development/SKILL.md +226 -307
  92. package/.cursor/skills/data-permission/SKILL.md +131 -202
  93. package/.cursor/skills/database-ops/SKILL.md +158 -355
  94. package/.cursor/skills/error-handler/SKILL.md +224 -285
  95. package/.cursor/skills/file-oss-management/SKILL.md +174 -169
  96. package/.cursor/skills/git-workflow/SKILL.md +123 -341
  97. package/.cursor/skills/json-serialization/SKILL.md +121 -137
  98. package/.cursor/skills/leniu-report-customization/SKILL.md +82 -2
  99. package/.cursor/skills/leniu-report-standard-customization/SKILL.md +65 -2
  100. package/.cursor/skills/loki-log-query/SKILL.md +400 -0
  101. package/.cursor/skills/loki-log-query/environments.json +45 -0
  102. package/.cursor/skills/mysql-debug/SKILL.md +58 -22
  103. package/.cursor/skills/performance-doctor/SKILL.md +83 -89
  104. package/.cursor/skills/redis-cache/SKILL.md +134 -185
  105. package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
  106. package/.cursor/skills/security-guard/SKILL.md +168 -276
  107. package/.cursor/skills/skill-creator/LICENSE.txt +202 -0
  108. package/.cursor/skills/skill-creator/SKILL.md +479 -0
  109. package/.cursor/skills/skill-creator/agents/analyzer.md +274 -0
  110. package/.cursor/skills/skill-creator/agents/comparator.md +202 -0
  111. package/.cursor/skills/skill-creator/agents/grader.md +223 -0
  112. package/.cursor/skills/skill-creator/assets/eval_review.html +146 -0
  113. package/.cursor/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  114. package/.cursor/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  115. package/.cursor/skills/skill-creator/references/schemas.md +430 -0
  116. package/.cursor/skills/skill-creator/scripts/__init__.py +0 -0
  117. package/.cursor/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  118. package/.cursor/skills/skill-creator/scripts/generate_report.py +326 -0
  119. package/.cursor/skills/skill-creator/scripts/improve_description.py +248 -0
  120. package/.cursor/skills/skill-creator/scripts/package_skill.py +136 -0
  121. package/.cursor/skills/skill-creator/scripts/quick_validate.py +103 -0
  122. package/.cursor/skills/skill-creator/scripts/run_eval.py +310 -0
  123. package/.cursor/skills/skill-creator/scripts/run_loop.py +332 -0
  124. package/.cursor/skills/skill-creator/scripts/utils.py +47 -0
  125. package/.cursor/skills/sms-mail/SKILL.md +266 -228
  126. package/.cursor/skills/social-login/SKILL.md +257 -195
  127. package/.cursor/skills/sync-back-merge/SKILL.md +66 -0
  128. package/.cursor/skills/tenant-management/SKILL.md +172 -188
  129. package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
  130. package/.cursor/skills/websocket-sse/SKILL.md +251 -172
  131. package/.cursor/skills/workflow-engine/SKILL.md +178 -250
  132. package/.cursor/skills/yunxiao-task-management/SKILL.md +489 -0
  133. package/AGENTS.md +49 -540
  134. package/CLAUDE.md +73 -119
  135. package/README.md +37 -6
  136. package/bin/index.js +611 -25
  137. package/package.json +1 -1
  138. package/src/platform-map.json +4 -0
  139. package/src/skills/api-development/SKILL.md +179 -130
  140. package/src/skills/architecture-design/SKILL.md +102 -212
  141. package/src/skills/backend-annotations/SKILL.md +166 -220
  142. package/src/skills/bug-detective/SKILL.md +225 -186
  143. package/src/skills/code-patterns/SKILL.md +127 -244
  144. package/src/skills/codex-code-review/SKILL.md +261 -69
  145. package/src/skills/collaborating-with-codex/SKILL.md +96 -113
  146. package/src/skills/crud-development/SKILL.md +226 -307
  147. package/src/skills/data-permission/SKILL.md +131 -202
  148. package/src/skills/database-ops/SKILL.md +158 -355
  149. package/src/skills/error-handler/SKILL.md +224 -285
  150. package/src/skills/file-oss-management/SKILL.md +174 -169
  151. package/src/skills/git-workflow/SKILL.md +123 -341
  152. package/src/skills/json-serialization/SKILL.md +121 -137
  153. package/src/skills/leniu-report-customization/SKILL.md +82 -2
  154. package/src/skills/leniu-report-standard-customization/SKILL.md +65 -2
  155. package/src/skills/loki-log-query/SKILL.md +400 -0
  156. package/src/skills/loki-log-query/environments.json +45 -0
  157. package/src/skills/mysql-debug/SKILL.md +58 -22
  158. package/src/skills/performance-doctor/SKILL.md +83 -89
  159. package/src/skills/redis-cache/SKILL.md +134 -185
  160. package/src/skills/scheduled-jobs/SKILL.md +187 -224
  161. package/src/skills/security-guard/SKILL.md +168 -276
  162. package/src/skills/skill-creator/LICENSE.txt +202 -0
  163. package/src/skills/skill-creator/SKILL.md +479 -0
  164. package/src/skills/skill-creator/agents/analyzer.md +274 -0
  165. package/src/skills/skill-creator/agents/comparator.md +202 -0
  166. package/src/skills/skill-creator/agents/grader.md +223 -0
  167. package/src/skills/skill-creator/assets/eval_review.html +146 -0
  168. package/src/skills/skill-creator/eval-viewer/generate_review.py +471 -0
  169. package/src/skills/skill-creator/eval-viewer/viewer.html +1325 -0
  170. package/src/skills/skill-creator/references/schemas.md +430 -0
  171. package/src/skills/skill-creator/scripts/__init__.py +0 -0
  172. package/src/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  173. package/src/skills/skill-creator/scripts/generate_report.py +326 -0
  174. package/src/skills/skill-creator/scripts/improve_description.py +248 -0
  175. package/src/skills/skill-creator/scripts/package_skill.py +136 -0
  176. package/src/skills/skill-creator/scripts/quick_validate.py +103 -0
  177. package/src/skills/skill-creator/scripts/run_eval.py +310 -0
  178. package/src/skills/skill-creator/scripts/run_loop.py +332 -0
  179. package/src/skills/skill-creator/scripts/utils.py +47 -0
  180. package/src/skills/sms-mail/SKILL.md +266 -228
  181. package/src/skills/social-login/SKILL.md +257 -195
  182. package/src/skills/sync-back-merge/SKILL.md +66 -0
  183. package/src/skills/tenant-management/SKILL.md +172 -188
  184. package/src/skills/utils-toolkit/SKILL.md +214 -222
  185. package/src/skills/websocket-sse/SKILL.md +251 -172
  186. package/src/skills/workflow-engine/SKILL.md +178 -250
  187. package/src/skills/yunxiao-task-management/SKILL.md +489 -0
@@ -10,246 +10,251 @@ description: |
10
10
  - 文件元数据管理
11
11
  - OSS服务商切换
12
12
 
13
- 触发词:文件上传、OSS、云存储、MinIO、阿里云、腾讯云、七牛、图片上传、文件下载、预签名、presigned、OssClient、OssFactory
13
+ 触发词:文件上传、OSS、云存储、MinIO、阿里云、腾讯云、七牛、图片上传、文件下载、预签名、presigned、S3
14
14
  ---
15
15
 
16
16
  # 文件与云存储指南
17
17
 
18
- > 模块位置:`ruoyi-common/ruoyi-common-oss`
19
18
  > 统一协议:基于 AWS S3 SDK v2,兼容所有 S3 协议云服务
20
19
 
21
- ## 核心类
20
+ ## 架构概述
22
21
 
23
- | | 说明 |
22
+ | 组件 | 说明 |
24
23
  |----|------|
25
- | `OssFactory` | 获取 OssClient 实例(只有2个方法) |
26
- | `OssClient` | 统一操作入口(基于 AWS S3 SDK v2) |
24
+ | `[你的OssClient]` | 统一操作入口(基于 AWS S3 SDK v2) |
25
+ | `S3Client` | AWS SDK 底层客户端 |
27
26
  | `UploadResult` | 上传结果(url, filename, eTag) |
28
- | `ISysOssService` | OSS 文件管理服务接口 |
29
27
 
30
28
  ---
31
29
 
32
- ## 一、获取 OssClient
30
+ ## 一、S3 Client 初始化
33
31
 
34
32
  ```java
35
- import org.dromara.common.oss.factory.OssFactory;
36
- import org.dromara.common.oss.core.OssClient;
37
-
38
- OssClient client = OssFactory.instance(); // 默认配置
39
- OssClient client = OssFactory.instance("aliyun"); // 指定配置(字符串,非枚举)
40
- OssClient client = OssFactory.instance("minio");
41
-
42
- // 不存在 OssType 枚举参数
43
- OssClient client = OssFactory.instance(OssType.ALIYUN); // 编译错误!
33
+ import software.amazon.awssdk.services.s3.S3Client;
34
+ import software.amazon.awssdk.services.s3.presigner.S3Presigner;
35
+ import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
36
+ import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
37
+ import software.amazon.awssdk.regions.Region;
38
+
39
+ // 通用 S3 客户端构建(兼容 MinIO / 阿里云 / 腾讯云等)
40
+ S3Client s3Client = S3Client.builder()
41
+ .endpointOverride(URI.create(endpoint))
42
+ .credentialsProvider(StaticCredentialsProvider.create(
43
+ AwsBasicCredentials.create(accessKey, secretKey)))
44
+ .region(Region.of(region))
45
+ .forcePathStyle(true) // MinIO 需要开启
46
+ .build();
44
47
  ```
45
48
 
46
- > 内部使用 ConcurrentHashMap + ReentrantLock 双检锁缓存实例,支持多租户隔离。
47
-
48
49
  ---
49
50
 
50
51
  ## 二、文件上传
51
52
 
52
- ```java
53
- import org.dromara.common.oss.entity.UploadResult;
53
+ ### 基础上传
54
54
 
55
- // 1. 上传字节数组,自动生成路径(推荐)
56
- UploadResult result = client.uploadSuffix(data, ".jpg", "image/jpeg");
55
+ ```java
56
+ import software.amazon.awssdk.services.s3.model.PutObjectRequest;
57
+ import software.amazon.awssdk.core.sync.RequestBody;
57
58
 
58
- // 2. 上传输入流,自动生成路径
59
- UploadResult result = client.uploadSuffix(is, ".jpg", fileSize, "image/jpeg");
59
+ // 上传文件
60
+ PutObjectRequest request = PutObjectRequest.builder()
61
+ .bucket(bucketName)
62
+ .key("images/photo.jpg")
63
+ .contentType("image/jpeg")
64
+ .build();
60
65
 
61
- // 3. 上传 File 对象,自动生成路径
62
- UploadResult result = client.uploadSuffix(file, ".jpg");
66
+ s3Client.putObject(request, RequestBody.fromFile(file.toPath()));
63
67
 
64
- // 4. 上传到指定路径
65
- UploadResult result = client.upload(file.toPath(), "avatar/user123.jpg", null, "image/jpeg");
68
+ // 上传输入流
69
+ s3Client.putObject(request, RequestBody.fromInputStream(inputStream, contentLength));
66
70
 
67
- // 5. 上传流到指定路径
68
- UploadResult result = client.upload(is, "images/photo.jpg", fileSize, "image/jpeg");
71
+ // 上传字节数组
72
+ s3Client.putObject(request, RequestBody.fromBytes(data));
69
73
  ```
70
74
 
71
- **方法签名:**
75
+ ### 封装上传服务(推荐模式)
76
+
72
77
  ```java
73
- UploadResult upload(Path filePath, String key, String md5Digest, String contentType)
74
- UploadResult upload(InputStream inputStream, String key, Long length, String contentType)
75
- UploadResult uploadSuffix(byte[] data, String suffix, String contentType)
76
- UploadResult uploadSuffix(InputStream inputStream, String suffix, Long length, String contentType)
77
- UploadResult uploadSuffix(File file, String suffix)
78
+ @Service
79
+ @RequiredArgsConstructor
80
+ public class OssService {
81
+
82
+ private final S3Client s3Client;
83
+ private final OssProperties properties;
84
+
85
+ /**
86
+ * 上传文件,自动生成路径
87
+ */
88
+ public UploadResult upload(MultipartFile file) {
89
+ String suffix = getFileSuffix(file.getOriginalFilename());
90
+ String key = generateObjectKey(suffix); // 如 2026/03/07/uuid.jpg
91
+
92
+ PutObjectRequest request = PutObjectRequest.builder()
93
+ .bucket(properties.getBucketName())
94
+ .key(key)
95
+ .contentType(file.getContentType())
96
+ .build();
97
+
98
+ s3Client.putObject(request,
99
+ RequestBody.fromInputStream(file.getInputStream(), file.getSize()));
100
+
101
+ return UploadResult.builder()
102
+ .url(properties.getDomain() + "/" + key)
103
+ .filename(key)
104
+ .build();
105
+ }
106
+
107
+ private String generateObjectKey(String suffix) {
108
+ String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
109
+ return datePath + "/" + UUID.randomUUID() + suffix;
110
+ }
111
+ }
78
112
  ```
79
113
 
80
114
  ---
81
115
 
82
- ## 三、UploadResult 字段
83
-
84
- > 只有 3 个字段,使用 Lombok `@Builder`。
85
-
86
- | 字段 | 类型 | 说明 |
87
- |------|------|------|
88
- | `url` | String | 文件访问URL |
89
- | `filename` | String | 文件名/对象键(**小写 n**) |
90
- | `eTag` | String | 文件校验标记 |
116
+ ## 三、文件下载
91
117
 
92
118
  ```java
93
- String url = result.getUrl();
94
- String filename = result.getFilename(); // ✅ 小写 'n'
95
- // ❌ result.getFileName() / result.getFileSize() / result.getContentType() 不存在
119
+ import software.amazon.awssdk.services.s3.model.GetObjectRequest;
120
+ import software.amazon.awssdk.core.ResponseInputStream;
121
+
122
+ // 下载到输出流(推荐用于HTTP响应)
123
+ GetObjectRequest getRequest = GetObjectRequest.builder()
124
+ .bucket(bucketName)
125
+ .key("images/photo.jpg")
126
+ .build();
127
+
128
+ ResponseInputStream<?> response = s3Client.getObject(getRequest);
129
+
130
+ // 写入 HTTP 响应
131
+ try (InputStream is = response) {
132
+ httpResponse.setContentType("image/jpeg");
133
+ httpResponse.setContentLengthLong(response.response().contentLength());
134
+ is.transferTo(httpResponse.getOutputStream());
135
+ }
96
136
  ```
97
137
 
98
138
  ---
99
139
 
100
- ## 四、文件下载
140
+ ## 四、文件删除
101
141
 
102
142
  ```java
103
- // 下载到临时文件
104
- Path tempFile = client.fileDownload("images/photo.jpg");
143
+ import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
105
144
 
106
- // 下载到输出流(推荐用于HTTP响应)
107
- client.download("images/photo.jpg", out, contentLength -> {
108
- response.setContentLengthLong(contentLength);
109
- });
145
+ DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
146
+ .bucket(bucketName)
147
+ .key("images/photo.jpg")
148
+ .build();
110
149
 
111
- // 获取文件输入流(内部创建临时文件,使用后自动删除)
112
- InputStream is = client.getObjectContent("images/photo.jpg");
150
+ s3Client.deleteObject(deleteRequest);
113
151
  ```
114
152
 
115
153
  ---
116
154
 
117
- ## 五、文件删除与预签名URL
155
+ ## 五、预签名 URL
118
156
 
119
157
  ```java
120
- // 删除
121
- client.delete("images/photo.jpg");
122
- // ❌ client.copyFile() / client.getFileMetadata() / client.listFiles() 不存在
158
+ import software.amazon.awssdk.services.s3.presigner.S3Presigner;
159
+ import software.amazon.awssdk.services.s3.presigner.model.*;
160
+
161
+ S3Presigner presigner = S3Presigner.builder()
162
+ .endpointOverride(URI.create(endpoint))
163
+ .credentialsProvider(credentialsProvider)
164
+ .region(Region.of(region))
165
+ .build();
123
166
 
124
167
  // 下载预签名URL
125
- String url = client.createPresignedGetUrl("images/photo.jpg", Duration.ofMinutes(60));
168
+ GetObjectPresignRequest getPresignRequest = GetObjectPresignRequest.builder()
169
+ .signatureDuration(Duration.ofMinutes(60))
170
+ .getObjectRequest(b -> b.bucket(bucketName).key("images/photo.jpg"))
171
+ .build();
172
+ String downloadUrl = presigner.presignGetObject(getPresignRequest).url().toString();
126
173
 
127
174
  // 上传预签名URL(前端直传)
128
- String url = client.createPresignedPutUrl("images/upload.jpg", Duration.ofHours(1), metadata);
129
- // ❌ client.generatePresignedUrl() / client.generatePublicUrl() 不存在
175
+ PutObjectPresignRequest putPresignRequest = PutObjectPresignRequest.builder()
176
+ .signatureDuration(Duration.ofHours(1))
177
+ .putObjectRequest(b -> b.bucket(bucketName).key("images/upload.jpg"))
178
+ .build();
179
+ String uploadUrl = presigner.presignPutObject(putPresignRequest).url().toString();
130
180
  ```
131
181
 
132
182
  ---
133
183
 
134
- ## 六、OssClient 工具方法
184
+ ## 六、Controller 接口(设计模式)
135
185
 
136
186
  ```java
137
- String baseUrl = client.getUrl(); // 基础URL
138
- String endpoint = client.getEndpoint(); // 终端点URL
139
- String domain = client.getDomain(); // 自定义域名
140
- String configKey = client.getConfigKey(); // 配置键
141
- AccessPolicyType policy = client.getAccessPolicy(); // 桶权限(PUBLIC/PRIVATE)
142
- String path = client.getPath("", ".jpg"); // 生成对象键路径
143
- String relative = client.removeBaseUrl(fullUrl); // 获取相对路径
144
- boolean same = client.checkPropertiesSame(props); // 配置是否相同
145
- ```
146
-
147
- ---
148
-
149
- ## 七、Controller 接口(SysOssController)
150
-
151
- | 操作 | HTTP | 路径 | 权限 |
152
- |------|------|------|------|
153
- | 查询列表 | GET | `/resource/oss/list` | `system:oss:list` |
154
- | 批量查询 | GET | `/resource/oss/listByIds/{ossIds}` | `system:oss:query` |
155
- | 上传文件 | POST | `/resource/oss/upload` | `system:oss:upload` |
156
- | 下载文件 | GET | `/resource/oss/download/{ossId}` | `system:oss:download` |
157
- | 删除文件 | DELETE | `/resource/oss/{ossIds}` | `system:oss:remove` |
158
-
159
- **上传接口规范:**
160
- ```java
161
- // 必须使用 @RequestPart("file"),必须指定 consumes
162
- @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
163
- public R<SysOssUploadVo> upload(@RequestPart("file") MultipartFile file) {
164
- SysOssVo oss = ossService.upload(file);
165
- SysOssUploadVo uploadVo = new SysOssUploadVo();
166
- uploadVo.setUrl(oss.getUrl());
167
- uploadVo.setFileName(oss.getOriginalName());
168
- uploadVo.setOssId(oss.getOssId().toString());
169
- return R.ok(uploadVo);
187
+ @RestController
188
+ @RequiredArgsConstructor
189
+ @RequestMapping("/api/oss")
190
+ public class OssController {
191
+
192
+ private final OssService ossService;
193
+
194
+ @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
195
+ public UploadResult upload(@RequestPart("file") MultipartFile file) {
196
+ return ossService.upload(file);
197
+ }
198
+
199
+ @GetMapping("/download/{id}")
200
+ public void download(@PathVariable Long id, HttpServletResponse response) throws IOException {
201
+ ossService.download(id, response);
202
+ }
203
+
204
+ @DeleteMapping("/{ids}")
205
+ public void delete(@PathVariable List<Long> ids) {
206
+ ossService.deleteByIds(ids);
207
+ }
170
208
  }
171
209
  ```
172
210
 
173
- **SysOssUploadVo**:`url`(String) / `fileName`(String) / `ossId`(String)
174
-
175
211
  ---
176
212
 
177
- ## 八、Service 层接口(ISysOssService)
213
+ ## 七、配置模型
214
+
215
+ ```yaml
216
+ # application.yml
217
+ oss:
218
+ endpoint: https://s3.amazonaws.com # 或 MinIO/阿里云/腾讯云端点
219
+ access-key: your-access-key
220
+ secret-key: your-secret-key
221
+ bucket-name: your-bucket
222
+ region: us-east-1
223
+ domain: https://cdn.example.com # 自定义域名(可选)
224
+ ```
178
225
 
179
226
  ```java
180
- TableDataInfo<SysOssVo> queryPageList(SysOssBo sysOss, PageQuery pageQuery);
181
- List<SysOssVo> listByIds(Collection<Long> ossIds);
182
- @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
183
- SysOssVo getById(Long ossId);
184
- SysOssVo upload(MultipartFile file);
185
- SysOssVo upload(File file);
186
- void download(Long ossId, HttpServletResponse response) throws IOException;
187
- Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
227
+ @Data
228
+ @ConfigurationProperties(prefix = "oss")
229
+ public class OssProperties {
230
+ private String endpoint;
231
+ private String accessKey;
232
+ private String secretKey;
233
+ private String bucketName;
234
+ private String region;
235
+ private String domain;
236
+ }
188
237
  ```
189
238
 
190
- > 推荐通过 `ISysOssService.upload()` 上传,会自动保存数据库记录。
191
- > 直接使用 `OssClient` 上传不会有数据库记录。
192
-
193
- > 完整 Service 实现代码详见 [references/service-impl.md](references/service-impl.md)
194
-
195
- ---
196
-
197
- ## 九、数据库实体
198
-
199
- > 完整实体/VO/BO 定义详见 [references/entities.md](references/entities.md)
200
-
201
- **SysOss 关键字段:**
202
-
203
- | 字段 | 说明 |
204
- |------|------|
205
- | `ossId` | 主键 |
206
- | `fileName` | OSS对象键 |
207
- | `originalName` | 原始文件名 |
208
- | `fileSuffix` | 后缀名 |
209
- | `url` | 访问URL |
210
- | `ext1` | 扩展字段(JSON,存储 SysOssExt) |
211
- | `service` | 服务商标识 |
212
-
213
- ---
214
-
215
- ## 十、配置(sys_oss_config 表)
216
-
217
- | 字段 | 说明 |
218
- |------|------|
219
- | `config_key` | 配置标识(aliyun、minio等) |
220
- | `access_key` / `secret_key` | 认证信息 |
221
- | `bucket_name` | 存储桶 |
222
- | `prefix` | 路径前缀 |
223
- | `endpoint` | 服务端点 |
224
- | `domain` | 自定义域名 |
225
- | `is_https` | 是否HTTPS(Y/N) |
226
- | `region` | 区域 |
227
- | `access_policy` | 0-private, 1-public, 2-custom |
228
-
229
- > 配置从 Redis 读取(`CacheNames.SYS_OSS_CONFIG`),私有桶文件自动生成 120 秒预签名URL。
230
-
231
239
  ---
232
240
 
233
- ## 十一、快速对照表
241
+ ## 八、服务商对照
234
242
 
235
- | 错误 | 正确 |
236
- |------|------|
237
- | `OssFactory.instance(OssType.ALIYUN)` | `OssFactory.instance("aliyun")` |
238
- | `result.getFileName()` | `result.getFilename()` |
239
- | `result.getFileSize()` | 不存在 |
240
- | `client.downloadToTempFile(path)` | `client.fileDownload(path)` |
241
- | `client.generatePresignedUrl(...)` | `client.createPresignedGetUrl(...)` |
242
- | `throw ServiceException.of("msg")` | `throw new ServiceException("msg")` |
243
- | `client.copyFile/listFiles/getFileMetadata` | 不存在 |
243
+ | 服务商 | endpoint 示例 | 备注 |
244
+ |--------|-------------|------|
245
+ | 阿里云 OSS | `https://oss-cn-hangzhou.aliyuncs.com` | S3 兼容 |
246
+ | 腾讯云 COS | `https://cos.ap-guangzhou.myqcloud.com` | S3 兼容 |
247
+ | 七牛云 | `https://s3-cn-south-1.qiniucs.com` | S3 兼容 |
248
+ | MinIO | `http://localhost:9000` | `forcePathStyle(true)` |
249
+ | AWS S3 | `https://s3.amazonaws.com` | 原生支持 |
244
250
 
245
251
  ---
246
252
 
247
- ## 核心文件位置
253
+ ## 九、设计要点
248
254
 
249
- | 类型 | 位置 |
250
- |------|------|
251
- | OssFactory | `ruoyi-common/ruoyi-common-oss/.../factory/OssFactory.java` |
252
- | OssClient | `ruoyi-common/ruoyi-common-oss/.../core/OssClient.java` |
253
- | UploadResult | `ruoyi-common/ruoyi-common-oss/.../entity/UploadResult.java` |
254
- | SysOssController | `ruoyi-modules/ruoyi-system/.../controller/system/SysOssController.java` |
255
- | SysOssServiceImpl | `ruoyi-modules/ruoyi-system/.../service/impl/SysOssServiceImpl.java` |
255
+ 1. **统一封装**:通过 S3 协议统一对接多个云服务商,切换只需改配置
256
+ 2. **路径生成**:按日期+UUID生成对象路径,避免冲突
257
+ 3. **私有桶**:私有桶文件通过预签名URL访问,设置合理的过期时间
258
+ 4. **文件记录**:上传后保存数据库记录,关联业务数据
259
+ 5. **大文件**:超过 100MB 考虑分片上传(`CreateMultipartUpload`)
260
+ 6. **安全**:前端直传使用预签名URL,不暴露密钥