update 基于S3协议重新实现 OSS模块 支持自定义域名

dev
疯狂的狮子li 4 years ago
parent 6d9a89a65f
commit 3430b090e6

@ -23,34 +23,8 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.qiniu</groupId> <groupId>com.amazonaws</groupId>
<artifactId>qiniu-java-sdk</artifactId> <artifactId>aws-java-sdk-s3</artifactId>
<version>${qiniu.version}</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>${aliyun.oss.version}</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>${qcloud.cos.version}</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>${minio.version}</version>
</dependency> </dependency>
</dependencies> </dependencies>

@ -8,31 +8,41 @@ import java.util.List;
* *
* @author Lion Li * @author Lion Li
*/ */
public class OssConstant { public interface OssConstant {
/** /**
* OSSKEY * OSSKEY
*/ */
public static final String SYS_OSS_KEY = "sys_oss:"; String SYS_OSS_KEY = "sys_oss:";
/** /**
* KEY * KEY
*/ */
public static final String OSS_CONFIG_KEY = "OssConfig"; String OSS_CONFIG_KEY = "OssConfig";
/** /**
* KEY * KEY
*/ */
public static final String CACHE_CONFIG_KEY = SYS_OSS_KEY + OSS_CONFIG_KEY; String CACHE_CONFIG_KEY = SYS_OSS_KEY + OSS_CONFIG_KEY;
/** /**
* Key * Key
*/ */
public static final String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource"; String PEREVIEW_LIST_RESOURCE_KEY = "sys.oss.previewListResource";
/** /**
* ids * ids
*/ */
public static final List<Integer> SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4); List<Integer> SYSTEM_DATA_IDS = Arrays.asList(1, 2, 3, 4);
/**
*
*/
String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu"};
/**
* https
*/
String IS_HTTPS = "Y";
} }

@ -1,52 +0,0 @@
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;
}
}

@ -1,19 +1,3 @@
/*
* 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; package com.ruoyi.common.oss.enumd;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

@ -1,17 +1,17 @@
package com.ruoyi.common.oss.factory; package com.ruoyi.common.oss.factory;
import com.ruoyi.common.core.utils.JsonUtils; 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.core.utils.StringUtils;
import com.ruoyi.common.oss.constant.OssConstant; import com.ruoyi.common.oss.constant.OssConstant;
import com.ruoyi.common.oss.enumd.OssEnumd; import com.ruoyi.common.oss.core.OssClient;
import com.ruoyi.common.oss.exception.OssException; import com.ruoyi.common.oss.exception.OssException;
import com.ruoyi.common.oss.properties.OssProperties; 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 com.ruoyi.common.redis.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/** /**
* Factory * Factory
* *
@ -20,17 +20,19 @@ import lombok.extern.slf4j.Slf4j;
@Slf4j @Slf4j
public class OssFactory { public class OssFactory {
private static final Map<String, OssClient> CLIENT_CACHE = new ConcurrentHashMap<>();
/** /**
* *
*/ */
public static void init() { public static void init() {
log.info("初始化OSS工厂"); log.info("初始化OSS工厂");
RedisUtils.subscribe(OssConstant.CACHE_CONFIG_KEY, String.class, type -> { RedisUtils.subscribe(OssConstant.CACHE_CONFIG_KEY, String.class, configKey -> {
AbstractOssStrategy strategy = getStrategy(type); OssClient client = getClient(configKey);
// 未初始化不处理 // 未初始化不处理
if (strategy.isInit) { if (client != null) {
refresh(type); refresh(configKey);
log.info("订阅刷新OSS配置 => " + type); log.info("订阅刷新OSS配置 => " + configKey);
} }
}); });
} }
@ -38,42 +40,38 @@ public class OssFactory {
/** /**
* *
*/ */
public static IOssStrategy instance() { public static OssClient instance() {
// 获取redis 默认类型 // 获取redis 默认类型
String type = RedisUtils.getCacheObject(OssConstant.CACHE_CONFIG_KEY); String configKey = RedisUtils.getCacheObject(OssConstant.CACHE_CONFIG_KEY);
if (StringUtils.isEmpty(type)) { if (StringUtils.isEmpty(configKey)) {
throw new OssException("文件存储服务类型无法找到!"); throw new OssException("文件存储服务类型无法找到!");
} }
return instance(type); return instance(configKey);
} }
/** /**
* *
*/ */
public static IOssStrategy instance(String type) { public static OssClient instance(String configKey) {
OssEnumd enumd = OssEnumd.find(type); OssClient client = getClient(configKey);
if (enumd == null) { if (client == null) {
throw new OssException("文件存储服务类型无法找到!"); refresh(configKey);
return getClient(configKey);
} }
AbstractOssStrategy strategy = getStrategy(type); return client;
if (!strategy.isInit) {
refresh(type);
}
return strategy;
} }
private static void refresh(String type) { private static void refresh(String configKey) {
Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + type); Object json = RedisUtils.getCacheObject(OssConstant.SYS_OSS_KEY + configKey);
OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class); OssProperties properties = JsonUtils.parseObject(json.toString(), OssProperties.class);
if (properties == null) { if (properties == null) {
throw new OssException("系统异常, '" + type + "'配置信息不存在!"); throw new OssException("系统异常, '" + configKey + "'配置信息不存在!");
} }
getStrategy(type).init(properties); CLIENT_CACHE.put(configKey, new OssClient(configKey, properties));
} }
private static AbstractOssStrategy getStrategy(String type) { private static OssClient getClient(String configKey) {
OssEnumd enumd = OssEnumd.find(type); return CLIENT_CACHE.get(configKey);
return (AbstractOssStrategy) SpringUtils.getBean(enumd.getBeanClass());
} }
} }

