package com.tcm.training.admin.upload; import com.obs.services.ObsClient; import com.obs.services.exception.ObsException; import com.obs.services.model.ProgressListener; import com.obs.services.model.PutObjectRequest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Service; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.nio.file.Files; import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.UUID; @Service public class ObsUploadService { private static final Logger log = LoggerFactory.getLogger(ObsUploadService.class); private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd"); private final ObsUploadProperties properties; private final UploadProgressService uploadProgressService; public ObsUploadService(ObsUploadProperties properties, UploadProgressService uploadProgressService) { this.properties = properties; this.uploadProgressService = uploadProgressService; } public UploadFileResult upload(MultipartFile file, String bizPath, String taskId) throws IOException { validateConfig(); String originalName = file.getOriginalFilename(); String objectKey = buildObjectKey(bizPath, originalName); File tempFile = createTempFile(file, originalName); long totalBytes = file.getSize(); uploadProgressService.init(taskId, totalBytes); try (ObsClient obsClient = new ObsClient( properties.getAccessKeyId(), properties.getSecretAccessKey(), properties.getEndpoint())) { PutObjectRequest request = new PutObjectRequest(); request.setBucketName(properties.getBucketName()); request.setObjectKey(objectKey); request.setFile(tempFile); request.setProgressListener((ProgressListener) progressStatus -> uploadProgressService.update(taskId, progressStatus)); request.setProgressInterval(1024 * 100L); obsClient.putObject(request); UploadFileResult result = new UploadFileResult(buildFileUrl(objectKey), originalName, objectKey); uploadProgressService.markSuccess(taskId, result, totalBytes); return result; } catch (ObsException e) { log.error("OBS文件上传失败: bucket={}, objectKey={}", properties.getBucketName(), objectKey, e); uploadProgressService.markFailed(taskId, "上传文件到OBS失败"); throw new IOException("上传文件到OBS失败", e); } catch (IOException e) { uploadProgressService.markFailed(taskId, e.getMessage()); throw e; } catch (RuntimeException e) { uploadProgressService.markFailed(taskId, e.getMessage()); throw e; } finally { Files.deleteIfExists(tempFile.toPath()); } } private void validateConfig() { if (!StringUtils.hasText(properties.getAccessKeyId()) || !StringUtils.hasText(properties.getSecretAccessKey()) || !StringUtils.hasText(properties.getBucketName()) || !StringUtils.hasText(properties.getEndpoint())) { throw new IllegalArgumentException("OBS上传配置不完整"); } } private String buildObjectKey(String bizPath, String originalName) { String extension = ""; if (StringUtils.hasText(originalName) && originalName.contains(".")) { extension = originalName.substring(originalName.lastIndexOf(".")); } String normalizedBizPath = StringUtils.hasText(bizPath) ? bizPath.trim() : "file"; String datePath = LocalDate.now().format(DATE_FORMATTER); String fileName = UUID.randomUUID().toString().replace("-", "") + extension; return normalizedBizPath + "/" + datePath + "/" + fileName; } private File createTempFile(MultipartFile file, String originalName) throws IOException { String extension = ""; if (StringUtils.hasText(originalName) && originalName.contains(".")) { extension = originalName.substring(originalName.lastIndexOf(".")); } File tempFile = File.createTempFile("obs-upload-", extension); file.transferTo(tempFile); return tempFile; } private String buildFileUrl(String objectKey) { String endpoint = properties.getEndpoint().trim(); if (!endpoint.contains("://")) { endpoint = "https://" + endpoint; } try { URI uri = new URI(endpoint); String host = uri.getHost(); if (!StringUtils.hasText(host)) { throw new IllegalArgumentException("OBS endpoint格式错误"); } String bucketHost = host.startsWith(properties.getBucketName() + ".") ? host : properties.getBucketName() + "." + host; StringBuilder builder = new StringBuilder(); builder.append(uri.getScheme()).append("://").append(bucketHost); if (uri.getPort() > -1) { builder.append(":").append(uri.getPort()); } if (StringUtils.hasText(uri.getPath()) && !"/".equals(uri.getPath())) { builder.append(uri.getPath()); } if (builder.charAt(builder.length() - 1) != '/') { builder.append("/"); } builder.append(objectKey); return builder.toString(); } catch (URISyntaxException e) { throw new IllegalArgumentException("OBS endpoint格式错误", e); } } }