From ea17240cf1db76c86cbec392072ea6f53ddcac44 Mon Sep 17 00:00:00 2001 From: Tim <135014430+nagisa77@users.noreply.github.com> Date: Thu, 31 Jul 2025 22:34:27 +0800 Subject: [PATCH] feat: support presigned url upload --- open-isle-cli/src/utils/vditor.js | 35 ++++++++----------- .../openisle/controller/UploadController.java | 5 +++ .../openisle/service/CosImageUploader.java | 23 ++++++++++++ .../com/openisle/service/ImageUploader.java | 8 +++++ 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/open-isle-cli/src/utils/vditor.js b/open-isle-cli/src/utils/vditor.js index 5592d017b..7b097381e 100644 --- a/open-isle-cli/src/utils/vditor.js +++ b/open-isle-cli/src/utils/vditor.js @@ -76,29 +76,22 @@ export function createVditor(editorId, options = {}) { 'upload' ], upload: { - fieldName: 'file', - url: `${API_BASE_URL}/api/upload`, accept: 'image/*,video/*', multiple: false, - headers: { Authorization: `Bearer ${getToken()}` }, - format(files, responseText) { - const res = JSON.parse(responseText) - if (res.code === 0) { - return JSON.stringify({ - code: 0, - msg: '', - data: { - errFiles: [], - succMap: { [files[0].name]: res.data.url } - } - }) - } else { - return JSON.stringify({ - code: 1, - msg: '上传失败', - data: { errFiles: files.map(f => f.name), succMap: {} } - }) - } + handler: async (files) => { + const file = files[0] + const res = await fetch(`${API_BASE_URL}/api/upload/presign?filename=${encodeURIComponent(file.name)}`, { + headers: { Authorization: `Bearer ${getToken()}` } + }) + if (!res.ok) return '获取上传地址失败' + const info = await res.json() + const put = await fetch(info.uploadUrl, { method: 'PUT', body: file }) + if (!put.ok) return '上传失败' + return JSON.stringify({ + code: 0, + msg: '', + data: { errFiles: [], succMap: { [file.name]: info.fileUrl } } + }) } }, toolbarConfig: { pin: true }, diff --git a/src/main/java/com/openisle/controller/UploadController.java b/src/main/java/com/openisle/controller/UploadController.java index b21c5432c..fe27b2917 100644 --- a/src/main/java/com/openisle/controller/UploadController.java +++ b/src/main/java/com/openisle/controller/UploadController.java @@ -74,4 +74,9 @@ public class UploadController { return ResponseEntity.internalServerError().body(Map.of("code", 3, "msg", "Upload failed")); } } + + @GetMapping("/presign") + public java.util.Map presign(@RequestParam("filename") String filename) { + return imageUploader.presignUpload(filename); + } } diff --git a/src/main/java/com/openisle/service/CosImageUploader.java b/src/main/java/com/openisle/service/CosImageUploader.java index accf028f6..4848daa49 100644 --- a/src/main/java/com/openisle/service/CosImageUploader.java +++ b/src/main/java/com/openisle/service/CosImageUploader.java @@ -6,6 +6,8 @@ import com.qcloud.cos.auth.BasicCOSCredentials; import com.qcloud.cos.auth.COSCredentials; import com.qcloud.cos.model.ObjectMetadata; import com.qcloud.cos.model.PutObjectRequest; +import com.qcloud.cos.http.HttpMethodName; +import com.qcloud.cos.model.GeneratePresignedUrlRequest; import com.qcloud.cos.region.Region; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.concurrent.CustomizableThreadFactory; @@ -98,4 +100,25 @@ public class CosImageUploader extends ImageUploader { logger.warn("Failed to delete image {} from COS", key, e); } } + + @Override + public java.util.Map presignUpload(String filename) { + String ext = ""; + int dot = filename.lastIndexOf('.'); + if (dot != -1) { + ext = filename.substring(dot); + } + String randomName = java.util.UUID.randomUUID().toString().replace("-", "") + ext; + String objectKey = UPLOAD_DIR + randomName; + java.util.Date expiration = new java.util.Date(System.currentTimeMillis() + 15 * 60 * 1000L); + GeneratePresignedUrlRequest req = new GeneratePresignedUrlRequest(bucketName, objectKey, HttpMethodName.PUT); + req.setExpiration(expiration); + java.net.URL url = cosClient.generatePresignedUrl(req); + String fileUrl = baseUrl + "/" + objectKey; + return java.util.Map.of( + "uploadUrl", url.toString(), + "fileUrl", fileUrl, + "key", objectKey + ); + } } diff --git a/src/main/java/com/openisle/service/ImageUploader.java b/src/main/java/com/openisle/service/ImageUploader.java index 04abf1585..e7a84b6de 100644 --- a/src/main/java/com/openisle/service/ImageUploader.java +++ b/src/main/java/com/openisle/service/ImageUploader.java @@ -38,6 +38,14 @@ public abstract class ImageUploader { protected abstract void deleteFromStore(String key); + /** + * Generate a presigned PUT URL for direct browser upload. + * Default implementation is unsupported. + */ + public java.util.Map presignUpload(String filename) { + throw new UnsupportedOperationException("presignUpload not supported"); + } + /** Extract COS URLs from text. */ public Set extractUrls(String text) { Set set = new HashSet<>();