@ -15,6 +15,11 @@ public class OssProperties {
*/ */
private String endpoint; private String endpoint;
/**
*
*/
private String domain;
/** /**
* *
*/ */

@ -1,74 +0,0 @@
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
* @param contentType
* @return http
*/
UploadResult upload(byte[] data, String path, String contentType);
/**
*
*
* @param path
*/
void delete(String path);
/**
*
*
* @param data
* @param suffix
* @param contentType
* @return http
*/
UploadResult uploadSuffix(byte[] data, String suffix, String contentType);
/**
*
*
* @param inputStream
* @param path
* @param contentType
* @return http
*/
UploadResult upload(InputStream inputStream, String path, String contentType);
/**
*
*
* @param inputStream
* @param suffix
* @param contentType
* @return http
*/
UploadResult uploadSuffix(InputStream inputStream, String suffix, String contentType);
}

@ -1,69 +0,0 @@
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);
/**
* 访
*
* @return 访
*/
public abstract String getEndpointLink();
}

@ -1,115 +0,0 @@
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();
}
}

@ -1,186 +0,0 @@
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 {
// 解决 inputStream.available() 在 socket 下传输延迟问题 导致获取数值不精确
Thread.sleep(1000);
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();
}
}

@ -1,124 +0,0 @@
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();
}
}

@ -1,127 +0,0 @@
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();
}
}
}

@ -1,5 +1 @@
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.ruoyi.common.oss.service.impl.AliyunOssStrategy,\
com.ruoyi.common.oss.service.impl.MinioOssStrategy,\
com.ruoyi.common.oss.service.impl.QcloudOssStrategy,\
com.ruoyi.common.oss.service.impl.QiniuOssStrategy

