diff --git a/pigx-common/pigx-common-minio/pom.xml b/pigx-common/pigx-common-minio/pom.xml new file mode 100755 index 000000000..07505a9bf --- /dev/null +++ b/pigx-common/pigx-common-minio/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + com.pig4cloud + pigx-common + 2.0.0 + + + pigx-common-minio + jar + + pigx 文件系统依赖 + + + + io.minio + minio + ${minio.version} + + + \ No newline at end of file diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioAutoConfiguration.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioAutoConfiguration.java new file mode 100755 index 000000000..2ba6233b4 --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioAutoConfiguration.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio; + +import com.pig4cloud.common.minio.service.MinioTemplate; +import lombok.AllArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; + +/** + * minio 自动配置类 + * + * @author lengleng + */ +@AllArgsConstructor +@EnableConfigurationProperties({MinioProperties.class}) +public class MinioAutoConfiguration { + private final MinioProperties properties; + + @Bean + @ConditionalOnMissingBean(MinioTemplate.class) + @ConditionalOnProperty(name = "minio.url") + MinioTemplate template() { + return new MinioTemplate( + properties.getUrl(), + properties.getAccessKey(), + properties.getSecretKey() + ); + } + +} diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioProperties.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioProperties.java new file mode 100755 index 000000000..664cd813c --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/MinioProperties.java @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +/** + * minio 配置信息 + * + * @author lengleng + */ +@Data +@Configuration +@ConfigurationProperties(prefix = "minio") +public class MinioProperties { + /** + * minio 服务地址 http://ip:port + */ + private String url; + + /** + * 用户名 + */ + private String accessKey; + + /** + * 密码 + */ + private String secretKey; + +} diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/http/MinioEndpoint.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/http/MinioEndpoint.java new file mode 100755 index 000000000..1952d6bfd --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/http/MinioEndpoint.java @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio.http; + +import com.pig4cloud.common.minio.service.MinioTemplate; +import com.pig4cloud.common.minio.vo.MinioItem; +import com.pig4cloud.common.minio.vo.MinioObject; +import io.minio.messages.Bucket; +import lombok.AllArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * minio 对外提供服务端点 + * + * @author lengleng + *

