新增 minio-s3-api 模块,该模块定义了MinIO S3 标准接口,目前设计了两个实现,一个是基于 MinIO 官方SDK的实现,一个是自定义实现。
This commit is contained in:
parent
112aba97da
commit
701a6be443
|
@ -1,317 +0,0 @@
|
|||
//import cn.hutool.core.collection.CollUtil;
|
||||
//import cn.hutool.core.util.StrUtil;
|
||||
//import cn.hutool.http.HttpRequest;
|
||||
//import cn.hutool.http.HttpResponse;
|
||||
//import cn.hutool.http.HttpUtil;
|
||||
//import cn.hutool.http.Method;
|
||||
//import com.google.common.base.Joiner;
|
||||
//import com.google.common.collect.ImmutableSet;
|
||||
//import com.google.common.collect.Multimap;
|
||||
//import com.google.common.collect.MultimapBuilder;
|
||||
//import com.google.common.io.BaseEncoding;
|
||||
//import io.minio.PartSource;
|
||||
//import io.minio.Signer;
|
||||
//import io.minio.Xml;
|
||||
//import io.minio.credentials.Credentials;
|
||||
//import io.minio.errors.*;
|
||||
//import io.minio.http.HttpUtils;
|
||||
//import io.minio.messages.ErrorResponse;
|
||||
//import okhttp3.*;
|
||||
//
|
||||
//import javax.crypto.Mac;
|
||||
//import javax.crypto.spec.SecretKeySpec;
|
||||
//import java.io.IOException;
|
||||
//import java.io.PrintWriter;
|
||||
//import java.nio.charset.StandardCharsets;
|
||||
//import java.security.InvalidKeyException;
|
||||
//import java.security.NoSuchAlgorithmException;
|
||||
//import java.time.ZonedDateTime;
|
||||
//import java.util.*;
|
||||
//import java.util.stream.Collectors;
|
||||
//
|
||||
//public class MinIORestful2 {
|
||||
//
|
||||
// static final String serviceName = "s3";
|
||||
// static final String US_EAST_1 = "us-east-1";
|
||||
// private static final Set<String> IGNORED_HEADERS = ImmutableSet.of("accept-encoding", "authorization", "content-type", "content-length", "user-agent");
|
||||
//
|
||||
// static String accessKey = "minioadmin";
|
||||
// static String secretKey = "minioadmin";
|
||||
// static String ZERO_MD5_HASH = "1B2M2Y8AsgTpgAmY7PhCfg==";
|
||||
// static String ZERO_SHA256_HASH = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
|
||||
// static String backend = "http://localhost:9000";
|
||||
//
|
||||
// public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
//
|
||||
// // 动态传入参数
|
||||
// String url = "http://localhost:9000/document";
|
||||
//
|
||||
// HttpResponse httpResponse = request(url,"","/document","head");
|
||||
//
|
||||
// System.out.println("httpResponse.isOk()="+httpResponse.isOk());
|
||||
// System.out.println("httpResponse.getStatus()="+httpResponse.getStatus());
|
||||
// System.out.println("httpResponse.headers()="+httpResponse.headers());
|
||||
// System.out.println("httpResponse.body()="+httpResponse.body());
|
||||
//
|
||||
// }
|
||||
//
|
||||
// public static HttpResponse request(String url,String params,String path,String method) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
//
|
||||
// // 取得当前时间
|
||||
// ZonedDateTime date = ZonedDateTime.now();
|
||||
//
|
||||
// // 创建除Authorization外所有header
|
||||
// Map<String, List<String>> headers = new HashMap<>();
|
||||
// headers.put("Host", CollUtil.newArrayList(backend.replace("http://","").replace("https://","")));
|
||||
// headers.put("Accept-Encoding", CollUtil.newArrayList("identity"));
|
||||
// headers.put("User-Agent", CollUtil.newArrayList("MinIO (Windows 10; amd64) minio-java/8.3.3"));
|
||||
// headers.put("Content-MD5", CollUtil.newArrayList(ZERO_MD5_HASH));
|
||||
// headers.put("x-amz-content-sha256", CollUtil.newArrayList(ZERO_SHA256_HASH));
|
||||
// headers.put("x-amz-date", CollUtil.newArrayList(date.format(Time.AMZ_DATE_FORMAT)));
|
||||
//
|
||||
// // 计算scope
|
||||
// String scope =buildScope(serviceName,date);
|
||||
//
|
||||
// // 计算signedHeaders
|
||||
// Map<String, String> canonicalHeaders = buildCanonicalHeaders(headers,IGNORED_HEADERS);
|
||||
//
|
||||
// // 计算signedHeaders
|
||||
// String signedHeaders = buildSignedHeaders(canonicalHeaders);
|
||||
//
|
||||
// // 计算canonicalQueryString
|
||||
// String canonicalQueryString = buildCanonicalQueryString(params);
|
||||
//
|
||||
// // 计算buildCanonicalRequest
|
||||
// String canonicalRequestHash = buildCanonicalRequest(canonicalHeaders,signedHeaders,canonicalQueryString,method,path);
|
||||
//
|
||||
// // 计算stringToSign
|
||||
// String stringToSign = buildStringToSign(date,scope,canonicalRequestHash);
|
||||
//
|
||||
// // 计算signingKey
|
||||
// byte[] signingKey = buildSigningKey(serviceName,date);
|
||||
//
|
||||
// // 计算signature
|
||||
// String signature = buildSignature(signingKey,stringToSign);
|
||||
//
|
||||
// // 计算authorization
|
||||
// String authorization = buildAuthorization(accessKey,scope,signedHeaders,signature);
|
||||
//
|
||||
// HttpRequest httpRequest = HttpUtil.createRequest(Method.HEAD, url);
|
||||
// httpRequest.header(headers,true);
|
||||
// httpRequest.header("Authorization", authorization);
|
||||
//
|
||||
//
|
||||
//
|
||||
// System.out.println("scope="+scope);
|
||||
// System.out.println("canonicalHeaders="+canonicalHeaders);
|
||||
// System.out.println("signedHeaders="+signedHeaders);
|
||||
// System.out.println("canonicalQueryString="+canonicalQueryString);
|
||||
// System.out.println("canonicalRequestHash="+canonicalRequestHash);
|
||||
// System.out.println("stringToSign="+stringToSign);
|
||||
// System.out.println("signingKey="+signingKey);
|
||||
// System.out.println("signature="+signature);
|
||||
// System.out.println("authorization="+authorization);
|
||||
//
|
||||
// System.out.println("httpRequest.headers()="+httpRequest.headers());
|
||||
//
|
||||
// return httpRequest.execute();
|
||||
// }
|
||||
//
|
||||
//
|
||||
// protected void execute(
|
||||
// io.minio.http.Method method,
|
||||
// String bucketName,
|
||||
// String objectName,
|
||||
// String region,
|
||||
// Headers headers,
|
||||
// Multimap<String, String> queryParamMap,
|
||||
// Object body,
|
||||
// int length)
|
||||
// throws ErrorResponseException, InsufficientDataException, InternalException,
|
||||
// InvalidKeyException, InvalidResponseException, IOException, NoSuchAlgorithmException,
|
||||
// ServerException, XmlParserException {
|
||||
// boolean traceRequestBody = false;
|
||||
// if (body != null && !(body instanceof PartSource || body instanceof byte[])) {
|
||||
// byte[] bytes;
|
||||
// if (body instanceof CharSequence) {
|
||||
// bytes = body.toString().getBytes(StandardCharsets.UTF_8);
|
||||
// } else {
|
||||
// bytes = Xml.marshal(body).getBytes(StandardCharsets.UTF_8);
|
||||
// }
|
||||
//
|
||||
// body = bytes;
|
||||
// length = bytes.length;
|
||||
// traceRequestBody = true;
|
||||
// }
|
||||
//
|
||||
// if (body == null && (method == io.minio.http.Method.PUT || method == io.minio.http.Method.POST))
|
||||
// body = HttpUtils.EMPTY_BODY;
|
||||
//
|
||||
// HttpUrl url = buildUrl(method, bucketName, objectName, region, queryParamMap);
|
||||
// Credentials creds = (provider == null) ? null : provider.fetch();
|
||||
// Request request = createRequest(url, method, headers, body, length, creds);
|
||||
// if (creds != null) {
|
||||
// request =
|
||||
// Signer.signV4S3(
|
||||
// request,
|
||||
// region,
|
||||
// creds.accessKey(),
|
||||
// creds.secretKey(),
|
||||
// request.header("x-amz-content-sha256"));
|
||||
// }
|
||||
//
|
||||
// StringBuilder traceBuilder =
|
||||
// newTraceBuilder(
|
||||
// request, traceRequestBody ? new String((byte[]) body, StandardCharsets.UTF_8) : null);
|
||||
// PrintWriter traceStream = this.traceStream;
|
||||
// if (traceStream != null) traceStream.println(traceBuilder.toString());
|
||||
// traceBuilder.append("\n");
|
||||
//
|
||||
// OkHttpClient httpClient = this.httpClient;
|
||||
// if (!(body instanceof byte[]) && (method == io.minio.http.Method.PUT || method == io.minio.http.Method.POST)) {
|
||||
// // Issue #924: disable connection retry for PUT and POST methods for other than byte array.
|
||||
// httpClient = this.httpClient.newBuilder().retryOnConnectionFailure(false).build();
|
||||
// }
|
||||
//
|
||||
// Response response = httpClient.newCall(request).execute();
|
||||
//// String trace =
|
||||
//// response.protocol().toString().toUpperCase(Locale.US)
|
||||
//// + " "
|
||||
//// + response.code()
|
||||
//// + "\n"
|
||||
//// + response.headers();
|
||||
//// traceBuilder.append(trace).append("\n");
|
||||
//// if (traceStream != null) traceStream.println(trace);
|
||||
////
|
||||
//// if (response.isSuccessful()) {
|
||||
//// if (traceStream != null) {
|
||||
//// // Trace response body only if the request is not GetObject/ListenBucketNotification S3 API.
|
||||
//// Set<String> keys = queryParamMap.keySet();
|
||||
//// if ((method != io.minio.http.Method.GET
|
||||
//// || objectName == null
|
||||
//// || !Collections.disjoint(keys, TRACE_QUERY_PARAMS))
|
||||
//// && !(keys.contains("events") && (keys.contains("prefix") || keys.contains("suffix")))) {
|
||||
//// ResponseBody responseBody = response.peekBody(1024 * 1024);
|
||||
//// traceStream.println(responseBody.string());
|
||||
//// }
|
||||
//// traceStream.println(END_HTTP);
|
||||
//// }
|
||||
//// return response;
|
||||
//// }
|
||||
////
|
||||
//// String errorXml = null;
|
||||
//// try (ResponseBody responseBody = response.body()) {
|
||||
//// errorXml = responseBody.string();
|
||||
//// }
|
||||
////
|
||||
//// if (!("".equals(errorXml) && method.equals(io.minio.http.Method.HEAD))) {
|
||||
//// traceBuilder.append(errorXml).append("\n");
|
||||
//// if (traceStream != null) traceStream.println(errorXml);
|
||||
//// }
|
||||
////
|
||||
//// traceBuilder.append(END_HTTP).append("\n");
|
||||
//// if (traceStream != null) traceStream.println(END_HTTP);
|
||||
////
|
||||
//// // Error in case of Non-XML response from server for non-HEAD requests.
|
||||
//// String contentType = response.headers().get("content-type");
|
||||
//// if (!method.equals(io.minio.http.Method.HEAD)
|
||||
//// && (contentType == null
|
||||
//// || !Arrays.asList(contentType.split(";")).contains("application/xml"))) {
|
||||
//// throw new InvalidResponseException(
|
||||
//// response.code(),
|
||||
//// contentType,
|
||||
//// errorXml.substring(0, errorXml.length() > 1024 ? 1024 : errorXml.length()),
|
||||
//// traceBuilder.toString());
|
||||
//// }
|
||||
////
|
||||
//// ErrorResponse errorResponse = null;
|
||||
//// if (!"".equals(errorXml)) {
|
||||
//// errorResponse = Xml.unmarshal(ErrorResponse.class, errorXml);
|
||||
//// } else if (!method.equals(io.minio.http.Method.HEAD)) {
|
||||
//// throw new InvalidResponseException(
|
||||
//// response.code(), contentType, errorXml, traceBuilder.toString());
|
||||
//// }
|
||||
////
|
||||
//// if (errorResponse == null) {
|
||||
//// String code = null;
|
||||
//// String message = null;
|
||||
//// switch (response.code()) {
|
||||
//// case 301:
|
||||
//// case 307:
|
||||
//// case 400:
|
||||
//// String[] result = handleRedirectResponse(method, bucketName, response, true);
|
||||
//// code = result[0];
|
||||
//// message = result[1];
|
||||
//// break;
|
||||
//// case 404:
|
||||
//// if (objectName != null) {
|
||||
//// code = "NoSuchKey";
|
||||
//// message = "Object does not exist";
|
||||
//// } else if (bucketName != null) {
|
||||
//// code = NO_SUCH_BUCKET;
|
||||
//// message = NO_SUCH_BUCKET_MESSAGE;
|
||||
//// } else {
|
||||
//// code = "ResourceNotFound";
|
||||
//// message = "Request resource not found";
|
||||
//// }
|
||||
//// break;
|
||||
//// case 501:
|
||||
//// case 405:
|
||||
//// code = "MethodNotAllowed";
|
||||
//// message = "The specified method is not allowed against this resource";
|
||||
//// break;
|
||||
//// case 409:
|
||||
//// if (bucketName != null) {
|
||||
//// code = NO_SUCH_BUCKET;
|
||||
//// message = NO_SUCH_BUCKET_MESSAGE;
|
||||
//// } else {
|
||||
//// code = "ResourceConflict";
|
||||
//// message = "Request resource conflicts";
|
||||
//// }
|
||||
//// break;
|
||||
//// case 403:
|
||||
//// code = "AccessDenied";
|
||||
//// message = "Access denied";
|
||||
//// break;
|
||||
//// case 412:
|
||||
//// code = "PreconditionFailed";
|
||||
//// message = "At least one of the preconditions you specified did not hold";
|
||||
//// break;
|
||||
//// case 416:
|
||||
//// code = "InvalidRange";
|
||||
//// message = "The requested range cannot be satisfied";
|
||||
//// break;
|
||||
//// default:
|
||||
//// if (response.code() >= 500) {
|
||||
//// throw new ServerException(
|
||||
//// "server failed with HTTP status code " + response.code(), traceBuilder.toString());
|
||||
//// }
|
||||
////
|
||||
//// throw new InternalException(
|
||||
//// "unhandled HTTP code "
|
||||
//// + response.code()
|
||||
//// + ". Please report this issue at "
|
||||
//// + "https://github.com/minio/minio-java/issues",
|
||||
//// traceBuilder.toString());
|
||||
//// }
|
||||
////
|
||||
//// errorResponse =
|
||||
//// new ErrorResponse(
|
||||
//// code,
|
||||
//// message,
|
||||
//// bucketName,
|
||||
//// objectName,
|
||||
//// request.url().encodedPath(),
|
||||
//// response.header("x-amz-request-id"),
|
||||
//// response.header("x-amz-id-2"));
|
||||
//// }
|
||||
////
|
||||
//// // invalidate region cache if needed
|
||||
//// if (errorResponse.code().equals(NO_SUCH_BUCKET) || errorResponse.code().equals(RETRY_HEAD)) {
|
||||
//// regionCache.remove(bucketName);
|
||||
//// }
|
||||
////
|
||||
//// throw new ErrorResponseException(errorResponse, response, traceBuilder.toString());
|
||||
// }
|
||||
//
|
||||
//}
|
|
@ -85,7 +85,9 @@ public class MinioRepositoryImpl implements MinioRepository {
|
|||
@Override
|
||||
public ObjectWriteResponse completeMultipartUpload(MultipartUploadCreateDTO multipartUploadCreate) {
|
||||
try {
|
||||
return this.getClient().completeMultipartUpload(multipartUploadCreate.getBucketName(), multipartUploadCreate.getRegion(), multipartUploadCreate.getObjectName(), multipartUploadCreate.getUploadId(), multipartUploadCreate.getParts(), multipartUploadCreate.getHeaders(), multipartUploadCreate.getExtraQueryParams());
|
||||
return this.getClient().completeMultipartUpload(multipartUploadCreate.getBucketName(), multipartUploadCreate.getRegion()
|
||||
, multipartUploadCreate.getObjectName(), multipartUploadCreate.getUploadId(), multipartUploadCreate.getParts(), multipartUploadCreate.getHeaders()
|
||||
, multipartUploadCreate.getExtraQueryParams());
|
||||
} catch (Exception e) {
|
||||
log.error(MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED.getMessage()+",uploadId:{},ObjectName:{},失败原因:{},", multipartUploadCreate.getUploadId(), multipartUploadCreate.getObjectName(), e.getMessage(), e);
|
||||
throw new MinioPlusException(MinioPlusErrorCode.COMPLETE_MULTIPART_FAILED);
|
||||
|
|
|
@ -3,14 +3,19 @@
|
|||
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>minio-plus-api-wrapper</artifactId>
|
||||
<artifactId>minio-s3-api</artifactId>
|
||||
<groupId>org.liuxp</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>minio-plus-api-wrapper-custom</artifactId>
|
||||
|
||||
<artifactId>minio-s3-api-custom</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -1,21 +1,16 @@
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.HexUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import cn.hutool.http.Method;
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
import io.minio.Digest;
|
||||
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
|
@ -25,7 +20,10 @@ public class MinIORestful {
|
|||
|
||||
static final String serviceName = "s3";
|
||||
static final String US_EAST_1 = "us-east-1";
|
||||
private static final Set<String> IGNORED_HEADERS = ImmutableSet.of("accept-encoding", "authorization", "content-type", "content-length", "user-agent");
|
||||
|
||||
|
||||
|
||||
private static final Set<String> IGNORED_HEADERS = CollUtil.set(true,"accept-encoding", "authorization", "content-type", "content-length", "user-agent");
|
||||
|
||||
static String accessKey = "minioadmin";
|
||||
static String secretKey = "minioadmin";
|
||||
|
@ -35,6 +33,8 @@ public class MinIORestful {
|
|||
|
||||
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
|
||||
|
||||
|
||||
// 动态传入参数
|
||||
String url = "http://localhost:9000/document";
|
||||
|
||||
|
@ -146,7 +146,7 @@ public class MinIORestful {
|
|||
* @return
|
||||
*/
|
||||
public static String buildSignedHeaders(Map<String, String> canonicalHeaders) {
|
||||
return Joiner.on(";").join(canonicalHeaders.keySet());
|
||||
return StrUtil.join(";", canonicalHeaders.keySet());
|
||||
}
|
||||
|
||||
public static String buildCanonicalQueryString(String params){
|
||||
|
@ -155,31 +155,51 @@ public class MinIORestful {
|
|||
return "";
|
||||
}
|
||||
|
||||
return params;
|
||||
|
||||
//TODO
|
||||
|
||||
// MapUtil
|
||||
|
||||
// Building a multimap which only order keys, ordering values is not performed
|
||||
// until MinIO server supports it.
|
||||
Multimap<String, String> signedQueryParams =
|
||||
MultimapBuilder.treeKeys().arrayListValues().build();
|
||||
|
||||
for (String queryParam : params.split("&")) {
|
||||
String[] tokens = queryParam.split("=");
|
||||
if (tokens.length > 1) {
|
||||
signedQueryParams.put(tokens[0], tokens[1]);
|
||||
} else {
|
||||
signedQueryParams.put(tokens[0], "");
|
||||
}
|
||||
}
|
||||
|
||||
return Joiner.on("&").withKeyValueSeparator("=").join(signedQueryParams.entries());
|
||||
// Multimap<String, String> signedQueryParams =
|
||||
// MultimapBuilder.treeKeys().arrayListValues().build();
|
||||
//
|
||||
// for (String queryParam : params.split("&")) {
|
||||
// String[] tokens = queryParam.split("=");
|
||||
// if (tokens.length > 1) {
|
||||
// signedQueryParams.put(tokens[0], tokens[1]);
|
||||
// } else {
|
||||
// signedQueryParams.put(tokens[0], "");
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// return Joiner.on("&").withKeyValueSeparator("=").join(signedQueryParams.entries());
|
||||
|
||||
}
|
||||
|
||||
public static String buildCanonicalRequest(Map<String, String> canonicalHeaders,String signedHeaders
|
||||
,String canonicalQueryString,String method,String path) throws NoSuchAlgorithmException {
|
||||
|
||||
StringBuilder headers = new StringBuilder();
|
||||
for (String key : canonicalHeaders.keySet()) {
|
||||
|
||||
headers.append(key);
|
||||
headers.append(":");
|
||||
headers.append(canonicalHeaders.get(key));
|
||||
headers.append("\n");
|
||||
}
|
||||
|
||||
String canonicalRequest = method + "\n" + path + "\n" + canonicalQueryString + "\n"
|
||||
+ Joiner.on("\n").withKeyValueSeparator(":").join(canonicalHeaders) + "\n\n" + signedHeaders + "\n" + ZERO_SHA256_HASH;
|
||||
+ headers + "\n" + signedHeaders + "\n" + ZERO_SHA256_HASH;
|
||||
System.out.println("canonicalRequest="+canonicalRequest);
|
||||
return Digest.sha256Hash(canonicalRequest);
|
||||
|
||||
byte[] data = canonicalRequest.getBytes(StandardCharsets.UTF_8);
|
||||
MessageDigest sha256Digest = MessageDigest.getInstance("SHA-256");
|
||||
sha256Digest.update(data, 0, data.length);
|
||||
|
||||
return HexUtil.encodeHexStr(sha256Digest.digest());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -217,7 +237,7 @@ public class MinIORestful {
|
|||
*/
|
||||
public static String buildSignature(byte[] signingKey,String stringToSign) throws NoSuchAlgorithmException, InvalidKeyException {
|
||||
byte[] digest = sumHmac(signingKey, stringToSign.getBytes(StandardCharsets.UTF_8));
|
||||
return BaseEncoding.base16().encode(digest).toLowerCase(Locale.US);
|
||||
return HexUtil.encodeHexStr(digest);
|
||||
}
|
||||
|
||||
/**
|
|
@ -0,0 +1,21 @@
|
|||
<?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>minio-s3-api</artifactId>
|
||||
<groupId>org.liuxp</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>minio-s3-api-definition</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,52 @@
|
|||
package org.liuxp.minioplus.s3.def;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
public class ListParts {
|
||||
|
||||
private String bucketName;
|
||||
|
||||
private String objectName;
|
||||
|
||||
private int maxParts;
|
||||
|
||||
private List<Part> partList = null;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@ToString
|
||||
static class Part{
|
||||
private int partNumber;
|
||||
|
||||
private String etag;
|
||||
|
||||
private ZonedDateTime lastModified;
|
||||
|
||||
private Long size;
|
||||
}
|
||||
|
||||
ListParts addPart(int partNumber,String etag,ZonedDateTime lastModified,Long size){
|
||||
|
||||
Part part = new Part();
|
||||
part.setPartNumber(partNumber);
|
||||
part.setEtag(etag);
|
||||
part.setLastModified(lastModified);
|
||||
part.setSize(size);
|
||||
|
||||
if(this.partList == null){
|
||||
partList = new ArrayList<>();
|
||||
}
|
||||
partList.add(part);
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
package org.liuxp.minioplus.s3.def;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MinIO S3文件存储引擎接口定义
|
||||
*
|
||||
* @author contact@liuxp.me
|
||||
* @since 2024/06/03
|
||||
*/
|
||||
public interface MinioS3Client {
|
||||
|
||||
/**
|
||||
* 判断存储桶是否存在
|
||||
* @param bucketName 桶名称
|
||||
* @return 是否存在
|
||||
*/
|
||||
Boolean bucketExists(String bucketName);
|
||||
|
||||
/**
|
||||
* 创建桶
|
||||
* @param bucketName 桶名称
|
||||
*/
|
||||
void makeBucket(String bucketName);
|
||||
|
||||
/**
|
||||
* 创建上传任务
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称(含路径)
|
||||
* @return UploadId 上传任务编号
|
||||
*/
|
||||
String createMultipartUpload(String bucketName, String objectName);
|
||||
|
||||
/**
|
||||
* 合并分片
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称(含路径)
|
||||
* @param uploadId 上传任务编号
|
||||
* @param parts 分片信息 partNumber & etag
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean completeMultipartUpload(String bucketName, String objectName, String uploadId, List<ListParts.Part> parts);
|
||||
|
||||
/**
|
||||
* 获取分片信息列表
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称(含路径)
|
||||
* @param maxParts 分片数量
|
||||
* @param uploadId 上传任务编号
|
||||
* @return 分片信息
|
||||
*/
|
||||
ListParts listParts(String bucketName,String objectName,Integer maxParts,String uploadId);
|
||||
|
||||
/**
|
||||
* 获得对象&分片上传链接
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称(含路径)
|
||||
* @param partNumber 分片序号
|
||||
* @return {@link String}
|
||||
*/
|
||||
String getUploadObjectUrl(String bucketName, String objectName, String partNumber);
|
||||
|
||||
/**
|
||||
* 取得下载链接
|
||||
* @param fileName 文件全名含扩展名
|
||||
* @param contentType 数据类型
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称含路径
|
||||
* @return 下载地址
|
||||
*/
|
||||
String getDownloadUrl(String fileName, String contentType, String bucketName, String objectName);
|
||||
|
||||
/**
|
||||
* 取得图片预览链接
|
||||
* @param contentType 数据类型
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称含路径
|
||||
* @return 图片预览链接
|
||||
*/
|
||||
String getPreviewUrl(String contentType, String bucketName, String objectName);
|
||||
|
||||
/**
|
||||
* 写入文件
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称含路径
|
||||
* @param stream 文件流
|
||||
* @param size 文件长度
|
||||
* @param contentType 文件类型
|
||||
* @return 是否成功
|
||||
*/
|
||||
Boolean putObject(String bucketName, String objectName, InputStream stream, long size, String contentType);
|
||||
|
||||
/**
|
||||
* 读取文件
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称含路径
|
||||
* @return 文件流
|
||||
*/
|
||||
byte[] getObject(String bucketName, String objectName);
|
||||
|
||||
/**
|
||||
* 删除文件
|
||||
* @param bucketName 桶名称
|
||||
* @param objectName 对象名称含路径
|
||||
*/
|
||||
void removeObject(String bucketName, String objectName);
|
||||
|
||||
}
|
|
@ -3,13 +3,13 @@
|
|||
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>minio-plus-api-wrapper</artifactId>
|
||||
<artifactId>minio-s3-api</artifactId>
|
||||
<groupId>org.liuxp</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>minio-plus-api-wrapper-official</artifactId>
|
||||
<artifactId>minio-s3-api-official</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<!-- minio -->
|
||||
|
@ -28,10 +28,6 @@
|
|||
<artifactId>okhttp</artifactId>
|
||||
<version>4.11.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* MinIO Java SDK for Amazon S3 Compatible Cloud Storage,
|
||||
* (C) 2020 MinIO, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Locale;
|
||||
|
||||
/** Time formatters for S3 APIs. */
|
||||
public class Time {
|
||||
public static final ZoneId UTC = ZoneId.of("Z");
|
||||
|
||||
public static final DateTimeFormatter AMZ_DATE_FORMAT =
|
||||
DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'", Locale.US).withZone(UTC);
|
||||
|
||||
public static final DateTimeFormatter RESPONSE_DATE_FORMAT =
|
||||
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH':'mm':'ss'.'SSS'Z'", Locale.US).withZone(UTC);
|
||||
|
||||
// Formatted string is convertible to LocalDate only, not to LocalDateTime or ZonedDateTime.
|
||||
// Below example shows how to use this to get ZonedDateTime.
|
||||
// LocalDate.parse("20200225", SIGNER_DATE_FORMAT).atStartOfDay(UTC);
|
||||
public static final DateTimeFormatter SIGNER_DATE_FORMAT =
|
||||
DateTimeFormatter.ofPattern("yyyyMMdd", Locale.US).withZone(UTC);
|
||||
|
||||
public static final DateTimeFormatter HTTP_HEADER_DATE_FORMAT =
|
||||
DateTimeFormatter.ofPattern("EEE',' dd MMM yyyy HH':'mm':'ss 'GMT'", Locale.US).withZone(UTC);
|
||||
|
||||
public static final DateTimeFormatter EXPIRATION_DATE_FORMAT = RESPONSE_DATE_FORMAT;
|
||||
|
||||
private Time() {}
|
||||
}
|
|
@ -9,12 +9,13 @@
|
|||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>minio-plus-api-wrapper</artifactId>
|
||||
<artifactId>minio-s3-api</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<modules>
|
||||
<module>minio-plus-api-wrapper-custom</module>
|
||||
<module>minio-plus-api-wrapper-official</module>
|
||||
<module>minio-s3-api-definition</module>
|
||||
<module>minio-s3-api-custom</module>
|
||||
<module>minio-s3-api-official</module>
|
||||
</modules>
|
||||
|
||||
</project>
|
2
pom.xml
2
pom.xml
|
@ -35,7 +35,6 @@
|
|||
</scm>
|
||||
|
||||
<modules>
|
||||
<module>minio-plus-api-wrapper</module>
|
||||
<module>minio-plus-application</module>
|
||||
<module>minio-plus-common</module>
|
||||
<module>minio-plus-config</module>
|
||||
|
@ -43,6 +42,7 @@
|
|||
<module>minio-plus-extension</module>
|
||||
<module>minio-plus-model</module>
|
||||
<module>minio-plus-spring-boot-starter</module>
|
||||
<module>minio-s3-api</module>
|
||||
</modules>
|
||||
|
||||
<properties>
|
||||
|
|
Loading…
Reference in New Issue