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