+ * minio.endpoint.enable + */ +@ConditionalOnProperty(name = "minio.endpoint.enable", havingValue = "true") +@RestController +@AllArgsConstructor +@RequestMapping("${minio.endpoint.name:/minio}") +public class MinioEndpoint { + private final MinioTemplate template; + + /** + * Bucket Endpoints + */ + @PostMapping("/bucket/{bucketName}") + public Bucket createBucker(@PathVariable String bucketName) throws Exception { + + template.createBucket(bucketName); + return template.getBucket(bucketName).get(); + + } + + @GetMapping("/bucket") + public List getBuckets() throws Exception { + return template.getAllBuckets(); + } + + @GetMapping("/bucket/{bucketName}") + public Bucket getBucket(@PathVariable String bucketName) throws Exception { + return template.getBucket(bucketName).orElseThrow(() -> new IllegalArgumentException("Bucket Name not found!")); + } + + @DeleteMapping("/bucket/{bucketName}") + @ResponseStatus(HttpStatus.ACCEPTED) + public void deleteBucket(@PathVariable String bucketName) throws Exception { + + template.removeBucket(bucketName); + } + + /** + * Object Endpoints + */ + + @PostMapping("/object/{bucketName}") + public MinioObject createObject(@RequestBody MultipartFile object, @PathVariable String bucketName) throws Exception { + String name = object.getOriginalFilename(); + template.putObject(bucketName, name, object.getInputStream(), object.getSize(), object.getContentType()); + return new MinioObject(template.getObjectInfo(bucketName, name)); + + } + + @PostMapping("/object/{bucketName}/{objectName}") + public MinioObject createObject(@RequestBody MultipartFile object, @PathVariable String bucketName, @PathVariable String objectName) throws Exception { + template.putObject(bucketName, objectName, object.getInputStream(), object.getSize(), object.getContentType()); + return new MinioObject(template.getObjectInfo(bucketName, objectName)); + + } + + + @GetMapping("/object/{bucketName}/{objectName}") + public List filterObject(@PathVariable String bucketName, @PathVariable String objectName) throws Exception { + + return template.getAllObjectsByPrefix(bucketName, objectName, true); + + } + + @GetMapping("/object/{bucketName}/{objectName}/{expires}") + public Map getObject(@PathVariable String bucketName, @PathVariable String objectName, @PathVariable Integer expires) throws Exception { + Map responseBody = new HashMap<>(8); + // Put Object info + responseBody.put("bucket", bucketName); + responseBody.put("object", objectName); + responseBody.put("url", template.getObjectURL(bucketName, objectName, expires)); + responseBody.put("expires", expires); + return responseBody; + } + + @DeleteMapping("/object/{bucketName}/{objectName}/") + @ResponseStatus(HttpStatus.ACCEPTED) + public void deleteObject(@PathVariable String bucketName, @PathVariable String objectName) throws Exception { + + template.removeObject(bucketName, objectName); + } + + +} diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/service/MinioTemplate.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/service/MinioTemplate.java new file mode 100755 index 000000000..396b82f90 --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/service/MinioTemplate.java @@ -0,0 +1,189 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio.service; + +import com.pig4cloud.common.minio.vo.MinioItem; +import io.minio.MinioClient; +import io.minio.ObjectStat; +import io.minio.Result; +import io.minio.messages.Bucket; +import io.minio.messages.Item; +import lombok.AllArgsConstructor; +import lombok.NoArgsConstructor; + +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +/** + * minio 交互类 + * + * @author lengleng + */ +@NoArgsConstructor +@AllArgsConstructor +public class MinioTemplate { + + private String endpoint; + private String accessKey; + private String secretKey; + + + /** + * 创建bucket + * + * @param bucketName bucket名称 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#makeBucket + */ + public void createBucket(String bucketName) throws Exception { + MinioClient client = getMinioClient(); + if (!client.bucketExists(bucketName)) { + client.makeBucket(bucketName); + } + } + + /** + * 获取全部bucket + *

+ * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets + */ + public List getAllBuckets() throws Exception { + return getMinioClient().listBuckets(); + } + + /** + * @param bucketName bucket名称 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#listBuckets + */ + public Optional getBucket(String bucketName) throws Exception { + return getMinioClient().listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst(); + } + + /** + * @param bucketName bucket名称 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeBucket + */ + public void removeBucket(String bucketName) throws Exception { + getMinioClient().removeBucket(bucketName); + } + + /** + * 根据文件前置查询文件 + * + * @param bucketName bucket名称 + * @param prefix 前缀 + * @param recursive 是否递归查询 + * @return + * @throws Exception + */ + public List getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception { + List objectList = new ArrayList(); + Iterable> objectsIterator = getMinioClient() + .listObjects(bucketName, prefix, recursive); + + while (objectsIterator.iterator().hasNext()) { + objectList.add(objectsIterator.iterator().next().get()); + } + return objectList; + } + + /** + * 获取文件外链 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @param expires 过期时间 <=7 + * @return url + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject + */ + public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception { + return getMinioClient().presignedGetObject(bucketName, objectName, expires); + } + + /** + * 获取文件 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @return 二进制流 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject + */ + public InputStream getObject(String bucketName, String objectName) throws Exception { + return getMinioClient().getObject(bucketName, objectName); + } + + /** + * 上传文件 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @param stream 文件流 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject + */ + public void putObject(String bucketName, String objectName, InputStream stream) throws Exception { + getMinioClient().putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream"); + } + + /** + * 上传文件 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @param stream 文件流 + * @param size 大小 + * @param contextType 类型 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject + */ + public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception { + getMinioClient().putObject(bucketName, objectName, stream, size, contextType); + } + + /** + * 获取文件信息 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject + */ + public ObjectStat getObjectInfo(String bucketName, String objectName) throws Exception { + return getMinioClient().statObject(bucketName, objectName); + } + + /** + * 删除文件 + * + * @param bucketName bucket名称 + * @param objectName 文件名称 + * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject + */ + public void removeObject(String bucketName, String objectName) throws Exception { + getMinioClient().removeObject(bucketName, objectName); + } + + + /** + * 获取minio 原生客户端 + * + * @return + * @throws Exception + */ + public MinioClient getMinioClient() throws Exception { + return new MinioClient(endpoint, accessKey, secretKey); + } +} diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioItem.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioItem.java new file mode 100755 index 000000000..fcb9b0644 --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioItem.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio.vo; + +import io.minio.messages.Item; +import io.minio.messages.Owner; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; + +/** + * minio 桶中的对象信息 + * + * @author lengleng + */ +@Data +@AllArgsConstructor +public class MinioItem { + + private String objectName; + private Date lastModified; + private String etag; + private Long size; + private String storageClass; + private Owner owner; + private String type; + + public MinioItem(Item item) { + this.objectName = item.objectName(); + this.lastModified = item.lastModified(); + this.etag = item.etag(); + this.size = (long) item.size(); + this.storageClass = item.storageClass(); + this.owner = item.owner(); + this.type = item.isDir() ? "directory" : "file"; + } +} diff --git a/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioObject.java b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioObject.java new file mode 100755 index 000000000..c4fd4f85c --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/java/com/pig4cloud/common/minio/vo/MinioObject.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2018-2025, lengleng All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * Neither the name of the pig4cloud.com developer nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * Author: lengleng (wangiegie@gmail.com) + */ + +package com.pig4cloud.common.minio.vo; + +import io.minio.ObjectStat; +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; + + +/** + * 存储对象的元数据 + * + * @author lengleng + */ +@Data +@AllArgsConstructor +public class MinioObject { + private String bucketName; + private String name; + private Date createdTime; + private Long length; + private String etag; + private String contentType; + private String matDesc; + + public MinioObject(ObjectStat os) { + this.bucketName = os.bucketName(); + this.name = os.name(); + this.createdTime = os.createdTime(); + this.length = os.length(); + this.etag = os.etag(); + this.contentType = os.contentType(); + this.matDesc = os.matDesc(); + } + +} diff --git a/pigx-common/pigx-common-minio/src/main/resources/META-INF/spring.factories b/pigx-common/pigx-common-minio/src/main/resources/META-INF/spring.factories new file mode 100755 index 000000000..b67a03493 --- /dev/null +++ b/pigx-common/pigx-common-minio/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ + com.pig4cloud.common.minio.MinioAutoConfiguration \ No newline at end of file diff --git a/pigx-common/pom.xml b/pigx-common/pom.xml index 35eec4fa1..80415e4c8 100644 --- a/pigx-common/pom.xml +++ b/pigx-common/pom.xml @@ -38,6 +38,7 @@ pigx-common-gateway pigx-common-job pigx-common-log + pigx-common-minio pigx-common-security pigx-common-swagger pigx-common-transaction diff --git a/pom.xml b/pom.xml index 1bf361b1b..a57e66274 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,7 @@ 4.1.0 2.1.0 2.10.1 + 3.0.12 2.1.5 8.0.13 2.3.3.RELEASE