From 5a66e972d39f2004f8241b6a119f246d308c70c8 Mon Sep 17 00:00:00 2001
From: zhaowenyu <35589726@qq.com>
Date: Wed, 26 Nov 2025 14:02:18 +0800
Subject: [PATCH] 2025-11-26 zwy 增加ossdock模块,机场自己单独用的minio

---
 pom.xml                                                                                  |    8 
 ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockServiceContext.java        |  205 ++++++++++
 ard-ossdock/src/main/java/com/ard/ossdock/model/CredentialsDockDTO.java                  |   50 ++
 ard-ossdock/src/main/java/com/ard/ossdock/model/enums/OssDockTypeEnum.java               |   25 +
 ard-ossdock/src/main/java/com/ard/ossdock/model/MinioDockUploadResult.java               |   27 +
 ard-sample/pom.xml                                                                       |    4 
 ard-ossdock/src/main/java/com/ard/ossdock/model/StsCredentialsDockDTO.java               |   33 +
 ard-admin/src/main/resources/application-daqing.yml                                      |   12 
 ard-ossdock/pom.xml                                                                      |   70 +++
 ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AmazonS3DockDockServiceImpl.java  |  129 ++++++
 ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockAspectHandler.java         |   31 +
 ard-ossdock/src/main/java/com/ard/ossdock/service/IOssDockService.java                   |   57 +++
 ard-ossdock/src/main/java/com/ard/ossdock/config/OssDockConfiguration.java               |   94 ++++
 ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AliyunDockOssDockServiceImpl.java |  115 ++++++
 ard-ossdock/src/main/java/com/ard/ossdock/service/impl/MinIODockDockServiceImpl.java     |  258 +++++++++++++
 15 files changed, 1,117 insertions(+), 1 deletions(-)

diff --git a/ard-admin/src/main/resources/application-daqing.yml b/ard-admin/src/main/resources/application-daqing.yml
index c630210..ce8b82a 100644
--- a/ard-admin/src/main/resources/application-daqing.yml
+++ b/ard-admin/src/main/resources/application-daqing.yml
@@ -79,3 +79,15 @@
   expire: 3600
   region: us-east-1
   object-dir-prefix: wayline
