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