From 7c5b144b90670e8d1a6568378eb3a930747b4b71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90li?= <15040126243@163.com> Date: Wed, 9 Feb 2022 11:38:09 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E5=A2=9E=E5=8A=A0=20ruoyi-common-oss=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + ruoyi-common/pom.xml | 1 + ruoyi-common/ruoyi-common-bom/pom.xml | 7 + ruoyi-common/ruoyi-common-oss/pom.xml | 53 +++++ .../common/oss/constant/OssConstant.java | 38 ++++ .../ruoyi/common/oss/entity/UploadResult.java | 24 +++ .../com/ruoyi/common/oss/enumd/OssEnumd.java | 52 +++++ .../ruoyi/common/oss/enumd/PolicyType.java | 51 +++++ .../common/oss/exception/OssException.java | 16 ++ .../ruoyi/common/oss/factory/OssFactory.java | 79 ++++++++ .../common/oss/properties/OssProperties.java | 48 +++++ .../common/oss/service/IOssStrategy.java | 67 +++++++ .../abstractd/AbstractOssStrategy.java | 64 ++++++ .../oss/service/impl/AliyunOssStrategy.java | 115 +++++++++++ .../oss/service/impl/MinioOssStrategy.java | 184 ++++++++++++++++++ .../oss/service/impl/QcloudOssStrategy.java | 124 ++++++++++++ .../oss/service/impl/QiniuOssStrategy.java | 127 ++++++++++++ .../main/resources/META-INF/spring.factories | 1 + 18 files changed, 1057 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-oss/pom.xml create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/constant/OssConstant.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/entity/UploadResult.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/OssEnumd.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/PolicyType.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/exception/OssException.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/factory/OssFactory.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/IOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/abstractd/AbstractOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/AliyunOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/MinioOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QcloudOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QiniuOssStrategy.java create mode 100644 ruoyi-common/ruoyi-common-oss/src/main/resources/META-INF/spring.factories diff --git a/pom.xml b/pom.xml index ad7aa0a4..6496e14d 100644 --- a/pom.xml +++ b/pom.xml @@ -49,6 +49,12 @@ 3.0.3 1.28.0 + + 7.9.2 + 3.14.0 + 5.6.68 + 8.3.5 + localhost http://${docker.registry.url}:2375 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index fbc15739..8d5d11c3 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -25,6 +25,7 @@ ruoyi-common-dubbo ruoyi-common-seata ruoyi-common-loadbalancer + ruoyi-common-oss ruoyi-common diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index f9ead887..85623563 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -114,6 +114,13 @@ ruoyi-common-loadbalancer ${project.version} + + + com.ruoyi + ruoyi-common-oss + ${project.version} + + diff --git a/ruoyi-common/ruoyi-common-oss/pom.xml b/ruoyi-common/ruoyi-common-oss/pom.xml new file mode 100644 index 00000000..d3b83ce9 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/pom.xml @@ -0,0 +1,53 @@ + + + + com.ruoyi + ruoyi-common + 0.5.0 + + 4.0.0 + + ruoyi-common-oss + + + ruoyi-common-oss oss服务 + + + + + + com.ruoyi + ruoyi-common-redis + + + + com.qiniu + qiniu-java-sdk + ${qiniu.version} + + + com.aliyun.oss + aliyun-sdk-oss + ${aliyun.oss.version} + + + com.qcloud + cos_api + ${qcloud.cos.version} + + + org.slf4j + slf4j-log4j12 + + + + + io.minio + minio + ${minio.version} + + + + diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/constant/OssConstant.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/constant/OssConstant.java new file mode 100644 index 00000000..3e5730e4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/constant/OssConstant.java @@ -0,0 +1,38 @@ +package com.ruoyi.common.oss.constant; + +import java.util.Arrays; +import java.util.List; + +/** + * 对象存储常量 + * + * @author Lion Li + */ +public class OssConstant { + + /** + * OSS模块KEY + */ + public static final String SYS_OSS_KEY = "sys_oss:"; + + /** + * 对象存储配置KEY + */ + public static final String OSS_CONFIG_KEY = "OssConfig"; + + /** + * 缓存配置KEY + */ + public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + OSS_CONFIG_KEY; + + /** + * 预览列表资源开关Key + */ + public static final String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource"; + + /** + * 系统数据ids + */ + public static final List SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4); + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/entity/UploadResult.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/entity/UploadResult.java new file mode 100644 index 00000000..fd2e7fc1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/entity/UploadResult.java @@ -0,0 +1,24 @@ +package com.ruoyi.common.oss.entity; + +import lombok.Builder; +import lombok.Data; + +/** + * 上传返回体 + * + * @author Lion Li + */ +@Data +@Builder +public class UploadResult { + + /** + * 文件路径 + */ + private String url; + + /** + * 文件名 + */ + private String filename; +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/OssEnumd.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/OssEnumd.java new file mode 100644 index 00000000..cc281381 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/OssEnumd.java @@ -0,0 +1,52 @@ +package com.ruoyi.common.oss.enumd; + +import com.ruoyi.common.oss.service.impl.AliyunOssStrategy; +import com.ruoyi.common.oss.service.impl.MinioOssStrategy; +import com.ruoyi.common.oss.service.impl.QcloudOssStrategy; +import com.ruoyi.common.oss.service.impl.QiniuOssStrategy; +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 对象存储服务商枚举 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum OssEnumd { + + /** + * 七牛云 + */ + QINIU("qiniu", QiniuOssStrategy.class), + + /** + * 阿里云 + */ + ALIYUN("aliyun", AliyunOssStrategy.class), + + /** + * 腾讯云 + */ + QCLOUD("qcloud", QcloudOssStrategy.class), + + /** + * minio + */ + MINIO("minio", MinioOssStrategy.class); + + private final String value; + + private final Class beanClass; + + public static OssEnumd find(String value) { + for (OssEnumd enumd : values()) { + if (enumd.getValue().equals(value)) { + return enumd; + } + } + return null; + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/PolicyType.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/PolicyType.java new file mode 100644 index 00000000..704874bd --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/enumd/PolicyType.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2018-2028, Chill Zhuang 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 dreamlu.net 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: Chill 庄骞 (smallchill@163.com) + */ +package com.ruoyi.common.oss.enumd; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * minio策略配置 + * + * @author Lion Li + */ +@Getter +@AllArgsConstructor +public enum PolicyType { + + /** + * 只读 + */ + READ("read-only"), + + /** + * 只写 + */ + WRITE("write-only"), + + /** + * 读写 + */ + READ_WRITE("read-write"); + + /** + * 类型 + */ + private final String type; + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/exception/OssException.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/exception/OssException.java new file mode 100644 index 00000000..061165b4 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/exception/OssException.java @@ -0,0 +1,16 @@ +package com.ruoyi.common.oss.exception; + +/** + * OSS异常类 + * + * @author Lion Li + */ +public class OssException extends RuntimeException { + + private static final long serialVersionUID = 1L; + + public OssException(String msg) { + super(msg); + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/factory/OssFactory.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/factory/OssFactory.java new file mode 100644 index 00000000..107d646d --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/factory/OssFactory.java @@ -0,0 +1,79 @@ +package com.ruoyi.common.oss.factory; + +import com.ruoyi.common.core.utils.JsonUtils; +import com.ruoyi.common.core.utils.SpringUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.oss.constant.OssConstant; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.exception.OssException; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.IOssStrategy; +import com.ruoyi.common.oss.service.abstractd.AbstractOssStrategy; +import com.ruoyi.common.redis.utils.RedisUtils; +import lombok.extern.slf4j.Slf4j; + +/** + * 文件上传Factory + * + * @author Lion Li + */ +@Slf4j +public class OssFactory { + + /** + * 初始化工厂 + */ + public static void init() { + log.info("初始化OSS工厂"); + RedisUtils.subscribe(OssConstant.CACHE_CONFIG_KEY, String.class, type -> { + AbstractOssStrategy strategy = getStrategy(type); + // 未初始化不处理 + if (strategy.isInit) { + refresh(type); + log.info("订阅刷新OSS配置 => " + type); + } + }); + } + + /** + * 获取默认实例 + */ + public static IOssStrategy instance() { + // 获取redis 默认类型 + String type = RedisUtils.getCacheObject(OssConstant.CACHE_CONFIG_KEY); + if (StringUtils.isEmpty(type)) { + throw new OssException("文件存储服务类型无法找到!"); + } + return instance(type); + } + + /** + * 根据类型获取实例 + */ + public static IOssStrategy instance(String type) { + OssEnumd enumd = OssEnumd.find(type); + if (enumd == null) { + throw new OssException("文件存储服务类型无法找到!"); + } + AbstractOssStrategy strategy = getStrategy(type); + if (!strategy.isInit) { + refresh(type); + } + return strategy; + } + + private static void refresh(String type) { + Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + type); + OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class); + if (properties == null) { + throw new OssException("系统异常, '" + type + "'配置信息不存在!"); + } + getStrategy(type).init(properties); + } + + private static AbstractOssStrategy getStrategy(String type) { + OssEnumd enumd = OssEnumd.find(type); + return (AbstractOssStrategy) SpringUtils.getBean(enumd.getBeanClass()); + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java new file mode 100644 index 00000000..2975f951 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/properties/OssProperties.java @@ -0,0 +1,48 @@ +package com.ruoyi.common.oss.properties; + +import lombok.Data; + +/** + * OSS对象存储 配置属性 + * + * @author Lion Li + */ +@Data +public class OssProperties { + + /** + * 域名 + */ + private String endpoint; + + /** + * 前缀 + */ + private String prefix; + + /** + * ACCESS_KEY + */ + private String accessKey; + + /** + * SECRET_KEY + */ + private String secretKey; + + /** + * 存储空间名 + */ + private String bucketName; + + /** + * 存储区域 + */ + private String region; + + /** + * 是否https(Y=是,N=否) + */ + private String isHttps; + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/IOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/IOssStrategy.java new file mode 100644 index 00000000..6e1de5b1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/IOssStrategy.java @@ -0,0 +1,67 @@ +package com.ruoyi.common.oss.service; + + +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; + +import java.io.InputStream; + +/** + * 对象存储策略 + * + * @author Lion Li + */ +public interface IOssStrategy { + + void createBucket(); + + /** + * 获取服务商类型 + * @return + */ + OssEnumd getServiceType(); + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + UploadResult upload(byte[] data, String path, String contentType); + + /** + * 文件删除 + * + * @param path 文件路径,包含文件名 + */ + void delete(String path); + + /** + * 文件上传 + * + * @param data 文件字节数组 + * @param suffix 后缀 + * @return 返回http地址 + */ + UploadResult uploadSuffix(byte[] data, String suffix, String contentType); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param path 文件路径,包含文件名 + * @return 返回http地址 + */ + UploadResult upload(InputStream inputStream, String path, String contentType); + + /** + * 文件上传 + * + * @param inputStream 字节流 + * @param suffix 后缀 + * @return 返回http地址 + */ + UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/abstractd/AbstractOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/abstractd/AbstractOssStrategy.java new file mode 100644 index 00000000..d837800b --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/abstractd/AbstractOssStrategy.java @@ -0,0 +1,64 @@ +package com.ruoyi.common.oss.service.abstractd; + +import cn.hutool.core.io.IoUtil; +import cn.hutool.core.util.IdUtil; +import com.ruoyi.common.core.utils.DateUtils; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.IOssStrategy; + +import java.io.InputStream; + +/** + * 对象存储策略(支持七牛、阿里云、腾讯云、minio) + * + * @author Lion Li + */ +public abstract class AbstractOssStrategy implements IOssStrategy { + + protected OssProperties properties; + public boolean isInit = false; + + public void init(OssProperties properties) { + this.properties = properties; + } + + @Override + public abstract void createBucket(); + + @Override + public abstract OssEnumd getServiceType(); + + public String getPath(String prefix, String suffix) { + // 生成uuid + String uuid = IdUtil.fastSimpleUUID(); + // 文件路径 + String path = DateUtils.datePath() + "/" + uuid; + if (StringUtils.isNotBlank(prefix)) { + path = prefix + "/" + path; + } + return path + suffix; + } + + @Override + public abstract UploadResult upload(byte[] data, String path, String contentType); + + @Override + public abstract void delete(String path); + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + byte[] data = IoUtil.readBytes(inputStream); + return this.upload(data, path, contentType); + } + + @Override + public abstract UploadResult uploadSuffix(byte[] data, String suffix, String contentType); + + @Override + public abstract UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType); + + public abstract String getEndpointLink(); +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/AliyunOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/AliyunOssStrategy.java new file mode 100644 index 00000000..f0d3fb35 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/AliyunOssStrategy.java @@ -0,0 +1,115 @@ +package com.ruoyi.common.oss.service.impl; + +import com.aliyun.oss.ClientConfiguration; +import com.aliyun.oss.OSSClient; +import com.aliyun.oss.common.auth.DefaultCredentialProvider; +import com.aliyun.oss.model.CannedAccessControlList; +import com.aliyun.oss.model.CreateBucketRequest; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.exception.OssException; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.abstractd.AbstractOssStrategy; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 阿里云存储策略 + * + * @author Lion Li + */ +@Component +public class AliyunOssStrategy extends AbstractOssStrategy { + + private OSSClient client; + + @Override + public void init(OssProperties ossProperties) { + super.init(ossProperties); + try { + ClientConfiguration configuration = new ClientConfiguration(); + DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider( + properties.getAccessKey(), properties.getSecretKey()); + client = new OSSClient(properties.getEndpoint(), credentialProvider, configuration); + createBucket(); + } catch (Exception e) { + throw new OssException("阿里云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + isInit = true; + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (client.doesBucketExist(bucketName)) { + return; + } + CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); + createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead); + client.createBucket(createBucketRequest); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对阿里云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public OssEnumd getServiceType() { + return OssEnumd.ALIYUN; + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(contentType); + client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]"); + } + return UploadResult.builder().url(getEndpointLink() + "/" + path).filename(path).build(); } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + client.deleteObject(properties.getBucketName(), path); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查阿里云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + String endpoint = properties.getEndpoint(); + StringBuilder sb = new StringBuilder(endpoint); + if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) { + sb.insert(7, properties.getBucketName() + "."); + } else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) { + sb.insert(8, properties.getBucketName() + "."); + } else { + throw new OssException("Endpoint配置错误"); + } + return sb.toString(); + } +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/MinioOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/MinioOssStrategy.java new file mode 100644 index 00000000..50d52b8b --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/MinioOssStrategy.java @@ -0,0 +1,184 @@ +package com.ruoyi.common.oss.service.impl; + +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.enumd.PolicyType; +import com.ruoyi.common.oss.exception.OssException; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.abstractd.AbstractOssStrategy; +import io.minio.*; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * minio存储策略 + * + * @author Lion Li + */ +@Component +public class MinioOssStrategy extends AbstractOssStrategy { + + private MinioClient minioClient; + + @Override + public void init(OssProperties ossProperties) { + super.init(ossProperties); + try { + minioClient = MinioClient.builder() + .endpoint(properties.getEndpoint()) + .credentials(properties.getAccessKey(), properties.getSecretKey()) + .build(); + createBucket(); + } catch (Exception e) { + throw new OssException("Minio存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + isInit = true; + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); + if (exists) { + return; + } + // 不存在就创建桶 + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + minioClient.setBucketPolicy(SetBucketPolicyArgs.builder() + .bucket(bucketName) + .config(getPolicy(bucketName, PolicyType.READ)) + .build()); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对Minio配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public OssEnumd getServiceType() { + return OssEnumd.MINIO; + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + minioClient.putObject(PutObjectArgs.builder() + .bucket(properties.getBucketName()) + .object(path) + .contentType(StringUtils.blankToDefault(contentType, MediaType.APPLICATION_OCTET_STREAM_VALUE)) + .stream(inputStream, inputStream.available(), -1) + .build()); + } catch (Exception e) { + throw new OssException("上传文件失败,请核对Minio配置信息:[" + e.getMessage() + "]"); + } + return UploadResult.builder().url(getEndpointLink() + "/" + path).filename(path).build(); + } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + minioClient.removeObject(RemoveObjectArgs.builder() + .bucket(properties.getBucketName()) + .object(path) + .build()); + } catch (Exception e) { + throw new OssException(e.getMessage()); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + return properties.getEndpoint() + "/" + properties.getBucketName(); + } + + private String getPolicy(String bucketName, PolicyType policyType) { + StringBuilder builder = new StringBuilder(); + builder.append("{\n"); + builder.append(" \"Statement\": [\n"); + builder.append(" {\n"); + builder.append(" \"Action\": [\n"); + if (policyType == PolicyType.WRITE) { + builder.append(" \"s3:GetBucketLocation\",\n"); + builder.append(" \"s3:ListBucketMultipartUploads\"\n"); + } else if (policyType == PolicyType.READ_WRITE) { + builder.append(" \"s3:GetBucketLocation\",\n"); + builder.append(" \"s3:ListBucket\",\n"); + builder.append(" \"s3:ListBucketMultipartUploads\"\n"); + } else { + builder.append(" \"s3:GetBucketLocation\"\n"); + } + builder.append(" ],\n"); + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n"); + builder.append(" },\n"); + if (PolicyType.READ.equals(policyType)) { + builder.append(" {\n"); + builder.append(" \"Action\": [\n"); + builder.append(" \"s3:ListBucket\"\n"); + builder.append(" ],\n"); + builder.append(" \"Effect\": \"Deny\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("\"\n"); + builder.append(" },\n"); + } + builder.append(" {\n"); + builder.append(" \"Action\": "); + switch (policyType) { + case WRITE: + builder.append("[\n"); + builder.append(" \"s3:AbortMultipartUpload\",\n"); + builder.append(" \"s3:DeleteObject\",\n"); + builder.append(" \"s3:ListMultipartUploadParts\",\n"); + builder.append(" \"s3:PutObject\"\n"); + builder.append(" ],\n"); + break; + case READ_WRITE: + builder.append("[\n"); + builder.append(" \"s3:AbortMultipartUpload\",\n"); + builder.append(" \"s3:DeleteObject\",\n"); + builder.append(" \"s3:GetObject\",\n"); + builder.append(" \"s3:ListMultipartUploadParts\",\n"); + builder.append(" \"s3:PutObject\"\n"); + builder.append(" ],\n"); + break; + default: + builder.append("\"s3:GetObject\",\n"); + break; + } + builder.append(" \"Effect\": \"Allow\",\n"); + builder.append(" \"Principal\": \"*\",\n"); + builder.append(" \"Resource\": \"arn:aws:s3:::"); + builder.append(bucketName); + builder.append("/*\"\n"); + builder.append(" }\n"); + builder.append(" ],\n"); + builder.append(" \"Version\": \"2012-10-17\"\n"); + builder.append("}\n"); + return builder.toString(); + } +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QcloudOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QcloudOssStrategy.java new file mode 100644 index 00000000..6c19b346 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QcloudOssStrategy.java @@ -0,0 +1,124 @@ +package com.ruoyi.common.oss.service.impl; + +import com.qcloud.cos.COSClient; +import com.qcloud.cos.ClientConfig; +import com.qcloud.cos.auth.BasicCOSCredentials; +import com.qcloud.cos.auth.COSCredentials; +import com.qcloud.cos.http.HttpProtocol; +import com.qcloud.cos.model.*; +import com.qcloud.cos.region.Region; +import com.ruoyi.common.core.utils.StringUtils; +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.exception.OssException; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.abstractd.AbstractOssStrategy; +import org.springframework.stereotype.Component; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; + +/** + * 腾讯云存储策略 + * + * @author Lion Li + */ +@Component +public class QcloudOssStrategy extends AbstractOssStrategy { + + private COSClient client; + + @Override + public void init(OssProperties ossProperties) { + super.init(ossProperties); + try { + COSCredentials credentials = new BasicCOSCredentials( + properties.getAccessKey(), properties.getSecretKey()); + // 初始化客户端配置 + ClientConfig clientConfig = new ClientConfig(); + // 设置bucket所在的区域,华南:gz 华北:tj 华东:sh + clientConfig.setRegion(new Region(properties.getRegion())); + if ("Y".equals(properties.getIsHttps())) { + clientConfig.setHttpProtocol(HttpProtocol.https); + } else { + clientConfig.setHttpProtocol(HttpProtocol.http); + } + client = new COSClient(credentials, clientConfig); + createBucket(); + } catch (Exception e) { + throw new OssException("腾讯云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + isInit = true; + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (client.doesBucketExist(bucketName)) { + return; + } + CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName); + createBucketRequest.setCannedAcl(CannedAccessControlList.PublicRead); + client.createBucket(createBucketRequest); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对腾讯云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public OssEnumd getServiceType() { + return OssEnumd.QCLOUD; + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + return upload(new ByteArrayInputStream(data), path, contentType); + } + + @Override + public UploadResult upload(InputStream inputStream, String path, String contentType) { + try { + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(contentType); + client.putObject(new PutObjectRequest(properties.getBucketName(), path, inputStream, metadata)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检查腾讯云配置信息:[" + e.getMessage() + "]"); + } + return UploadResult.builder().url(getEndpointLink() + "/" + path).filename(path).build(); + } + + @Override + public void delete(String path) { + path = path.replace(getEndpointLink() + "/", ""); + try { + client.deleteObject(new DeleteObjectRequest(properties.getBucketName(), path)); + } catch (Exception e) { + throw new OssException("上传文件失败,请检腾讯云查配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + String endpoint = properties.getEndpoint(); + StringBuilder sb = new StringBuilder(endpoint); + if (StringUtils.containsAnyIgnoreCase(endpoint, "http://")) { + sb.insert(7, properties.getBucketName() + "."); + } else if (StringUtils.containsAnyIgnoreCase(endpoint, "https://")) { + sb.insert(8, properties.getBucketName() + "."); + } else { + throw new OssException("Endpoint配置错误"); + } + return sb.toString(); + } +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QiniuOssStrategy.java b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QiniuOssStrategy.java new file mode 100644 index 00000000..e35ed240 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/java/com/ruoyi/common/oss/service/impl/QiniuOssStrategy.java @@ -0,0 +1,127 @@ +package com.ruoyi.common.oss.service.impl; + +import cn.hutool.core.util.ArrayUtil; +import com.qiniu.http.Response; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.Region; +import com.qiniu.storage.UploadManager; +import com.qiniu.util.Auth; +import com.ruoyi.common.oss.entity.UploadResult; +import com.ruoyi.common.oss.enumd.OssEnumd; +import com.ruoyi.common.oss.exception.OssException; +import com.ruoyi.common.oss.properties.OssProperties; +import com.ruoyi.common.oss.service.abstractd.AbstractOssStrategy; +import org.springframework.stereotype.Component; + +import java.io.InputStream; + +/** + * 七牛云存储策略 + * + * @author Lion Li + */ +@Component +public class QiniuOssStrategy extends AbstractOssStrategy { + + private UploadManager uploadManager; + private BucketManager bucketManager; + private Auth auth; + + + @Override + public void init(OssProperties ossProperties) { + super.init(ossProperties); + try { + Configuration config = new Configuration(getRegion(properties.getRegion())); + // https设置 + config.useHttpsDomains = false; + config.useHttpsDomains = "Y".equals(properties.getIsHttps()); + uploadManager = new UploadManager(config); + auth = Auth.create(properties.getAccessKey(), properties.getSecretKey()); + bucketManager = new BucketManager(auth, config); + createBucket(); + } catch (Exception e) { + throw new OssException("七牛云存储配置错误! 请检查系统配置:[" + e.getMessage() + "]"); + } + isInit = true; + } + + @Override + public void createBucket() { + try { + String bucketName = properties.getBucketName(); + if (ArrayUtil.contains(bucketManager.buckets(), bucketName)) { + return; + } + bucketManager.createBucket(bucketName, properties.getRegion()); + } catch (Exception e) { + throw new OssException("创建Bucket失败, 请核对七牛云配置信息:[" + e.getMessage() + "]"); + } + } + + @Override + public OssEnumd getServiceType() { + return OssEnumd.QINIU; + } + + @Override + public UploadResult upload(byte[] data, String path, String contentType) { + try { + String token = auth.uploadToken(properties.getBucketName()); + Response res = uploadManager.put(data, path, token, null, contentType, false); + if (!res.isOK()) { + throw new RuntimeException("上传七牛出错:" + res.error); + } + } catch (Exception e) { + throw new OssException("上传文件失败,请核对七牛配置信息:[" + e.getMessage() + "]"); + } + return UploadResult.builder().url(getEndpointLink() + "/" + path).filename(path).build(); + } + + @Override + public void delete(String path) { + try { + path = path.replace(getEndpointLink() + "/", ""); + Response res = bucketManager.delete(properties.getBucketName(), path); + if (!res.isOK()) { + throw new RuntimeException("删除七牛文件出错:" + res.error); + } + } catch (Exception e) { + throw new OssException(e.getMessage()); + } + } + + @Override + public UploadResult uploadSuffix(byte[] data, String suffix, String contentType) { + return upload(data, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType) { + return upload(inputStream, getPath(properties.getPrefix(), suffix), contentType); + } + + @Override + public String getEndpointLink() { + return properties.getEndpoint(); + } + + private Region getRegion(String region) { + switch (region) { + case "z0": + return Region.region0(); + case "z1": + return Region.region1(); + case "z2": + return Region.region2(); + case "na0": + return Region.regionNa0(); + case "as0": + return Region.regionAs0(); + default: + return Region.autoRegion(); + } + } + +} diff --git a/ruoyi-common/ruoyi-common-oss/src/main/resources/META-INF/spring.factories b/ruoyi-common/ruoyi-common-oss/src/main/resources/META-INF/spring.factories new file mode 100644 index 00000000..485802b1 --- /dev/null +++ b/ruoyi-common/ruoyi-common-oss/src/main/resources/META-INF/spring.factories @@ -0,0 +1 @@ +org.springframework.boot.autoconfigure.EnableAutoConfiguration= \ No newline at end of file