ai-engineering-init 1.7.0 → 1.10.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 (139) hide show
  1. package/.claude/agents/bug-analyzer.md +103 -0
  2. package/.claude/agents/code-reviewer.md +115 -5
  3. package/.claude/agents/image-reader.md +154 -0
  4. package/.claude/agents/loki-runner.md +80 -0
  5. package/.claude/agents/mysql-runner.md +81 -0
  6. package/.claude/agents/requirements-analyzer.md +162 -0
  7. package/.claude/agents/task-fetcher.md +75 -0
  8. package/.claude/commands/dev.md +29 -0
  9. package/.claude/commands/next.md +31 -1
  10. package/.claude/commands/progress.md +23 -1
  11. package/.claude/hooks/skill-forced-eval.js +46 -62
  12. package/.claude/settings.json +10 -1
  13. package/.claude/skills/api-development/SKILL.md +179 -130
  14. package/.claude/skills/architecture-design/SKILL.md +102 -212
  15. package/.claude/skills/backend-annotations/SKILL.md +166 -220
  16. package/.claude/skills/bug-detective/SKILL.md +225 -186
  17. package/.claude/skills/code-patterns/SKILL.md +127 -244
  18. package/.claude/skills/collaborating-with-codex/SKILL.md +96 -113
  19. package/.claude/skills/crud-development/SKILL.md +226 -307
  20. package/.claude/skills/data-permission/SKILL.md +131 -202
  21. package/.claude/skills/database-ops/SKILL.md +158 -355
  22. package/.claude/skills/error-handler/SKILL.md +224 -285
  23. package/.claude/skills/file-oss-management/SKILL.md +174 -169
  24. package/.claude/skills/git-workflow/SKILL.md +123 -341
  25. package/.claude/skills/json-serialization/SKILL.md +121 -137
  26. package/.claude/skills/performance-doctor/SKILL.md +83 -89
  27. package/.claude/skills/redis-cache/SKILL.md +134 -185
  28. package/.claude/skills/scheduled-jobs/SKILL.md +187 -224
  29. package/.claude/skills/security-guard/SKILL.md +168 -276
  30. package/.claude/skills/sms-mail/SKILL.md +266 -228
  31. package/.claude/skills/social-login/SKILL.md +257 -195
  32. package/.claude/skills/tenant-management/SKILL.md +172 -188
  33. package/.claude/skills/utils-toolkit/SKILL.md +214 -222
  34. package/.claude/skills/websocket-sse/SKILL.md +251 -172
  35. package/.claude/skills/workflow-engine/SKILL.md +178 -250
  36. package/.codex/skills/api-development/SKILL.md +179 -130
  37. package/.codex/skills/architecture-design/SKILL.md +102 -212
  38. package/.codex/skills/backend-annotations/SKILL.md +166 -220
  39. package/.codex/skills/bug-detective/SKILL.md +225 -186
  40. package/.codex/skills/code-patterns/SKILL.md +127 -244
  41. package/.codex/skills/collaborating-with-codex/SKILL.md +96 -113
  42. package/.codex/skills/crud-development/SKILL.md +226 -307
  43. package/.codex/skills/data-permission/SKILL.md +131 -202
  44. package/.codex/skills/database-ops/SKILL.md +158 -355
  45. package/.codex/skills/dev/SKILL.md +476 -131
  46. package/.codex/skills/error-handler/SKILL.md +224 -285
  47. package/.codex/skills/file-oss-management/SKILL.md +174 -169
  48. package/.codex/skills/git-workflow/SKILL.md +123 -341
  49. package/.codex/skills/json-serialization/SKILL.md +121 -137
  50. package/.codex/skills/next/SKILL.md +186 -42
  51. package/.codex/skills/performance-doctor/SKILL.md +83 -89
  52. package/.codex/skills/progress/SKILL.md +147 -76
  53. package/.codex/skills/redis-cache/SKILL.md +134 -185
  54. package/.codex/skills/scheduled-jobs/SKILL.md +187 -224
  55. package/.codex/skills/security-guard/SKILL.md +168 -276
  56. package/.codex/skills/sms-mail/SKILL.md +266 -228
  57. package/.codex/skills/social-login/SKILL.md +257 -195
  58. package/.codex/skills/tenant-management/SKILL.md +172 -188
  59. package/.codex/skills/utils-toolkit/SKILL.md +214 -222
  60. package/.codex/skills/websocket-sse/SKILL.md +251 -172
  61. package/.codex/skills/workflow-engine/SKILL.md +178 -250
  62. package/.cursor/agents/bug-analyzer.md +102 -0
  63. package/.cursor/agents/code-reviewer.md +80 -97
  64. package/.cursor/agents/image-reader.md +154 -0
  65. package/.cursor/agents/loki-runner.md +80 -0
  66. package/.cursor/agents/mysql-runner.md +81 -0
  67. package/.cursor/agents/project-manager.md +1 -1
  68. package/.cursor/agents/requirements-analyzer.md +141 -0
  69. package/.cursor/agents/task-fetcher.md +75 -0
  70. package/.cursor/hooks/cursor-skill-eval.js +66 -6
  71. package/.cursor/skills/api-development/SKILL.md +179 -130
  72. package/.cursor/skills/architecture-design/SKILL.md +102 -212
  73. package/.cursor/skills/backend-annotations/SKILL.md +166 -220
  74. package/.cursor/skills/bug-detective/SKILL.md +225 -186
  75. package/.cursor/skills/code-patterns/SKILL.md +127 -244
  76. package/.cursor/skills/collaborating-with-codex/SKILL.md +96 -113
  77. package/.cursor/skills/crud-development/SKILL.md +226 -307
  78. package/.cursor/skills/data-permission/SKILL.md +131 -202
  79. package/.cursor/skills/database-ops/SKILL.md +158 -355
  80. package/.cursor/skills/error-handler/SKILL.md +224 -285
  81. package/.cursor/skills/file-oss-management/SKILL.md +174 -169
  82. package/.cursor/skills/git-workflow/SKILL.md +123 -341
  83. package/.cursor/skills/json-serialization/SKILL.md +121 -137
  84. package/.cursor/skills/performance-doctor/SKILL.md +83 -89
  85. package/.cursor/skills/redis-cache/SKILL.md +134 -185
  86. package/.cursor/skills/scheduled-jobs/SKILL.md +187 -224
  87. package/.cursor/skills/security-guard/SKILL.md +168 -276
  88. package/.cursor/skills/sms-mail/SKILL.md +266 -228
  89. package/.cursor/skills/social-login/SKILL.md +257 -195
  90. package/.cursor/skills/tenant-management/SKILL.md +172 -188
  91. package/.cursor/skills/utils-toolkit/SKILL.md +214 -222
  92. package/.cursor/skills/websocket-sse/SKILL.md +251 -172
  93. package/.cursor/skills/workflow-engine/SKILL.md +178 -250
  94. package/AGENTS.md +117 -540
  95. package/CLAUDE.md +105 -117
  96. package/README.md +37 -6
  97. package/bin/index.js +5 -1
  98. package/package.json +1 -1
  99. package/src/skills/api-development/SKILL.md +179 -130
  100. package/src/skills/architecture-design/SKILL.md +102 -212
  101. package/src/skills/backend-annotations/SKILL.md +166 -220
  102. package/src/skills/bug-detective/SKILL.md +225 -186
  103. package/src/skills/code-patterns/SKILL.md +127 -244
  104. package/src/skills/collaborating-with-codex/SKILL.md +96 -113
  105. package/src/skills/crud-development/SKILL.md +226 -307
  106. package/src/skills/data-permission/SKILL.md +131 -202
  107. package/src/skills/database-ops/SKILL.md +158 -355
  108. package/src/skills/error-handler/SKILL.md +224 -285
  109. package/src/skills/file-oss-management/SKILL.md +174 -169
  110. package/src/skills/git-workflow/SKILL.md +123 -341
  111. package/src/skills/json-serialization/SKILL.md +121 -137
  112. package/src/skills/performance-doctor/SKILL.md +83 -89
  113. package/src/skills/redis-cache/SKILL.md +134 -185
  114. package/src/skills/scheduled-jobs/SKILL.md +187 -224
  115. package/src/skills/security-guard/SKILL.md +168 -276
  116. package/src/skills/sms-mail/SKILL.md +266 -228
  117. package/src/skills/social-login/SKILL.md +257 -195
  118. package/src/skills/tenant-management/SKILL.md +172 -188
  119. package/src/skills/utils-toolkit/SKILL.md +214 -222
  120. package/src/skills/websocket-sse/SKILL.md +251 -172
  121. package/src/skills/workflow-engine/SKILL.md +178 -250
  122. package/.claude/skills/skill-creator/LICENSE.txt +0 -202
  123. package/.claude/skills/skill-creator/SKILL.md +0 -479
  124. package/.claude/skills/skill-creator/agents/analyzer.md +0 -274
  125. package/.claude/skills/skill-creator/agents/comparator.md +0 -202
  126. package/.claude/skills/skill-creator/agents/grader.md +0 -223
  127. package/.claude/skills/skill-creator/assets/eval_review.html +0 -146
  128. package/.claude/skills/skill-creator/eval-viewer/generate_review.py +0 -471
  129. package/.claude/skills/skill-creator/eval-viewer/viewer.html +0 -1325
  130. package/.claude/skills/skill-creator/references/schemas.md +0 -430
  131. package/.claude/skills/skill-creator/scripts/__init__.py +0 -0
  132. package/.claude/skills/skill-creator/scripts/aggregate_benchmark.py +0 -401
  133. package/.claude/skills/skill-creator/scripts/generate_report.py +0 -326
  134. package/.claude/skills/skill-creator/scripts/improve_description.py +0 -248
  135. package/.claude/skills/skill-creator/scripts/package_skill.py +0 -136
  136. package/.claude/skills/skill-creator/scripts/quick_validate.py +0 -103
  137. package/.claude/skills/skill-creator/scripts/run_eval.py +0 -310
  138. package/.claude/skills/skill-creator/scripts/run_loop.py +0 -332
  139. package/.claude/skills/skill-creator/scripts/utils.py +0 -47
@@ -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,不暴露密钥