diff --git a/schisandra-cloud-storage-auth/schisandra-cloud-storage-auth-application/schisandra-cloud-storage-auth-application-controller/src/main/java/com/schisandra/auth/application/controller/ReactRotateCaptchaController.java b/schisandra-cloud-storage-auth/schisandra-cloud-storage-auth-application/schisandra-cloud-storage-auth-application-controller/src/main/java/com/schisandra/auth/application/controller/ReactRotateCaptchaController.java index 3306f64..c07c4e2 100644 --- a/schisandra-cloud-storage-auth/schisandra-cloud-storage-auth-application/schisandra-cloud-storage-auth-application-controller/src/main/java/com/schisandra/auth/application/controller/ReactRotateCaptchaController.java +++ b/schisandra-cloud-storage-auth/schisandra-cloud-storage-auth-application/schisandra-cloud-storage-auth-application-controller/src/main/java/com/schisandra/auth/application/controller/ReactRotateCaptchaController.java @@ -4,9 +4,7 @@ import com.schisandra.auth.application.dto.SchisandraCaptchaDTO; import com.schisandra.auth.common.entity.CaptchaResult; import com.schisandra.auth.common.redis.RedisUtil; import com.schisandra.auth.common.utils.AESUtils; -import com.schisandra.auth.common.utils.MD5Util; import com.schisandra.auth.common.utils.RotateImageUtils; -import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -17,7 +15,6 @@ import javax.annotation.Resource; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; -import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.Random; diff --git a/schisandra-cloud-storage-gateway/src/main/resources/application.yml b/schisandra-cloud-storage-gateway/src/main/resources/application.yml index 181eff3..4ff787c 100644 --- a/schisandra-cloud-storage-gateway/src/main/resources/application.yml +++ b/schisandra-cloud-storage-gateway/src/main/resources/application.yml @@ -16,6 +16,12 @@ spring: - Path=/auth/** filters: - StripPrefix=1 + - id: system + uri: lb://schisandra-cloud-storage-system-dev + predicates: + - Path=/system/** + filters: + - StripPrefix=1 # redis配置 redis: # Redis数据库索引(默认为0) diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/controller/SchisandraMinioOssController.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/controller/SchisandraMinioOssController.java new file mode 100644 index 0000000..11eca67 --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/controller/SchisandraMinioOssController.java @@ -0,0 +1,47 @@ +package com.schisandra.oss.application.controller; + +import com.schisandra.oss.application.oss.constant.OssConstant; +import com.schisandra.oss.application.oss.utils.MinIOUtils; +import com.schisandra.oss.domain.bo.SchisandraOssConfigBO; +import com.schisandra.oss.domain.service.impl.SchisandraOssConfigDomainService; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.ObjectUtils; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; + +/** + * @Classname SchisandraMinioOssController + * @BelongsProject: schisandra-cloud-storage + * @BelongsPackage: com.schisandra.oss.application.controller + * @Author: landaiqing + * @CreateTime: 2024-05-13 00:04 + * @Description: TODO + * @Version: 1.0 + */ +@RestController +@RequestMapping("/oss/minio/") +@Slf4j +public class SchisandraMinioOssController { + + @Resource + private SchisandraOssConfigDomainService schisandraOssConfigDomainService; + + @RequestMapping("init") + @SneakyThrows + public void init() { + SchisandraOssConfigBO minio = schisandraOssConfigDomainService.getOssConfig(OssConstant.OssType.MINIO); + if (ObjectUtils.isEmpty(minio)) { + log.error("minio配置信息获取失败"); + } + new MinIOUtils(minio.getEndpoint(), minio.getBucketName(), minio.getAccessKey(), minio.getSecretKey(), minio.getImgSize(), minio.getFileSize()); + } + + @GetMapping("test") + public void test(){ + System.out.println(MinIOUtils.getBasisUrl()); + } +} diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/convert/SchisandraOssConfigDTOConverter.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/convert/SchisandraOssConfigDTOConverter.java index 90e9d54..e28bcf7 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/convert/SchisandraOssConfigDTOConverter.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/convert/SchisandraOssConfigDTOConverter.java @@ -18,5 +18,6 @@ public interface SchisandraOssConfigDTOConverter { SchisandraOssConfigDTOConverter INSTANCE = Mappers.getMapper(SchisandraOssConfigDTOConverter.class); SchisandraOssConfigBO convertDTOToBO(SchisandraOssConfigDTO schisandraOssConfigDTO); + SchisandraOssConfigDTO convertBOToDTO(SchisandraOssConfigBO schisandraOssConfig); } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssConstant.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssConstant.java new file mode 100644 index 0000000..f62fadf --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssConstant.java @@ -0,0 +1,60 @@ +package com.schisandra.oss.application.oss.constant; + +import java.util.concurrent.TimeUnit; + +/** + * @author landaiqing + */ +public class OssConstant { + + public static final String OSS = "oss"; + public static final String ENABLE = "enable"; + public static final String DEFAULT_ENABLE_VALUE = "true"; + + public static final int KB = 1024; + + public static final int MB = 1024 * KB; + /** + * 默认分片大小 + */ + public static final Long DEFAULT_PART_SIZE = 5L * MB; + /** + * 默认缓冲区大小 + */ + public static final int DEFAULT_BUFFER_SIZE = 8 * KB; + /** + * 默认最大分片数 + */ + public static final Long DEFAULT_PART_NUM = 10000L; + /** + * 默认并发线程数 + */ + public static final Integer DEFAULT_TASK_NUM = Runtime.getRuntime().availableProcessors(); + + public static final Long DEFAULT_CONNECTION_TIMEOUT = TimeUnit.MINUTES.toMillis(5); + + /** + * OSS存储类型 + */ + public interface OssType { + String LOCAL = "local"; + String FTP = "ftp"; + String SFTP = "sftp"; + String ALI = "ali"; + String QINIU = "qiniu"; + String MINIO = "minio"; + String BAIDU = "baidu"; + String TENCENT = "tencent"; + String HUAWEI = "huawei"; + String JD = "jd"; + String UP = "up"; + String JINSHAN = "jinshan"; + String WANGYI = "wangyi"; + String UCLOUD = "ucloud"; + String PINGAN = "pingan"; + String QINGYUN = "qingyun"; + String JDBC = "jdbc"; + String AWS = "aws"; + } + +} diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssType.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssType.java new file mode 100644 index 0000000..5b7d8bb --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/constant/OssType.java @@ -0,0 +1,107 @@ +package com.schisandra.oss.application.oss.constant; + +/** + * @author landaiqing + */ +public enum OssType { + + /** + * 本地磁盘存储 + */ + LOCAL(OssConstant.OssType.LOCAL), + + /** + * FTP协议存储 + */ + FTP(OssConstant.OssType.FTP), + + /** + * SFTP存储 + */ + SFTP(OssConstant.OssType.SFTP), + + /** + * 阿里OSS存储 + */ + ALI(OssConstant.OssType.ALI), + + /** + * 七牛云存储 + */ + QINIU(OssConstant.OssType.QINIU), + + /** + * MinIO存储 + */ + MINIO(OssConstant.OssType.MINIO), + + /** + * 百度云存储 + */ + BAIDU(OssConstant.OssType.BAIDU), + + /** + * 腾讯云存储 + */ + TENCENT(OssConstant.OssType.TENCENT), + + /** + * 华为云存储 + */ + HUAWEI(OssConstant.OssType.HUAWEI), + + /** + * 京东云存储 + */ + JD(OssConstant.OssType.JD), + + /** + * 又拍云存储 + */ + UP(OssConstant.OssType.UP), + + /** + * 金山云 + */ + JINSHAN(OssConstant.OssType.JINSHAN), + + /** + * 网易数帆 + */ + WANGYI(OssConstant.OssType.WANGYI), + + /** + * UCloud + */ + UCLOUD(OssConstant.OssType.UCLOUD), + + /** + * 平安云 + */ + PINGAN(OssConstant.OssType.PINGAN), + + /** + * 青云 + */ + QINGYUN(OssConstant.OssType.QINGYUN), + + /** + * JDBC + */ + JDBC(OssConstant.OssType.JDBC), + + /** + * 亚马逊 + */ + AWS(OssConstant.OssType.AWS); + + private final String value; + + OssType(String value) { + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/enums/OssContentType.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/enums/OssContentType.java new file mode 100644 index 0000000..f6aa472 --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/enums/OssContentType.java @@ -0,0 +1,52 @@ +package com.schisandra.oss.application.oss.enums; + +import cn.hutool.core.util.StrUtil; + +public enum OssContentType { + DEFAULT("default","application/octet-stream"), + JPG("jpg", "image/jpeg"), + TIFF("tiff", "image/tiff"), + GIF("gif", "image/gif"), + JFIF("jfif", "image/jpeg"), + PNG("png", "image/png"), + TIF("tif", "image/tiff"), + ICO("ico", "image/x-icon"), + JPEG("jpeg", "image/jpeg"), + WBMP("wbmp", "image/vnd.wap.wbmp"), + FAX("fax", "image/fax"), + NET("net", "image/pnetvue"), + JPE("jpe", "image/jpeg"), + RP("rp", "image/vnd.rn-realpix"), + MP4("mp4", "video/mp4"); + + private String prefix; + + private String type; + + public static String getContentType(String prefix){ + if(StrUtil.isEmpty(prefix)){ + return DEFAULT.getType(); + } + prefix = prefix.substring(prefix.lastIndexOf(".") + 1); + for (OssContentType value : OssContentType.values()) { + if(prefix.equalsIgnoreCase(value.getPrefix())){ + return value.getType(); + } + } + return DEFAULT.getType(); + } + + OssContentType(String prefix, String type) { + this.prefix = prefix; + this.type = type; + } + + public String getPrefix() { + return prefix; + } + + public String getType() { + return type; + } +} + diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/MinIOUtils.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/MinIOUtils.java new file mode 100644 index 0000000..f6084ec --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/MinIOUtils.java @@ -0,0 +1,439 @@ +package com.schisandra.oss.application.oss.utils; + + +import io.minio.*; +import io.minio.http.Method; +import io.minio.messages.Bucket; +import io.minio.messages.DeleteObject; +import io.minio.messages.Item; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.multipart.MultipartFile; +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Optional; + +/** + * @Classname MinIOUtils + * @BelongsProject: schisandra-cloud-storage + * @BelongsPackage: com.schisandra.oss.application.oss.utils + * @Author: landaiqing + * @CreateTime: 2024-05-12 23:50 + * @Description: MinIO工具类 + * @Version: 1.0 + */ +@Slf4j +public class MinIOUtils { + + private static MinioClient minioClient; + + private static String endpoint; + private static String bucketName; + private static String accessKey; + private static String secretKey; + private static Double imgSize; + private static Double fileSize; + + + private static final String SEPARATOR = "/"; + + public MinIOUtils() { + } + + public MinIOUtils(String endpoint, String bucketName, String accessKey, String secretKey, Double imgSize, Double fileSize) { + MinIOUtils.endpoint = endpoint; + MinIOUtils.bucketName = bucketName; + MinIOUtils.accessKey = accessKey; + MinIOUtils.secretKey = secretKey; + MinIOUtils.imgSize = imgSize; + MinIOUtils.fileSize = fileSize; + createMinioClient(); + } + + /** + * 创建基于Java端的MinioClient + */ + public void createMinioClient() { + try { + if (null == minioClient) { + log.info("开始创建 MinioClient..."); + minioClient = MinioClient + .builder() + .endpoint(endpoint) + .credentials(accessKey, secretKey) + .build(); + createBucket(bucketName); + log.info("创建完毕 MinioClient..."); + } + } catch (Exception e) { + log.error("MinIO服务器异常:{}", e); + } + } + + /** + * 获取上传文件前缀路径 + * @return + */ + public static String getBasisUrl() { + return endpoint + SEPARATOR + bucketName + SEPARATOR; + } + + /****************************** Operate Bucket Start ******************************/ + + /** + * 启动SpringBoot容器的时候初始化Bucket + * 如果没有Bucket则创建 + * @throws Exception + */ + private static void createBucket(String bucketName) throws Exception { + if (!bucketExists(bucketName)) { + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + } + } + + /** + * 判断Bucket是否存在,true:存在,false:不存在 + * @return + * @throws Exception + */ + public static boolean bucketExists(String bucketName) throws Exception { + return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + } + + + /** + * 获得Bucket的策略 + * @param bucketName + * @return + * @throws Exception + */ + public static String getBucketPolicy(String bucketName) throws Exception { + String bucketPolicy = minioClient + .getBucketPolicy( + GetBucketPolicyArgs + .builder() + .bucket(bucketName) + .build() + ); + return bucketPolicy; + } + + + /** + * 获得所有Bucket列表 + * @return + * @throws Exception + */ + public static List getAllBuckets() throws Exception { + return minioClient.listBuckets(); + } + + /** + * 根据bucketName获取其相关信息 + * @param bucketName + * @return + * @throws Exception + */ + public static Optional getBucket(String bucketName) throws Exception { + return getAllBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst(); + } + + /** + * 根据bucketName删除Bucket,true:删除成功; false:删除失败,文件或已不存在 + * @param bucketName + * @throws Exception + */ + public static void removeBucket(String bucketName) throws Exception { + minioClient.removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build()); + } + + /****************************** Operate Bucket End ******************************/ + + + /****************************** Operate Files Start ******************************/ + + /** + * 判断文件是否存在 + * @param bucketName 存储桶 + * @param objectName 文件名 + * @return + */ + public static boolean isObjectExist(String bucketName, String objectName) { + boolean exist = true; + try { + minioClient.statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } catch (Exception e) { + exist = false; + } + return exist; + } + + /** + * 判断文件夹是否存在 + * @param bucketName 存储桶 + * @param objectName 文件夹名称 + * @return + */ + public static boolean isFolderExist(String bucketName, String objectName) { + boolean exist = false; + try { + Iterable> results = minioClient.listObjects( + ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build()); + for (Result result : results) { + Item item = result.get(); + if (item.isDir() && objectName.equals(item.objectName())) { + exist = true; + } + } + } catch (Exception e) { + exist = false; + } + return exist; + } + + /** + * 根据文件前缀查询文件 + * @param bucketName 存储桶 + * @param prefix 前缀 + * @param recursive 是否使用递归查询 + * @return MinioItem 列表 + * @throws Exception + */ + public static List getAllObjectsByPrefix(String bucketName, + String prefix, + boolean recursive) throws Exception { + List list = new ArrayList<>(); + Iterable> objectsIterator = minioClient.listObjects( + ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build()); + if (objectsIterator != null) { + for (Result o : objectsIterator) { + Item item = o.get(); + list.add(item); + } + } + return list; + } + + /** + * 获取文件流 + * @param bucketName 存储桶 + * @param objectName 文件名 + * @return 二进制流 + */ + public static InputStream getObject(String bucketName, String objectName) throws Exception { + return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build()); + } + + /** + * 断点下载 + * @param bucketName 存储桶 + * @param objectName 文件名称 + * @param offset 起始字节的位置 + * @param length 要读取的长度 + * @return 二进制流 + */ + public InputStream getObject(String bucketName, String objectName, long offset, long length)throws Exception { + return minioClient.getObject( + GetObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .offset(offset) + .length(length) + .build()); + } + + /** + * 获取路径下文件列表 + * @param bucketName 存储桶 + * @param prefix 文件名称 + * @param recursive 是否递归查找,false:模拟文件夹结构查找 + * @return 二进制流 + */ + public static Iterable> listObjects(String bucketName, String prefix, + boolean recursive) { + return minioClient.listObjects( + ListObjectsArgs.builder() + .bucket(bucketName) + .prefix(prefix) + .recursive(recursive) + .build()); + } + + /** + * 使用MultipartFile进行文件上传 + * @param bucketName 存储桶 + * @param file 文件名 + * @param objectName 对象名 + * @param contentType 类型 + * @return + * @throws Exception + */ + public static ObjectWriteResponse uploadFile(String bucketName, MultipartFile file, + String objectName, String contentType) throws Exception { + InputStream inputStream = file.getInputStream(); + return minioClient.putObject( + PutObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .contentType(contentType) + .stream(inputStream, inputStream.available(), -1) + .build()); + } + + /** + * 上传本地文件 + * @param bucketName 存储桶 + * @param objectName 对象名称 + * @param fileName 本地文件路径 + */ + public static ObjectWriteResponse uploadFile(String bucketName, String objectName, + String fileName) throws Exception { + return minioClient.uploadObject( + UploadObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .filename(fileName) + .build()); + } + + /** + * 通过流上传文件 + * + * @param bucketName 存储桶 + * @param objectName 文件对象 + * @param inputStream 文件流 + */ + public static ObjectWriteResponse uploadFile(String bucketName, String objectName, InputStream inputStream) throws Exception { + return minioClient.putObject( + PutObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .stream(inputStream, inputStream.available(), -1) + .build()); + } + + /** + * 创建文件夹或目录 + * @param bucketName 存储桶 + * @param objectName 目录路径 + */ + public static ObjectWriteResponse createDir(String bucketName, String objectName) throws Exception { + return minioClient.putObject( + PutObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .stream(new ByteArrayInputStream(new byte[]{}), 0, -1) + .build()); + } + + /** + * 获取文件信息, 如果抛出异常则说明文件不存在 + * + * @param bucketName 存储桶 + * @param objectName 文件名称 + */ + public static String getFileStatusInfo(String bucketName, String objectName) throws Exception { + return minioClient.statObject( + StatObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .build()).toString(); + } + + /** + * 拷贝文件 + * + * @param bucketName 存储桶 + * @param objectName 文件名 + * @param srcBucketName 目标存储桶 + * @param srcObjectName 目标文件名 + */ + public static ObjectWriteResponse copyFile(String bucketName, String objectName, + String srcBucketName, String srcObjectName) throws Exception { + return minioClient.copyObject( + CopyObjectArgs.builder() + .source(CopySource.builder().bucket(bucketName).object(objectName).build()) + .bucket(srcBucketName) + .object(srcObjectName) + .build()); + } + + /** + * 删除文件 + * @param bucketName 存储桶 + * @param objectName 文件名称 + */ + public static void removeFile(String bucketName, String objectName) throws Exception { + minioClient.removeObject( + RemoveObjectArgs.builder() + .bucket(bucketName) + .object(objectName) + .build()); + } + + /** + * 批量删除文件 + * @param bucketName 存储桶 + * @param keys 需要删除的文件列表 + * @return + */ + public static void removeFiles(String bucketName, List keys) { + List objects = new LinkedList<>(); + keys.forEach(s -> { + objects.add(new DeleteObject(s)); + try { + removeFile(bucketName, s); + } catch (Exception e) { + log.error("批量删除失败!error:{}",e); + } + }); + } + + /** + * 获取文件外链 + * @param bucketName 存储桶 + * @param objectName 文件名 + * @param expires 过期时间 <=7 秒 (外链有效时间(单位:秒)) + * @return url + * @throws Exception + */ + public static String getPresignedObjectUrl(String bucketName, String objectName, Integer expires) throws Exception { + GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().expiry(expires).bucket(bucketName).object(objectName).build(); + return minioClient.getPresignedObjectUrl(args); + } + + /** + * 获得文件外链 + * @param bucketName + * @param objectName + * @return url + * @throws Exception + */ + public static String getPresignedObjectUrl(String bucketName, String objectName) throws Exception { + GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder() + .bucket(bucketName) + .object(objectName) + .method(Method.GET).build(); + return minioClient.getPresignedObjectUrl(args); + } + + /** + * 将URLDecoder编码转成UTF8 + * @param str + * @return + * @throws UnsupportedEncodingException + */ + public static String getUtf8ByURLDecoder(String str) throws UnsupportedEncodingException { + String url = str.replaceAll("%(?![0-9a-fA-F]{2})", "%25"); + return URLDecoder.decode(url, "UTF-8"); + } + + /****************************** Operate Files End ******************************/ + +} + + diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/OssPathUtil.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/OssPathUtil.java new file mode 100644 index 0000000..250bb43 --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-application/schisandra-cloud-storage-oss-application-controller/src/main/java/com/schisandra/oss/application/oss/utils/OssPathUtil.java @@ -0,0 +1,68 @@ +package com.schisandra.oss.application.oss.utils; + +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import lombok.extern.slf4j.Slf4j; + +/** + * @author landaiqing + * @version PathUtil.java, v 1.1 2022/2/18 17:01 chenmin Exp $ + * Created on 2022/2/18 + */ +@Slf4j +public class OssPathUtil { + + public static String valid(String basePath) { + // 根路径未配置时,默认路径为 / + if (ObjectUtil.isEmpty(basePath)) { + basePath = StrUtil.SLASH; + } + // 将路径分隔符统一转为 / + basePath = basePath.replaceAll("\\\\", StrUtil.SLASH).replaceAll("//", StrUtil.SLASH); + + // 将配置默认转为绝对路径 + if (!basePath.startsWith(StrUtil.SLASH)) { + basePath = StrUtil.SLASH + basePath; + } + if (!basePath.endsWith(StrUtil.SLASH)) { + basePath = basePath + StrUtil.SLASH; + } + return basePath; + } + + /** + * 路径转换 + * 将路径分隔符转为统一的 / 分隔 + * @param key 路径 + * @param isAbsolute 是否绝对路径 + * true:绝对路径;false:相对路径 + * @return 以 / 为分隔的路径 + */ + public static String convertPath(String key, Boolean isAbsolute) { + key = key.replaceAll("\\\\", StrUtil.SLASH).replaceAll("//", StrUtil.SLASH); + if (isAbsolute && !key.startsWith(StrUtil.SLASH)) { + key = StrUtil.SLASH + key; + } else if (!isAbsolute && key.startsWith(StrUtil.SLASH)) { + key = key.replaceFirst(StrUtil.SLASH, ""); + } + return key; + } + + /** + * 获取相对根路径的绝对路径 + * @param path 全路径 + * @param basePath 根路径 + * @param isAbsolute 是否绝对路径 + * true:绝对路径;false:相对路径 + * @return 完整路径 + */ + public static String replaceKey(String path, String basePath, Boolean isAbsolute) { + String newPath; + if (StrUtil.SLASH.equals(basePath)) { + newPath = convertPath(path, isAbsolute); + } else { + newPath = convertPath(path, isAbsolute).replaceAll(convertPath(basePath, isAbsolute), ""); + } + return convertPath(newPath, isAbsolute); + } +} diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/pom.xml b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/pom.xml index 76146cf..1b68df3 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/pom.xml +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/pom.xml @@ -100,7 +100,24 @@ caffeine 3.1.8 + + cn.hutool + hutool-all + 5.1.1 + compile + + + io.minio + minio + 8.2.1 + + + + net.coobird + thumbnailator + 0.4.8 + diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/src/main/java/com/schisandra/oss/common/utils/ImageUtil.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/src/main/java/com/schisandra/oss/common/utils/ImageUtil.java new file mode 100644 index 0000000..b1a9563 --- /dev/null +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-common/src/main/java/com/schisandra/oss/common/utils/ImageUtil.java @@ -0,0 +1,194 @@ +package com.schisandra.oss.common.utils; + +import net.coobird.thumbnailator.Thumbnails; +import net.coobird.thumbnailator.geometry.Positions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.imageio.ImageIO; +import java.awt.*; +import java.awt.font.FontRenderContext; +import java.awt.font.TextAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; + +/** + * 图像工具类 + */ +public class ImageUtil { + private static final Logger log = LoggerFactory.getLogger(ImageUtil.class); + //压缩率 + private static final transient float IMAGE_RATIO = 0.1f; + //压缩最大宽度 + private static final transient int IMAGE_WIDTH = 800; + // 水印透明度 + private static float alpha = 0.3f; + // 水印文字字体 + private static Font font = new Font("PingFang SC Regular", Font.PLAIN, 36); + // 水印文字颜色 + private static Color color = new Color(111, 111, 111); + //水印文字内容 + private static final String text = "这是一个水印文本"; + // 水印之间的间隔 + private static final int XMOVE = 80; + // 水印之间的间隔 + private static final int YMOVE = 80; + + /** + * 压缩图像 + * + * @param image + * @return + * @throws IOException + */ + public static BufferedImage compress(BufferedImage image) throws IOException { + Thumbnails.Builder imageBuilder = Thumbnails.of(image).outputQuality(IMAGE_RATIO); + if (image.getWidth() > IMAGE_WIDTH) { + return imageBuilder.width(IMAGE_WIDTH).asBufferedImage(); + } else { + return imageBuilder.scale(1).asBufferedImage(); + } + } + + /** + * 图像添加水印 + * + * @param + * @return + */ + public static BufferedImage setWatermark(BufferedImage image) throws IOException { + return Thumbnails.of(image) + .outputQuality(IMAGE_RATIO) + .scale(1) + .watermark(Positions.BOTTOM_RIGHT + , createWatermark(text + , image.getWidth() + , image.getHeight() + ) + , alpha) + .asBufferedImage(); + } + + /** + * 根据文件扩展名判断文件是否图片格式 + * + * @return + */ + public static boolean isImage(String fileName) { + String[] imageExtension = new String[]{"jpeg", "jpg", "gif", "bmp", "png"}; + + for (String e : imageExtension) if (getFileExtention(fileName).toLowerCase().equals(e)) return true; + + return false; + } + + /** + * 获取文件后缀名称 + * + * @param fileName + * @return + */ + public static String getFileExtention(String fileName) { + String extension = fileName.substring(fileName.lastIndexOf(".") + 1); + return extension; + } + + /** + * 根据图片对象获取对应InputStream + * + * @param image + * @param readImageFormat + * @return + * @throws IOException + */ + public static InputStream getInputStream(BufferedImage image, String readImageFormat) throws IOException { + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ImageIO.write(image, readImageFormat, os); + InputStream is = new ByteArrayInputStream(os.toByteArray()); + os.close(); + return is; + } + + /** + * 创建水印图片 + * + * @param text 水印文字 + * @param width 图片宽 + * @param height 图片高 + * @return + */ + public static BufferedImage createWatermark(String text, int width, int height) { + BufferedImage image = new BufferedImage(width + , height, BufferedImage.TYPE_INT_RGB); + // 2.获取图片画笔 + Graphics2D g = image.createGraphics(); + // ---------- 增加下面的代码使得背景透明 ----------------- + image = g.getDeviceConfiguration().createCompatibleImage(width, height, Transparency.TRANSLUCENT); + g.dispose(); + g = image.createGraphics(); + // ---------- 背景透明代码结束 ----------------- + // 6、处理文字 + AttributedString ats = new AttributedString(text); + ats.addAttribute(TextAttribute.FONT, font, 0, text.length()); + AttributedCharacterIterator iter = ats.getIterator(); + // 7、设置对线段的锯齿状边缘处理 + g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); + g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + // 8、设置水印旋转 + g.rotate(Math.toRadians(-30)); + // 9、设置水印文字颜色 + g.setColor(color); + // 10、设置水印文字Font + g.setFont(font); + // 11、设置水印文字透明度 + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, alpha)); + g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER)); + /** + * 水印铺满图片 + * 计算水印位置 + */ + int x = -width / 2; + int y = -height / 2; + int[] arr = getWidthAndHeight(text, font); + int markWidth = arr[0];// 字体长度 + int markHeight = arr[1];// 字体高度 + // 循环添加水印 + while (x < width * 1.5) { + y = -height / 2; + while (y < height * 1.5) { + g.drawString(text, x, y); + + y += markHeight + YMOVE; + } + x += markWidth + XMOVE; + } + // 13、释放资源 + g.dispose(); + return image; + } + + /** + * 计算字体宽度及高度 + * + * @param text + * @param font + * @return + */ + private static int[] getWidthAndHeight(String text, Font font) { + Rectangle2D r = font.getStringBounds(text, new FontRenderContext( + AffineTransform.getScaleInstance(1, 1), false, false)); + int unitHeight = (int) Math.floor(r.getHeight());// + // 获取整个str用了font样式的宽度这里用四舍五入后+1保证宽度绝对能容纳这个字符串作为图片的宽度 + int width = (int) Math.round(r.getWidth()) + 1; + // 把单个字符的高度+3保证高度绝对能容纳字符串作为图片的高度 + int height = unitHeight + 3; + return new int[]{width, height}; + } +} \ No newline at end of file diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/convert/SchisandraOssConfigBOConverter.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/convert/SchisandraOssConfigBOConverter.java index 1080d9c..2312eb9 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/convert/SchisandraOssConfigBOConverter.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/convert/SchisandraOssConfigBOConverter.java @@ -18,5 +18,6 @@ public interface SchisandraOssConfigBOConverter { SchisandraOssConfigBOConverter INSTANCE = Mappers.getMapper(SchisandraOssConfigBOConverter.class); SchisandraOssConfig convertBOToEntity(SchisandraOssConfigBO schisandraOssConfigBO); + SchisandraOssConfigBO convertEntityToBO(SchisandraOssConfig schisandraOssConfig); } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/SchisandraOssConfigDomainService.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/SchisandraOssConfigDomainService.java index c1d11a5..d410249 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/SchisandraOssConfigDomainService.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/SchisandraOssConfigDomainService.java @@ -25,4 +25,5 @@ public interface SchisandraOssConfigDomainService { */ Boolean delete(SchisandraOssConfigBO schisandraOssConfigBO); + SchisandraOssConfigBO getOssConfig(String minio); } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainServiceImpl.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainService.java similarity index 79% rename from schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainServiceImpl.java rename to schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainService.java index cb0981d..53b5911 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainServiceImpl.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-domain/src/main/java/com/schisandra/oss/domain/service/impl/SchisandraOssConfigDomainService.java @@ -4,7 +4,6 @@ package com.schisandra.oss.domain.service.impl; import com.schisandra.oss.common.enums.IsDeletedFlagEnum; import com.schisandra.oss.domain.convert.SchisandraOssConfigBOConverter; import com.schisandra.oss.domain.bo.SchisandraOssConfigBO; -import com.schisandra.oss.domain.service.SchisandraOssConfigDomainService; import com.schisandra.oss.infra.basic.entity.SchisandraOssConfig; import com.schisandra.oss.infra.basic.service.SchisandraOssConfigService; import lombok.extern.slf4j.Slf4j; @@ -20,7 +19,7 @@ import javax.annotation.Resource; */ @Service @Slf4j -public class SchisandraOssConfigDomainServiceImpl implements SchisandraOssConfigDomainService { +public class SchisandraOssConfigDomainService implements com.schisandra.oss.domain.service.SchisandraOssConfigDomainService { @Resource private SchisandraOssConfigService schisandraOssConfigService; @@ -46,4 +45,11 @@ public class SchisandraOssConfigDomainServiceImpl implements SchisandraOssConfig return schisandraOssConfigService.update(schisandraOssConfig) > 0; } + @Override + public SchisandraOssConfigBO getOssConfig(String ossType) { + SchisandraOssConfig ossConfig = schisandraOssConfigService.getOssConfig(ossType); + SchisandraOssConfigBO schisandraOssConfigBO = SchisandraOssConfigBOConverter.INSTANCE.convertEntityToBO(ossConfig); + return schisandraOssConfigBO; + } + } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/SchisandraOssConfigService.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/SchisandraOssConfigService.java index 10daff8..d769ff7 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/SchisandraOssConfigService.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/SchisandraOssConfigService.java @@ -47,4 +47,5 @@ public interface SchisandraOssConfigService { */ SchisandraOssConfig queryByCondition(SchisandraOssConfig schisandraOssConfig); + SchisandraOssConfig getOssConfig(String ossType); } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/impl/SchisandraOssConfigServiceImpl.java b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/impl/SchisandraOssConfigServiceImpl.java index 996fe95..ac47259 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/impl/SchisandraOssConfigServiceImpl.java +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-infra/src/main/java/com/schisandra/oss/infra/basic/service/impl/SchisandraOssConfigServiceImpl.java @@ -2,6 +2,7 @@ package com.schisandra.oss.infra.basic.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.schisandra.oss.infra.basic.dao.SchisandraOssConfigDao; import com.schisandra.oss.infra.basic.entity.SchisandraOssConfig; @@ -111,4 +112,11 @@ public class SchisandraOssConfigServiceImpl implements SchisandraOssConfigServic } + @Override + public SchisandraOssConfig getOssConfig(String ossType) { + SchisandraOssConfig ossConfig = schisandraOssConfigDao.selectOne(new QueryWrapper() + .eq("oss_type", ossType).eq("is_deleted", 0)); + return ossConfig; + } + } diff --git a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-starter/pom.xml b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-starter/pom.xml index 343266a..561901d 100644 --- a/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-starter/pom.xml +++ b/schisandra-cloud-storage-oss/schisandra-cloud-storage-oss-starter/pom.xml @@ -39,6 +39,14 @@ spring-cloud-starter-bootstrap + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + com.schisandra