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);
|
uploadProgressService.init(taskId);
|
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);
|
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);
|
}
|
}
|
}
|