feat: support presigned url upload

This commit is contained in:
Tim
2025-07-31 22:34:27 +08:00
parent 68e3daa736
commit ea17240cf1
4 changed files with 50 additions and 21 deletions
+14 -21
View File
@@ -76,29 +76,22 @@ export function createVditor(editorId, options = {}) {
'upload' 'upload'
], ],
upload: { upload: {
fieldName: 'file',
url: `${API_BASE_URL}/api/upload`,
accept: 'image/*,video/*', accept: 'image/*,video/*',
multiple: false, multiple: false,
headers: { Authorization: `Bearer ${getToken()}` }, handler: async (files) => {
format(files, responseText) { const file = files[0]
const res = JSON.parse(responseText) const res = await fetch(`${API_BASE_URL}/api/upload/presign?filename=${encodeURIComponent(file.name)}`, {
if (res.code === 0) { headers: { Authorization: `Bearer ${getToken()}` }
return JSON.stringify({ })
code: 0, if (!res.ok) return '获取上传地址失败'
msg: '', const info = await res.json()
data: { const put = await fetch(info.uploadUrl, { method: 'PUT', body: file })
errFiles: [], if (!put.ok) return '上传失败'
succMap: { [files[0].name]: res.data.url } return JSON.stringify({
} code: 0,
}) msg: '',
} else { data: { errFiles: [], succMap: { [file.name]: info.fileUrl } }
return JSON.stringify({ })
code: 1,
msg: '上传失败',
data: { errFiles: files.map(f => f.name), succMap: {} }
})
}
} }
}, },
toolbarConfig: { pin: true }, toolbarConfig: { pin: true },
@@ -74,4 +74,9 @@ public class UploadController {
return ResponseEntity.internalServerError().body(Map.of("code", 3, "msg", "Upload failed")); return ResponseEntity.internalServerError().body(Map.of("code", 3, "msg", "Upload failed"));
} }
} }
@GetMapping("/presign")
public java.util.Map<String, String> presign(@RequestParam("filename") String filename) {
return imageUploader.presignUpload(filename);
}
} }
@@ -6,6 +6,8 @@ import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials; import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.ObjectMetadata; import com.qcloud.cos.model.ObjectMetadata;
import com.qcloud.cos.model.PutObjectRequest; 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 com.qcloud.cos.region.Region;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.concurrent.CustomizableThreadFactory; 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); logger.warn("Failed to delete image {} from COS", key, e);
} }
} }
@Override
public java.util.Map<String, String> 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
);
}
} }
@@ -38,6 +38,14 @@ public abstract class ImageUploader {
protected abstract void deleteFromStore(String key); protected abstract void deleteFromStore(String key);
/**
* Generate a presigned PUT URL for direct browser upload.
* Default implementation is unsupported.
*/
public java.util.Map<String, String> presignUpload(String filename) {
throw new UnsupportedOperationException("presignUpload not supported");
}
/** Extract COS URLs from text. */ /** Extract COS URLs from text. */
public Set<String> extractUrls(String text) { public Set<String> extractUrls(String text) {
Set<String> set = new HashSet<>(); Set<String> set = new HashSet<>();