+
+# 机场单独用的oss配置,要http地址
+ossdock:
+  enable: true
+  provider: minio
+  endpoint: http://192.168.10.103:9011
+  access-key: admin2
+  secret-key: ard123456
+  bucket: cloud-bucket
+  expire: 3600
+  region: us-east-1
+  object-dir-prefix: wayline
\ No newline at end of file
diff --git a/ard-ossdock/pom.xml b/ard-ossdock/pom.xml
new file mode 100644
index 0000000..6aeddac
--- /dev/null
+++ b/ard-ossdock/pom.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>ard</artifactId>
+        <groupId>com.ard</groupId>
+        <version>3.8.8</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ard-ossdock</artifactId>
+
+    <description>
+        机场存储模块
+    </description>
+    <properties>
+        <aliyun-sdk-sts.version>3.1.0</aliyun-sdk-sts.version>
+        <aliyun-oss.version>3.12.0</aliyun-oss.version>
+    </properties>
+    <dependencies>
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.ard</groupId>
+            <artifactId>ard-common</artifactId>
+        </dependency>
+
+        <!-- minio依赖-->
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-s3</artifactId>
+            <version>1.12.261</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.amazonaws</groupId>
+            <artifactId>aws-java-sdk-sts</artifactId>
+            <version>1.12.261</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-sts</artifactId>
+            <version>${aliyun-sdk-sts.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>${aliyun-oss.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/config/OssDockConfiguration.java b/ard-ossdock/src/main/java/com/ard/ossdock/config/OssDockConfiguration.java
new file mode 100644
index 0000000..cc9996e
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/config/OssDockConfiguration.java
@@ -0,0 +1,94 @@
+package com.ard.ossdock.config;
+
+import com.ard.ossdock.model.enums.OssDockTypeEnum;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author sean
+ * @version 0.2
+ * @date 2021/12/9
+ */
+@Component
+@ConfigurationProperties(prefix = "ossdock")
+public class OssDockConfiguration {
+
+    /**
+     * @see OssDockTypeEnum
+     */
+    public static String provider;
+
+    /**
+     * Whether to use the object storage service.
+     */
+    public static boolean enable;
+
+    /**
+     * The protocol needs to be included at the beginning of the address.
+     */
+    public static String endpoint;
+
+    public static String accessKey;
+
+    public static String secretKey;
+
+    public static String region;
+
+    public static Long expire;
+
+    public static String roleSessionName;
+
+    public static String roleArn;
+
+    public static String bucket;
+
+    public static String objectDirPrefix;
+
+    public void setProvider(String provider) {
+        OssDockConfiguration.provider = provider;
+    }
+
+    public void setEnable(boolean enable) {
+        OssDockConfiguration.enable = enable;
+    }
+
+    public void setEndpoint(String endpoint) {
+        OssDockConfiguration.endpoint = endpoint;
+    }
+
+    public void setAccessKey(String accessKey) {
+        OssDockConfiguration.accessKey = accessKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        OssDockConfiguration.secretKey = secretKey;
+    }
+
+    public void setRegion(String region) {
+        OssDockConfiguration.region = region;
+    }
+
+    public void setExpire(Long expire) {
+        OssDockConfiguration.expire = expire;
+    }
+
+    public void setRoleSessionName(String roleSessionName) {
+        OssDockConfiguration.roleSessionName = roleSessionName;
+    }
+
+    public void setRoleArn(String roleArn) {
+        OssDockConfiguration.roleArn = roleArn;
+    }
+
+    public void setBucket(String bucket) {
+        OssDockConfiguration.bucket = bucket;
+    }
+
+    public void setObjectDirPrefix(String objectDirPrefix) {
+        OssDockConfiguration.objectDirPrefix = objectDirPrefix;
+    }
+
+}
+
+
+
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/model/CredentialsDockDTO.java b/ard-ossdock/src/main/java/com/ard/ossdock/model/CredentialsDockDTO.java
new file mode 100644
index 0000000..edb6f79
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/model/CredentialsDockDTO.java
@@ -0,0 +1,50 @@
+package com.ard.ossdock.model;
+
+import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
+import io.minio.credentials.Credentials;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+/**
+ * @author sean
+ * @version 0.2
+ * @date 2021/12/7
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class CredentialsDockDTO {
+
+    private static final int DELAY = 300;
+
+    private String accessKeyId;
+
+    private String accessKeySecret;
+
+    private Long expire;
+
+    private String securityToken;
+
+    public CredentialsDockDTO(Credentials credentials, long expire) {
+        this.accessKeyId = credentials.accessKey();
+        this.accessKeySecret = credentials.secretKey();
+        this.securityToken = credentials.sessionToken();
+        this.expire = expire - DELAY;
+    }
+
+    public CredentialsDockDTO(AssumeRoleResponse.Credentials credentials, long expire) {
+        this.accessKeyId = credentials.getAccessKeyId();
+        this.accessKeySecret = credentials.getAccessKeySecret();
+        this.securityToken = credentials.getSecurityToken();
+        this.expire = expire - DELAY;
+    }
+
+    public CredentialsDockDTO(com.amazonaws.services.securitytoken.model.Credentials credentials) {
+        this.accessKeyId = credentials.getAccessKeyId();
+        this.accessKeySecret = credentials.getSecretAccessKey();
+        this.securityToken = credentials.getSessionToken();
+        this.expire = (credentials.getExpiration().getTime() - System.currentTimeMillis()) / 1000 - DELAY;
+    }
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/model/MinioDockUploadResult.java b/ard-ossdock/src/main/java/com/ard/ossdock/model/MinioDockUploadResult.java
new file mode 100644
index 0000000..20e908e
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/model/MinioDockUploadResult.java
@@ -0,0 +1,27 @@
+package com.ard.ossdock.model;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Description: Minio上传结果
+ * Author: lsy
+ * Date: 2025年10月13日10:42
+ **/
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@Builder
+public class MinioDockUploadResult {
+
+    /** 新文件名(上传后保存名) */
+    private String newFileName;
+
+    /** 文件完整访问 URL */
+    private String url;
+
+    /** 上传前原始文件名 */
+    private String originalFilename;
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/model/StsCredentialsDockDTO.java b/ard-ossdock/src/main/java/com/ard/ossdock/model/StsCredentialsDockDTO.java
new file mode 100644
index 0000000..16f2f7c
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/model/StsCredentialsDockDTO.java
@@ -0,0 +1,33 @@
+package com.ard.ossdock.model;
+
+import com.fasterxml.jackson.databind.PropertyNamingStrategy;
+import com.fasterxml.jackson.databind.annotation.JsonNaming;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * @author sean
+ * @version 0.2
+ * @date 2021/12/7
+ */
+@Data
+@Builder
+@AllArgsConstructor
+@NoArgsConstructor
+@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class)
+public class StsCredentialsDockDTO {
+
+    private String bucket;
+
+    private CredentialsDockDTO credentials;
+
+    private String endpoint;
+
+    private String objectKeyPrefix;
+
+    private String provider;
+
+    private String region;
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/model/enums/OssDockTypeEnum.java b/ard-ossdock/src/main/java/com/ard/ossdock/model/enums/OssDockTypeEnum.java
new file mode 100644
index 0000000..ccdeec9
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/model/enums/OssDockTypeEnum.java
@@ -0,0 +1,25 @@
+package com.ard.ossdock.model.enums;
+
+/**
+ * @author sean
+ * @version 1.0
+ * @date 2022/5/30
+ */
+public enum OssDockTypeEnum {
+
+    ALIYUN("ali"),
+
+    AWS("aws"),
+
+    MINIO("minio");
+
+    private String type;
+
+    OssDockTypeEnum(String type) {
+        this.type = type;
+    }
+
+    public String getType() {
+        return type;
+    }
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/IOssDockService.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/IOssDockService.java
new file mode 100644
index 0000000..b9073a8
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/IOssDockService.java
@@ -0,0 +1,57 @@
+package com.ard.ossdock.service;
+
+import com.ard.ossdock.model.CredentialsDockDTO;
+
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2021/12/23
+ */
+public interface IOssDockService {
+
+    public String getOssType();
+
+    /**
+     * Get temporary credentials.
+     *
+     * @return
+     */
+    public CredentialsDockDTO getCredentials();
+
+    /**
+     * Get the address of the object based on the bucket name and the object name.
+     *
+     * @param bucket    bucket name
+     * @param objectKey object name
+     * @return download link
+     */
+    public URL getObjectUrl(String bucket, String objectKey);
+
+    /**
+     * Deletes the object in the storage bucket.
+     *
+     * @param bucket
+     * @param objectKey
+     * @return
+     */
+    public Boolean deleteObject(String bucket, String objectKey);
+
+    /**
+     * Get the contents of an object.
+     *
+     * @param bucket
+     * @param objectKey
+     * @return
+     */
+    public InputStream getObject(String bucket, String objectKey);
+
+    public void putObject(String bucket, String objectKey, InputStream input);
+
+    public void putObject(String bucket, String objectKey, InputStream input, String contentType);
+
+    public void createClient();
+
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AliyunDockOssDockServiceImpl.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AliyunDockOssDockServiceImpl.java
new file mode 100644
index 0000000..57aee7e
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AliyunDockOssDockServiceImpl.java
@@ -0,0 +1,115 @@
+package com.ard.ossdock.service.impl;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.OSSException;
+import com.aliyun.oss.model.ObjectMetadata;
+import com.aliyun.oss.model.PutObjectRequest;
+import com.aliyun.oss.model.PutObjectResult;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest;
+import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse;
+import com.ard.ossdock.config.OssDockConfiguration;
+import com.ard.ossdock.model.CredentialsDockDTO;
+import com.ard.ossdock.model.enums.OssDockTypeEnum;
+import com.ard.ossdock.service.IOssDockService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2021/12/23
+ */
+@Service
+@Slf4j
+public class AliyunDockOssDockServiceImpl implements IOssDockService {
+
+    private OSS ossClient;
+
+    @Override
+    public String getOssType() {
+        return OssDockTypeEnum.ALIYUN.getType();
+    }
+
+    @Override
+    public CredentialsDockDTO getCredentials() {
+
+        try {
+            DefaultProfile profile = DefaultProfile.getProfile(
+                    OssDockConfiguration.region, OssDockConfiguration.accessKey, OssDockConfiguration.secretKey);
+            IAcsClient client = new DefaultAcsClient(profile);
+
+            AssumeRoleRequest request = new AssumeRoleRequest();
+            request.setDurationSeconds(OssDockConfiguration.expire);
+            request.setRoleArn(OssDockConfiguration.roleArn);
+            request.setRoleSessionName(OssDockConfiguration.roleSessionName);
+
+            AssumeRoleResponse response = client.getAcsResponse(request);
+            return new CredentialsDockDTO(response.getCredentials(), OssDockConfiguration.expire);
+
+        } catch (ClientException e) {
+            log.debug("Failed to obtain sts.");
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    @Override
+    public URL getObjectUrl(String bucket, String objectKey) {
+        // First check if the object can be fetched.
+        boolean isExist = ossClient.doesObjectExist(bucket, objectKey);
+        if (!isExist) {
+            throw new OSSException("The object does not exist.");
+        }
+
+        return ossClient.generatePresignedUrl(bucket, objectKey,
+                new Date(System.currentTimeMillis() + OssDockConfiguration.expire * 1000));
+    }
+
+    @Override
+    public Boolean deleteObject(String bucket, String objectKey) {
+        if (!ossClient.doesObjectExist(bucket, objectKey)) {
+            return true;
+        }
+        ossClient.deleteObject(bucket, objectKey);
+        return true;
+    }
+
+    @Override
+    public InputStream getObject(String bucket, String objectKey) {
+        return ossClient.getObject(bucket, objectKey).getObjectContent();
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input) {
+        if (ossClient.doesObjectExist(bucket, objectKey)) {
+            throw new RuntimeException("The filename already exists.");
+        }
+        PutObjectResult objectResult = ossClient.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata()));
+        log.info("Upload File: {}", objectResult.getETag());
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input, String contentType) {
+
+    }
+
+    @Override
+    public void createClient() {
+        if (Objects.nonNull(this.ossClient)) {
+            return;
+        }
+        this.ossClient = new OSSClientBuilder()
+                .build(OssDockConfiguration.endpoint, OssDockConfiguration.accessKey, OssDockConfiguration.secretKey);
+    }
+
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AmazonS3DockDockServiceImpl.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AmazonS3DockDockServiceImpl.java
new file mode 100644
index 0000000..f42d6fa
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/AmazonS3DockDockServiceImpl.java
@@ -0,0 +1,129 @@
+package com.ard.ossdock.service.impl;
+
+import com.amazonaws.HttpMethod;
+import com.amazonaws.auth.AWSStaticCredentialsProvider;
+import com.amazonaws.auth.BasicAWSCredentials;
+import com.amazonaws.services.s3.AmazonS3;
+import com.amazonaws.services.s3.AmazonS3ClientBuilder;
+import com.amazonaws.services.s3.model.ObjectMetadata;
+import com.amazonaws.services.s3.model.PutObjectRequest;
+import com.amazonaws.services.s3.model.PutObjectResult;
+import com.amazonaws.services.securitytoken.AWSSecurityTokenService;
+import com.amazonaws.services.securitytoken.AWSSecurityTokenServiceClientBuilder;
+import com.amazonaws.services.securitytoken.model.AssumeRoleRequest;
+import com.amazonaws.services.securitytoken.model.AssumeRoleResult;
+import com.amazonaws.services.securitytoken.model.Credentials;
+import com.ard.ossdock.config.OssDockConfiguration;
+import com.ard.ossdock.model.CredentialsDockDTO;
+import com.ard.ossdock.model.enums.OssDockTypeEnum;
+import com.ard.ossdock.service.IOssDockService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Date;
+import java.util.Objects;
+
+/**
+ * @author sean
+ * @version 1.0
+ * @date 2022/4/27
+ */
+@Slf4j
+@Service
+public class AmazonS3DockDockServiceImpl implements IOssDockService {
+
+    private AmazonS3 client;
+    
+    @Override
+    public String getOssType() {
+        return OssDockTypeEnum.AWS.getType();
+    }
+
+    @Override
+    public CredentialsDockDTO getCredentials() {
+        AWSSecurityTokenService stsClient = AWSSecurityTokenServiceClientBuilder.standard()
+                .withCredentials(new AWSStaticCredentialsProvider(
+                        new BasicAWSCredentials(OssDockConfiguration.accessKey, OssDockConfiguration.secretKey)))
+                .withRegion(OssDockConfiguration.region).build();
+
+        AssumeRoleRequest request = new AssumeRoleRequest()
+                .withRoleArn(OssDockConfiguration.roleArn)
+                .withRoleSessionName(OssDockConfiguration.roleSessionName)
+                .withDurationSeconds(Math.toIntExact(OssDockConfiguration.expire));
+        AssumeRoleResult result = stsClient.assumeRole(request);
+        Credentials credentials = result.getCredentials();
+        return new CredentialsDockDTO(credentials);
+    }
+
+    @Override
+    public URL getObjectUrl(String bucket, String objectKey) {
+        return client.generatePresignedUrl(bucket, objectKey,
+                new Date(System.currentTimeMillis() + OssDockConfiguration.expire * 1000), HttpMethod.GET);
+    }
+
+    @Override
+    public Boolean deleteObject(String bucket, String objectKey) {
+        if (!client.doesObjectExist(bucket, objectKey)) {
+            return true;
+        }
+        client.deleteObject(bucket, objectKey);
+        return true;
+    }
+
+    @Override
+    public InputStream getObject(String bucket, String objectKey) {
+        return client.getObject(bucket, objectKey).getObjectContent().getDelegateStream();
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input) {
+        if (client.doesObjectExist(bucket, objectKey)) {
+            throw new RuntimeException("The filename already exists.");
+        }
+        PutObjectResult objectResult = client.putObject(new PutObjectRequest(bucket, objectKey, input, new ObjectMetadata()));
+        log.info("Upload File: {}", objectResult.toString());
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input, String contentType) {
+
+    }
+
+    @Override
+    public void createClient() {
+        if (Objects.nonNull(this.client)) {
+            return;
+        }
+        this.client = AmazonS3ClientBuilder.standard()
+                .withCredentials(
+                        new AWSStaticCredentialsProvider(
+                                new BasicAWSCredentials(OssDockConfiguration.accessKey, OssDockConfiguration.secretKey)))
+                .withRegion(OssDockConfiguration.region)
+                .build();
+    }
+
+//    /**
+//     * Configuring cross-origin resource sharing
+//     */
+//    @PostConstruct
+//    private void configCORS() {
+//        if (!OssConfiguration.enable || !OssTypeEnum.AWS.getType().equals(OssConfiguration.provider)) {
+//            return;
+//        }
+//        List<CORSRule.AllowedMethods> allowedMethods = new ArrayList<>();
+//        allowedMethods.add(CORSRule.AllowedMethods.GET);
+//        allowedMethods.add(CORSRule.AllowedMethods.POST);
+//        allowedMethods.add(CORSRule.AllowedMethods.DELETE);
+//
+//        CORSRule rule = new CORSRule()
+//                .withId("CORSAccessRule")
+//                .withAllowedOrigins(List.of("*"))
+//                .withAllowedHeaders(List.of(AuthInterceptor.PARAM_TOKEN))
+//                .withAllowedMethods(allowedMethods);
+//
+//        client.setBucketCrossOriginConfiguration(OssConfiguration.bucket,
+//                new BucketCrossOriginConfiguration().withRules(rule));
+//
+//    }
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/MinIODockDockServiceImpl.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/MinIODockDockServiceImpl.java
new file mode 100644
index 0000000..f5a10b9
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/MinIODockDockServiceImpl.java
@@ -0,0 +1,258 @@
+package com.ard.ossdock.service.impl;
+
+import com.ard.ossdock.config.OssDockConfiguration;
+import com.ard.ossdock.model.CredentialsDockDTO;
+import com.ard.ossdock.model.enums.OssDockTypeEnum;
+import com.ard.ossdock.service.IOssDockService;
+import io.minio.*;
+import io.minio.credentials.AssumeRoleProvider;
+import io.minio.errors.*;
+import io.minio.http.Method;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.OkHttpClient;
+import org.springframework.stereotype.Service;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.ProviderException;
+import java.security.SecureRandom;
+import java.security.cert.X509Certificate;
+import java.util.Objects;
+
+import static com.ard.ossdock.config.OssDockConfiguration.*;
+
+/**
+ * @author sean
+ * @version 0.3
+ * @date 2021/12/23
+ */
+@Service
+@Slf4j
+public class MinIODockDockServiceImpl implements IOssDockService {
+
+    private MinioClient client;
+
+    @Override
+    public String getOssType() {
+        return OssDockTypeEnum.MINIO.getType();
+    }
+
+
+    public CredentialsDockDTO getCredentials111() {
+        try {
+            AssumeRoleProvider provider = new AssumeRoleProvider(endpoint, accessKey,
+                    secretKey, Math.toIntExact(OssDockConfiguration.expire),
+                    null, OssDockConfiguration.region, null, null, null, null);
+            return new CredentialsDockDTO(provider.fetch(), OssDockConfiguration.expire);
+        } catch (NoSuchAlgorithmException e) {
+            log.debug("Failed to obtain sts.");
+            e.printStackTrace();
+        }
+        return null;
+    }
+    @Override
+    public CredentialsDockDTO getCredentials() {
+        try {
+            // 创建自签证书的 OkHttpClient
+            TrustManager[] trustAllCerts = new TrustManager[]{
+                    new X509TrustManager() {
+                        @Override
+                        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
+                        @Override
+                        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
+                        @Override
+                        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
+                    }
+            };
+            SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
+            sslContext.init(null, trustAllCerts, new SecureRandom());
+            OkHttpClient httpClient = new OkHttpClient.Builder()
+                    .sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustAllCerts[0])
+                    .hostnameVerifier((hostname, session) -> true)
+                    .build();
+
+            // 构建 AssumeRoleProvider,使用自定义 httpClient
+            AssumeRoleProvider provider = new AssumeRoleProvider(
+                    endpoint,
+                    accessKey,
+                    secretKey,
+                    Math.toIntExact(OssDockConfiguration.expire),
+                    null,
+                    OssDockConfiguration.region,
+                    null,
+                    null,
+                    null,
+                    httpClient
+            );
+
+            // 获取 STS 凭证
+            var stsCredentials = provider.fetch();
+            return new CredentialsDockDTO(stsCredentials, OssDockConfiguration.expire);
+
+        } catch (ProviderException e) {
+            log.error("Failed to parse STS response", e);
+            throw new RuntimeException("STS response parse failed", e);
+        } catch (NoSuchAlgorithmException | java.security.KeyManagementException e) {
+            log.error("Failed to create custom SSL context", e);
+            throw new RuntimeException("SSL setup failed", e);
+        }
+    }
+
+    @Override
+    public URL getObjectUrl(String bucket, String objectKey) {
+        try {
+            return new URL(
+                    client.getPresignedObjectUrl(
+                            GetPresignedObjectUrlArgs.builder()
+                                    .method(Method.GET)
+                                    .bucket(bucket)
+                                    .object(objectKey)
+                                    .expiry(Math.toIntExact(OssDockConfiguration.expire))
+                                    .build()));
+        } catch (ErrorResponseException | InsufficientDataException | InternalException |
+                 InvalidKeyException | InvalidResponseException | IOException |
+                 NoSuchAlgorithmException | XmlParserException | ServerException e) {
+            throw new RuntimeException("The file does not exist on the OssConfiguration.");
+        }
+    }
+
+    @Override
+    public Boolean deleteObject(String bucket, String objectKey) {
+        try {
+            client.removeObject(RemoveObjectArgs.builder()
+                    .bucket(bucket)
+                    .object(objectKey)
+                    .build());
+        } catch (MinioException | NoSuchAlgorithmException | IOException | InvalidKeyException e) {
+            log.error("Failed to delete file.");
+            e.printStackTrace();
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public InputStream getObject(String bucket, String objectKey) {
+        try {
+            GetObjectResponse object = client.getObject(GetObjectArgs.builder()
+                    .bucket(bucket)
+                    .object(objectKey)
+                    .build());
+            return new ByteArrayInputStream(object.readAllBytes());
+        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException | XmlParserException e) {
+            e.printStackTrace();
+        }
+        return InputStream.nullInputStream();
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input) {
+        try {
+            client.statObject(StatObjectArgs.builder()
+                    .bucket(bucket)
+                    .object(objectKey)
+                    .build());
+            throw new RuntimeException("The filename already exists.");
+        } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
+            log.info("The file does not exist, start uploading.");
+            try {
+                // 设置 partSize 为 10MB
+                long partSize = 10 * 1024 * 1024;
+                ObjectWriteResponse response = client.putObject(
+                        PutObjectArgs.builder()
+                                .bucket(bucket)
+                                .object(objectKey)
+                                .stream(input, -1, partSize)
+                                .build());
+                log.info("Upload File: {}", response.etag());
+            } catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException ex) {
+                log.error("Failed to upload File {}.", objectKey);
+                ex.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public void putObject(String bucket, String objectKey, InputStream input, String contentType) {
+        try {
+            // 检查文件是否已经存在
+            client.statObject(StatObjectArgs.builder()
+                    .bucket(bucket)
+                    .object(objectKey)
+                    .build());
+            throw new RuntimeException("The file already exists: " + objectKey);
+        } catch (ErrorResponseException e) {
+            // 如果文件不存在,则继续上传
+            log.info("The file does not exist, start uploading.");
+            try {
+                // 设置 partSize 为 10MB
+                long partSize = 10 * 1024 * 1024; // 每块 10MB
+                PutObjectArgs.Builder putArgsBuilder = PutObjectArgs.builder()
+                        .bucket(bucket)
+                        .object(objectKey)
+                        .stream(input, -1, partSize);
+
+                // 如果提供了 Content-Type,则设置该类型
+                if (contentType != null && !contentType.isEmpty()) {
+                    putArgsBuilder.contentType(contentType);
+                }
+
+                // 上传文件
+                ObjectWriteResponse response = client.putObject(putArgsBuilder.build());
+                log.info("Uploaded file successfully: {}, ETag: {}", objectKey, response.etag());
+
+            } catch (MinioException | IOException | InvalidKeyException | NoSuchAlgorithmException ex) {
+                log.error("Failed to upload file: {}", objectKey, ex);
+                throw new RuntimeException("File upload failed: " + objectKey, ex);
+            }
+        } catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
+            // 如果 statObject 发生错误,说明服务端错误或其他问题
+            log.error("Failed to check if file exists: {}", objectKey, e);
+            throw new RuntimeException("Failed to check if file exists: " + objectKey, e);
+        }
+    }
+
+    @Override
+    public void createClient() {
+        if (Objects.nonNull(this.client)) {
+            return;
+        }
+        try {
+            TrustManager[] trustAllCerts = new TrustManager[]{
+                    new X509TrustManager() {
+                        @Override
+                        public void checkClientTrusted(X509Certificate[] chain, String authType) {}
+                        @Override
+                        public void checkServerTrusted(X509Certificate[] chain, String authType) {}
+                        @Override
+                        public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[]{}; }
+                    }
+            };
+
+            SSLContext sslContext = SSLContext.getInstance("TLS");
+            sslContext.init(null, trustAllCerts, new SecureRandom());
+            SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+            OkHttpClient httpClient = new OkHttpClient.Builder()
+                    .sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0])
+                    .hostnameVerifier((hostname, session) -> true)
+                    .build();
+
+            this.client = MinioClient.builder()
+                    .endpoint(endpoint)
+                    .credentials(accessKey, secretKey)
+                    .httpClient(httpClient)
+                    .build();
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to create unsafe MinioClient", e);
+        }
+    }
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockAspectHandler.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockAspectHandler.java
new file mode 100644
index 0000000..c7896c8
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockAspectHandler.java
@@ -0,0 +1,31 @@
+package com.ard.ossdock.service.impl;
+
+import com.ard.ossdock.config.OssDockConfiguration;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author sean
+ * @version 1.1
+ * @date 2022/6/20
+ */
+@Component
+@Aspect
+public class OssDockAspectHandler {
+
+    @Autowired
+    private OssDockServiceContext ossDockServiceContext;
+
+    @Before("execution(public * com.ard.ossdock.service.impl.OssDockServiceContext.*(..))")
+    public void before() {
+        if (!OssDockConfiguration.enable) {
+            throw new IllegalArgumentException("Please enable OssConfiguration.");
+        }
+        if (this.ossDockServiceContext.getOssService() == null) {
+            throw new IllegalArgumentException("Please check the OssConfiguration configuration.");
+        }
+        this.ossDockServiceContext.createClient();
+    }
+}
diff --git a/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockServiceContext.java b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockServiceContext.java
new file mode 100644
index 0000000..946aaa2
--- /dev/null
+++ b/ard-ossdock/src/main/java/com/ard/ossdock/service/impl/OssDockServiceContext.java
@@ -0,0 +1,205 @@
+package com.ard.ossdock.service.impl;
+
+import com.ard.ossdock.config.OssDockConfiguration;
+import com.ard.common.exception.file.FileNameLengthLimitExceededException;
+import com.ard.common.utils.file.FileUploadUtils;
+import com.ard.common.utils.file.MimeTypeUtils;
+import com.ard.ossdock.model.CredentialsDockDTO;
+import com.ard.ossdock.model.enums.OssDockTypeEnum;
+import com.ard.ossdock.service.IOssDockService;
+import lombok.Cleanup;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.ard.common.utils.file.FileUploadUtils.assertAllowed;
+import static com.ard.common.utils.file.FileUploadUtils.extractFilename;
+
+/**
+ * @author sean
+ * @version 1.0
+ * @date 2022/5/30
+ */
+@Service
+public class OssDockServiceContext {
+
+    private IOssDockService ossService;
+
+    @Autowired
+    public OssDockServiceContext(List<IOssDockService> ossServices, OssDockConfiguration configuration) {
+        if (!OssDockConfiguration.enable) {
+            return;
+        }
+        this.ossService = ossServices.stream()
+                .filter(ossService -> ossService.getOssType().equals(OssDockConfiguration.provider))
+                .findFirst()
+                .orElseThrow(() -> new IllegalArgumentException("Oss provider is illegal. Optional: " +
+                        Arrays.toString(Arrays.stream(OssDockTypeEnum.values()).map(OssDockTypeEnum::getType).toArray())));
+    }
+
+    IOssDockService getOssService() {
+        return this.ossService;
+    }
+
+    public CredentialsDockDTO getCredentials() {
+        return this.ossService.getCredentials();
+    }
+
+    public URL getObjectUrl(String bucket, String objectKey) {
+        if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) {
+            throw new IllegalArgumentException();
+        }
+        return this.ossService.getObjectUrl(bucket, objectKey);
+    }
+
+    public Boolean deleteObject(String bucket, String objectKey) {
+        return this.ossService.deleteObject(bucket, objectKey);
+    }
+
+    public InputStream getObject(String bucket, String objectKey) {
+        return this.ossService.getObject(bucket, objectKey);
+    }
+
+    public void putObject(String bucket, String objectKey, InputStream stream) {
+        this.ossService.putObject(bucket, objectKey, stream);
+    }
+
+
+    void createClient() {
+        this.ossService.createClient();
+    }
+
+    /**
+     * 以默认BucketName配置上传到Minio服务器
+     *
+     * @param file 上传的文件
+     * @return 文件名称
+     * @throws Exception
+     */
+    public String upload(MultipartFile file) throws IOException {
+        try {
+            return upload(OssDockConfiguration.bucket, file);
+        } catch (Exception e) {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 自定义bucketName配置上传到Minio服务器
+     *
+     * @param file 上传的文件
+     * @return 文件名称
+     * @throws Exception
+     */
+    public String upload(String bucket, MultipartFile file) throws IOException {
+        try {
+            return upload(bucket, null, file);
+        } catch (Exception e) {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * ✅ 通用上传方法:
+     * - bucket 必传
+     * - object 可选(为空则自动生成)
+     * - 返回永久访问 URL
+     */
+    public String upload(String bucket, String object, MultipartFile file) throws IOException {
+        try {
+            // 校验文件名长度
+            int fileNameLength = file.getOriginalFilename().length();
+            if (fileNameLength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
+                throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
+            }
+
+            // 检查文件扩展名是否合法
+            assertAllowed(file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+
+            // ✅ 如果 object 为空,则自动生成文件名
+            String objectName = (object == null || object.isEmpty())
+                    ? extractFilename(file)
+                    : object;
+
+            // 通过文件扩展名获取 MIME 类型
+            String contentType = getMimeTypeByExtension(file.getOriginalFilename());
+
+            @Cleanup
+            InputStream inputStream = file.getInputStream();
+            // 上传文件到 Minio
+            this.ossService.putObject(bucket, objectName, inputStream, contentType);
+
+            return buildUrl(bucket, objectName);
+        } catch (Exception e) {
+            throw new IOException("Upload failed: " + e.getMessage(), e);
+        }
+    }
+
+    public String upload(String bucket, String objectKey, InputStream input) {
+        try {
+            // 上传文件
+            this.ossService.putObject(bucket, objectKey, input);
+            return buildUrl(bucket, objectKey);
+        } catch (Exception e) {
+            throw new RuntimeException("Upload failed: " + e.getMessage(), e);
+        }
+    }
+
+    public String upload(String bucket, String objectKey, InputStream input, String contentType) {
+        try {
+            // 上传文件时指定 Content-Type
+            this.ossService.putObject(bucket, objectKey, input, contentType);
+            return buildUrl(bucket, objectKey);
+        } catch (Exception e) {
+            throw new RuntimeException("Upload failed: " + e.getMessage(), e);
+        }
+    }
+    // 获取文件 MIME 类型
+    public String getMimeTypeByExtension(String fileName) {
+        // 获取文件扩展名
+        String extension = fileName.substring(fileName.lastIndexOf('.') + 1).toLowerCase();
+
+        // 根据文件扩展名返回 MIME 类型
+        switch (extension) {
+            case "jpg":
+            case "jpeg":
+                return "image/jpeg";
+            case "png":
+                return "image/png";
+            case "gif":
+                return "image/gif";
+            case "pdf":
+                return "application/pdf";
+            case "txt":
+                return "text/plain";
+            case "html":
+                return "text/html";
+            case "json":
+                return "application/json";
+            case "csv":
+                return "text/csv";
+            case "zip":
+                return "application/zip";
+            // 添加更多的扩展名映射
+            default:
+                return "application/octet-stream";  // 默认 MIME 类型
+        }
+    }
+
+    // 构建url
+    private String buildUrl(String bucket, String key) {
+        String base = OssDockConfiguration.endpoint;
+        if (!base.endsWith("/")) {
+            base += "/";
+        }
+        return base + bucket + "/" + key;
+    }
+
+}
diff --git a/ard-sample/pom.xml b/ard-sample/pom.xml
index b0d5fdd..5d67cfc 100644
--- a/ard-sample/pom.xml
+++ b/ard-sample/pom.xml
@@ -118,5 +118,9 @@
             <groupId>com.ard</groupId>
             <artifactId>ard-route</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.ard</groupId>
+            <artifactId>ard-ossdock</artifactId>
+        </dependency>
     </dependencies>
 </project>
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 2bc5699..2e69d2b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -218,7 +218,12 @@
                 <artifactId>ard-oss</artifactId>
                 <version>${ard.version}</version>
             </dependency>
-
+            <!-- 机场存储模块-->
+            <dependency>
+                <groupId>com.ard</groupId>
+                <artifactId>ard-ossdock</artifactId>
+                <version>${ard.version}</version>
+            </dependency>
 
             <!-- okhttp3-->
             <dependency>
@@ -270,6 +275,7 @@
         <module>ard-route</module>
         <module>ard-device</module>
         <module>ard-oss</module>
+        <module>ard-ossdock</module>
     </modules>
 
     <build>

--
Gitblit v1.9.3