“mitao”
2026-04-23 bae38167a14707a0378590b60e09dc8a6bcf2433
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
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);
        }
    }
}