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 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 接口
|
*/
|
@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 响应(返回给大疆,衔接后续流程)
|
*/
|
@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);
|
}
|
}
|
}
|