@ -52,6 +52,12 @@ public class SysOssConfig extends BaseEntity {
*/ */
private String endpoint; private String endpoint;
/**
*
*/
private String domain;
/** /**
* https0 1 * https0 1
*/ */

@ -35,8 +35,8 @@ public class SysOssConfigBo extends BaseEntity {
/** /**
* key * key
*/ */
@ApiModelProperty(value = "configKey", required = true) @ApiModelProperty(value = "配置key", required = true)
@NotBlank(message = "configKey不能为空", groups = {AddGroup.class, EditGroup.class}) @NotBlank(message = "配置key不能为空", groups = {AddGroup.class, EditGroup.class})
@Size(min = 2, max = 100, message = "configKey长度必须介于2和20 之间") @Size(min = 2, max = 100, message = "configKey长度必须介于2和20 之间")
private String configKey; private String configKey;
@ -59,8 +59,8 @@ public class SysOssConfigBo extends BaseEntity {
/** /**
* *
*/ */
@ApiModelProperty(value = "bucketName", required = true) @ApiModelProperty(value = "桶名称", required = true)
@NotBlank(message = "bucketName不能为空", groups = {AddGroup.class, EditGroup.class}) @NotBlank(message = "桶名称不能为空", groups = {AddGroup.class, EditGroup.class})
@Size(min = 2, max = 100, message = "bucketName长度必须介于2和100之间") @Size(min = 2, max = 100, message = "bucketName长度必须介于2和100之间")
private String bucketName; private String bucketName;
@ -73,11 +73,17 @@ public class SysOssConfigBo extends BaseEntity {
/** /**
* 访 * 访
*/ */
@ApiModelProperty(value = "endpoint", required = true) @ApiModelProperty(value = "访问站点", required = true)
@NotBlank(message = "endpoint不能为空", groups = {AddGroup.class, EditGroup.class}) @NotBlank(message = "访问站点不能为空", groups = {AddGroup.class, EditGroup.class})
@Size(min = 2, max = 100, message = "endpoint长度必须介于2和100之间") @Size(min = 2, max = 100, message = "endpoint长度必须介于2和100之间")
private String endpoint; private String endpoint;
/**
*
*/
@ApiModelProperty("自定义域名")
private String domain;
/** /**
* httpsY=,N= * httpsY=,N=
*/ */
@ -93,7 +99,7 @@ public class SysOssConfigBo extends BaseEntity {
/** /**
* *
*/ */
@ApiModelProperty(value = "region") @ApiModelProperty(value = "")
private String region; private String region;
/** /**

@ -60,6 +60,12 @@ public class SysOssConfigVo {
@ApiModelProperty("访问站点") @ApiModelProperty("访问站点")
private String endpoint; private String endpoint;
/**
*
*/
@ApiModelProperty("自定义域名")
private String domain;
/** /**
* httpsY=,N= * httpsY=,N=
*/ */

@ -2,9 +2,9 @@ package com.ruoyi.resource.dubbo;
import com.ruoyi.common.core.exception.ServiceException; import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.oss.core.OssClient;
import com.ruoyi.common.oss.entity.UploadResult; import com.ruoyi.common.oss.entity.UploadResult;
import com.ruoyi.common.oss.factory.OssFactory; import com.ruoyi.common.oss.factory.OssFactory;
import com.ruoyi.common.oss.service.IOssStrategy;
import com.ruoyi.resource.api.RemoteFileService; import com.ruoyi.resource.api.RemoteFileService;
import com.ruoyi.resource.api.domain.SysFile; import com.ruoyi.resource.api.domain.SysFile;
import com.ruoyi.resource.domain.SysOss; import com.ruoyi.resource.domain.SysOss;
@ -36,7 +36,7 @@ public class RemoteFileServiceImpl implements RemoteFileService {
public SysFile upload(String name, String originalFilename, String contentType, byte[] file) throws ServiceException { public SysFile upload(String name, String originalFilename, String contentType, byte[] file) throws ServiceException {
try { try {
String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length()); String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length());
IOssStrategy storage = OssFactory.instance(); OssClient storage = OssFactory.instance();
UploadResult uploadResult = storage.uploadSuffix(file, suffix, contentType); UploadResult uploadResult = storage.uploadSuffix(file, suffix, contentType);
// 保存文件信息 // 保存文件信息
SysOss oss = new SysOss(); SysOss oss = new SysOss();
@ -44,7 +44,7 @@ public class RemoteFileServiceImpl implements RemoteFileService {
oss.setFileSuffix(suffix); oss.setFileSuffix(suffix);
oss.setFileName(uploadResult.getFilename()); oss.setFileName(uploadResult.getFilename());
oss.setOriginalName(originalFilename); oss.setOriginalName(originalFilename);
oss.setService(storage.getServiceType().getValue()); oss.setService(storage.getConfigKey());
sysOssMapper.insert(oss); sysOssMapper.insert(oss);
SysFile sysFile = new SysFile(); SysFile sysFile = new SysFile();
sysFile.setName(uploadResult.getFilename()); sysFile.setName(uploadResult.getFilename());

@ -7,9 +7,9 @@ import com.ruoyi.common.core.exception.ServiceException;
import com.ruoyi.common.core.utils.StringUtils; import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.mybatis.core.page.PageQuery; import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.ruoyi.common.mybatis.core.page.TableDataInfo; import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import com.ruoyi.common.oss.core.OssClient;
import com.ruoyi.common.oss.entity.UploadResult; import com.ruoyi.common.oss.entity.UploadResult;
import com.ruoyi.common.oss.factory.OssFactory; import com.ruoyi.common.oss.factory.OssFactory;
import com.ruoyi.common.oss.service.IOssStrategy;
import com.ruoyi.resource.domain.SysOss; import com.ruoyi.resource.domain.SysOss;
import com.ruoyi.resource.domain.bo.SysOssBo; import com.ruoyi.resource.domain.bo.SysOssBo;
import com.ruoyi.resource.domain.vo.SysOssVo; import com.ruoyi.resource.domain.vo.SysOssVo;
@ -65,7 +65,7 @@ public class SysOssServiceImpl implements ISysOssService {
public SysOss upload(MultipartFile file) { public SysOss upload(MultipartFile file) {
String originalfileName = file.getOriginalFilename(); String originalfileName = file.getOriginalFilename();
String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length()); String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
IOssStrategy storage = OssFactory.instance(); OssClient storage = OssFactory.instance();
UploadResult uploadResult; UploadResult uploadResult;
try { try {
uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType()); uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
@ -78,7 +78,7 @@ public class SysOssServiceImpl implements ISysOssService {
oss.setFileSuffix(suffix); oss.setFileSuffix(suffix);
oss.setFileName(uploadResult.getFilename()); oss.setFileName(uploadResult.getFilename());
oss.setOriginalName(originalfileName); oss.setOriginalName(originalfileName);
oss.setService(storage.getServiceType().getValue()); oss.setService(storage.getConfigKey());
baseMapper.insert(oss); baseMapper.insert(oss);
return oss; return oss;
} }
@ -90,7 +90,7 @@ public class SysOssServiceImpl implements ISysOssService {
} }
List<SysOss> list = baseMapper.selectBatchIds(ids); List<SysOss> list = baseMapper.selectBatchIds(ids);
for (SysOss sysOss : list) { for (SysOss sysOss : list) {
IOssStrategy storage = OssFactory.instance(sysOss.getService()); OssClient storage = OssFactory.instance(sysOss.getService());
storage.delete(sysOss.getUrl()); storage.delete(sysOss.getUrl());
} }
return baseMapper.deleteBatchIds(ids) > 0; return baseMapper.deleteBatchIds(ids) > 0;

@ -2,14 +2,13 @@
<div class="app-container"> <div class="app-container">
<el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px"> <el-form :model="queryParams" ref="queryForm" :inline="true" v-show="showSearch" label-width="68px">
<el-form-item label="配置key" prop="configKey"> <el-form-item label="配置key" prop="configKey">
<el-select v-model="queryParams.configKey" placeholder="请选择配置key" clearable size="small"> <el-input
<el-option v-model="queryParams.configKey"
v-for="configKey in configKeyOptions" placeholder="配置key"
:key="configKey.configKey" clearable
:label="configKey.label" size="small"
:value="configKey.configKey" @keyup.enter.native="handleQuery"
/> />
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="桶名称" prop="bucketName"> <el-form-item label="桶名称" prop="bucketName">
<el-input <el-input
@ -77,6 +76,7 @@
<el-table-column label="主建" align="center" prop="ossConfigId" v-if="false"/> <el-table-column label="主建" align="center" prop="ossConfigId" v-if="false"/>
<el-table-column label="配置key" align="center" prop="configKey" /> <el-table-column label="配置key" align="center" prop="configKey" />
<el-table-column label="访问站点" align="center" prop="endpoint" width="200" /> <el-table-column label="访问站点" align="center" prop="endpoint" width="200" />
<el-table-column label="自定义域名" align="center" prop="domain" width="200" />
<el-table-column label="桶名称" align="center" prop="bucketName" /> <el-table-column label="桶名称" align="center" prop="bucketName" />
<el-table-column label="前缀" align="center" prop="prefix" /> <el-table-column label="前缀" align="center" prop="prefix" />
<el-table-column label="域" align="center" prop="region" /> <el-table-column label="域" align="center" prop="region" />
@ -122,18 +122,14 @@
<el-dialog :title="title" :visible.sync="open" width="800px" append-to-body> <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
<el-form ref="form" :model="form" :rules="rules" label-width="120px"> <el-form ref="form" :model="form" :rules="rules" label-width="120px">
<el-form-item label="配置key" prop="configKey"> <el-form-item label="配置key" prop="configKey">
<el-select v-model="form.configKey" placeholder="请选择配置key"> <el-input v-model="form.configKey" placeholder="请输入配置key" />
<el-option
v-for="configKey in configKeyOptions"
:key="configKey.configKey"
:label="configKey.label"
:value="configKey.configKey"
/>
</el-select>
</el-form-item> </el-form-item>
<el-form-item label="访问站点" prop="endpoint"> <el-form-item label="访问站点" prop="endpoint">
<el-input v-model="form.endpoint" placeholder="请输入访问站点" /> <el-input v-model="form.endpoint" placeholder="请输入访问站点" />
</el-form-item> </el-form-item>
<el-form-item label="自定义域名" prop="domain">
<el-input v-model="form.domain" placeholder="请输入自定义域名" />
</el-form-item>
<el-form-item label="accessKey" prop="accessKey"> <el-form-item label="accessKey" prop="accessKey">
<el-input v-model="form.accessKey" placeholder="请输入accessKey" /> <el-input v-model="form.accessKey" placeholder="请输入accessKey" />
</el-form-item> </el-form-item>
@ -204,14 +200,6 @@ export default {
total: 0, total: 0,
// //
ossConfigList: [], ossConfigList: [],
// configKeyOptions
configKeyOptions: [],
configKeyDatas: [
{ configKey: "minio", label: "Minio" },
{ configKey: "qiniu", label: "七牛云" },
{ configKey: "aliyun", label: "阿里云" },
{ configKey: "qcloud", label: "腾讯云" },
],
// //
title: "", title: "",
// //
@ -276,7 +264,6 @@ export default {
}, },
created() { created() {
this.getList(); this.getList();
this.configKeyOptions = this.configKeyDatas;
}, },
methods: { methods: {
/** 查询对象存储配置列表 */ /** 查询对象存储配置列表 */
@ -303,6 +290,7 @@ export default {
bucketName: undefined, bucketName: undefined,
prefix: undefined, prefix: undefined,
endpoint: undefined, endpoint: undefined,
domain: undefined,
isHttps: "N", isHttps: "N",
region: undefined, region: undefined,
status: "1", status: "1",

@ -612,6 +612,7 @@ create table sys_oss_config (
bucket_name varchar(255) default '' comment '桶名称', bucket_name varchar(255) default '' comment '桶名称',
prefix varchar(255) default '' comment '前缀', prefix varchar(255) default '' comment '前缀',
endpoint varchar(255) default '' comment '访问站点', endpoint varchar(255) default '' comment '访问站点',
domain varchar(255) default '' comment '自定义域名',
is_https char(1) default 'N' comment '是否httpsY=是,N=否)', is_https char(1) default 'N' comment '是否httpsY=是,N=否)',
region varchar(255) default '' comment '', region varchar(255) default '' comment '',
status char(1) default '1' comment '状态0=正常,1=停用)', status char(1) default '1' comment '状态0=正常,1=停用)',
@ -624,10 +625,11 @@ create table sys_oss_config (
primary key (oss_config_id) primary key (oss_config_id)
) engine=innodb comment='对象存储配置表'; ) engine=innodb comment='对象存储配置表';
insert into sys_oss_config values (1, 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', 'http://localhost:9000', 'N', '', '0', '', 'admin', sysdate(), 'admin', sysdate(), NULL); insert into sys_oss_config values (1, 'minio', 'ruoyi', 'ruoyi123', 'ruoyi', '', 'localhost:9000', '','N', '', '0', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
insert into sys_oss_config values (2, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'http://XXX.XXXX.com', 'N', 'z0', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); insert into sys_oss_config values (2, 'qiniu', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 's3-cn-north-1.qiniucs.com', '','N', '', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
insert into sys_oss_config values (3, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'http://oss-cn-beijing.aliyuncs.com', 'N', '', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); insert into sys_oss_config values (3, 'aliyun', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi', '', 'oss-cn-beijing.aliyuncs.com', '','N', '', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
insert into sys_oss_config values (4, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'http://cos.ap-beijing.myqcloud.com', 'N', 'ap-beijing', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL); insert into sys_oss_config values (4, 'qcloud', 'XXXXXXXXXXXXXXX', 'XXXXXXXXXXXXXXX', 'ruoyi-1250000000', '', 'cos.ap-beijing.myqcloud.com', '','N', 'ap-beijing', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
insert into sys_oss_config values (5, 'image', 'ruoyi', 'ruoyi123', 'ruoyi', 'image', 'localhost:9000', '','N', '', '1', '', 'admin', sysdate(), 'admin', sysdate(), NULL);
-- ---------------------------- -- ----------------------------
-- 18、代码生成业务表 -- 18、代码生成业务表

Loading…
Cancel
Save