zhaowenyu
2026-01-26 a6281dabf5cb8fefd91171b02627b2ea43ce8536
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
package com.ard.web.controller.sample.media;
 
import com.ard.common.config.OssConfiguration;
import com.ard.oss.model.CredentialsDTO;
import com.ard.oss.service.impl.OssServiceContext;
import com.ard.sample.utils.S3PutObjectResponse;
import io.minio.MinioClient;
import io.minio.PutObjectArgs;
import io.minio.credentials.StaticProvider;
import io.minio.errors.MinioException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import java.io.ByteArrayInputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.OffsetDateTime;
import java.time.format.DateTimeFormatter;
 
/**
 * 适配 MinIO SDK 8.3.7 + 服务器 RELEASE.2024-08-03
 * 承接大疆 PUT 上传请求,中转上传到 MinIO HTTPS 接口
 */
@Api(tags = "机场上传minio")
@Slf4j
@RestController
@RequestMapping("/minioTransfer") // 根路径,匹配 Nginx 转发的 /dock/、/kmz/ 路径
public class MinioProxyUploadController {
 
//    @Autowired
//    private MinioStsUtils minioStsUtils; // 复用你已有的 HTTPS 临时凭证工具类
 
    @Autowired
    private OssServiceContext ossService;
 
    // 你的 MinIO HTTPS 原生地址(固定,与服务器版本匹配)
//    private static final String MINIO_HTTPS_ENDPOINT = "https://192.168.1.3:9001";
 
    /**
     * 核心接口:中转大疆的 PUT 上传请求到 MinIO
     * 匹配路径:/{bucketName}/{objectName}(例:/dock/xxx.png)
     * @param bucketName 桶名(dock/kmz,与大疆上传一致)
     * @param objectName 文件名(例:dji-test-20240124.png)
     * @param fileContent 文件二进制内容(大疆上传的核心数据)
     * @param contentType 文件 MIME 类型(默认二进制流,适配多种文件格式)
     * @return S3 规范 XML 响应(返回给大疆,衔接后续流程)
     */
    @ApiOperation("minio上传")
    @PutMapping("/{bucketName}/{objectName}")
    public ResponseEntity<S3PutObjectResponse> proxyUpload(
            @PathVariable String bucketName,
            @PathVariable String objectName,
            @RequestBody byte[] fileContent,
            @RequestHeader(value = "Content-Type", defaultValue = "application/octet-stream") String contentType
    ) {
        try {
            log.info("开始中转上传文件到 MinIO,收到参数:bucketName={}, objectName={}",bucketName,objectName);
            // 步骤 1:获取 MinIO HTTPS 临时凭证(复用你的已有工具类,已验证可行)
            CredentialsDTO credentials = ossService.getCredentials();
            if (credentials == null || credentials.getAccessKeyId() == null || credentials.getSecurityToken() == null) {
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
            }
 
            // 步骤 2:构建 MinioClient(适配 SDK 8.3.7,忽略私有 SSL 证书,使用临时凭证)
            MinioClient minioClient = MinioClient.builder()
                    .endpoint(OssConfiguration.endpoint) // 指定 MinIO HTTPS 原生地址
                    .credentialsProvider(new StaticProvider(
                            credentials.getAccessKeyId(),
                            credentials.getAccessKeySecret(),
                            credentials.getSecurityToken() // SDK 8.3.7 支持临时凭证的 sessionToken 参数
                    ))
                    .build();
 
            // 步骤 3:中转上传文件到 MinIO(核心:SDK 8.3.7 兼容 PutObjectArgs 构建)
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName) // 桶名与大疆上传一致(dock/kmz)
                            .object(objectName) // 文件名与大疆上传一致
                            .stream(
                                    new ByteArrayInputStream(fileContent), // 文件二进制流
                                    fileContent.length, // 文件字节长度
                                    -1 // 自动分块(SDK 8.3.7 支持 -1 自动处理,适配小文件上传)
                            )
                            .contentType(contentType) // 文件 MIME 类型
                            .build()
            );
            log.info("文件上传成功,文件名:{}",objectName);
 
            // 步骤 4:构造符合 S3 规范的成功响应(返回给大疆,确保流程衔接)
            S3PutObjectResponse successResponse = new S3PutObjectResponse(
                    // ETag:生成文件 MD5 值(带双引号,符合 S3 规范,依赖 commons-codec)
                    "\"" + org.apache.commons.codec.digest.DigestUtils.md5Hex(fileContent) + "\"",
                    // LastModified:当前时间(ISO 格式,MinIO 服务器兼容该格式)
                    OffsetDateTime.now().format(DateTimeFormatter.ISO_OFFSET_DATE_TIME)
            );
            log.info("构造回复大疆机场的响应信息-S3PutObjectResponse:{}",successResponse);
 
            // 步骤 5:返回 200 OK + XML 格式响应(Spring Boot 自动转换实体类为 XML)
            return ResponseEntity.status(HttpStatus.OK)
                    .contentType(MediaType.APPLICATION_XML)
                    .body(successResponse);
 
        } catch (MinioException e) {
            // MinIO 上传异常(SDK 8.3.7 抛出的异常类型,与高版本一致)
            e.printStackTrace();
            log.info("MinIO 上传异常:{}",e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        } catch (NoSuchAlgorithmException | InvalidKeyException e) {
            // 凭证/算法异常(适配 SDK 8.3.7 的加密校验逻辑)
            e.printStackTrace();
            log.info("MinIO 凭证或算法异常:{}",e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        } catch (Exception e) {
            // 其他通用异常
            e.printStackTrace();
            log.info("MinIO 异常:{}",e.getMessage());
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
        }
    }
}