修复配置文件中的拼写错误,更新MinIO和阿里云OSS相关异常类,添加生成预签名URL的方法

This commit is contained in:
Dftre 2025-02-23 14:52:41 +08:00
parent ff16be4064
commit ca36af0868
14 changed files with 402 additions and 106 deletions

View File

@ -42,9 +42,9 @@ minio:
url: http://localhost:9000 url: http://localhost:9000
accessKey: accessKey:
secretKey: secretKey:
buketName: ruoyi bucketName: ruoyi
# SLAVE: # SLAVE:
# url: http://127.0.0.1:9000 # url: http://127.0.0.1:9000
# accessKey: # accessKey:
# secretKey: # secretKey:
# buketName: ry # bucketName: ry

View File

@ -6,6 +6,7 @@ import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.Objects; import java.util.Objects;
@ -16,17 +17,22 @@ import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.constant.Constants; import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.FileEntity; import com.ruoyi.common.core.domain.entity.FileEntity;
import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException; import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileOperateUtils; import com.ruoyi.common.utils.file.FileOperateUtils;
import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.common.utils.sign.Md5Utils; import com.ruoyi.common.utils.sign.Md5Utils;
import jakarta.servlet.http.HttpServletRequest;
/** /**
* 磁盘文件操作实现类 * 磁盘文件操作实现类
*/ */
@Component("file:strategy:disk") @Component("file:strategy:disk")
public class DiskFileService implements FileService { public class DiskFileService implements FileService {
private static final long URL_EXPIRATION = 3600 * 1000; // URL有效期1小时
@Override @Override
public String upload(String filePath, MultipartFile file) throws Exception { public String upload(String filePath, MultipartFile file) throws Exception {
return upload(RuoYiConfig.getProfile(), filePath, file); return upload(RuoYiConfig.getProfile(), filePath, file);
@ -46,15 +52,24 @@ public class DiskFileService implements FileService {
@Override @Override
public InputStream downLoad(String filePath) throws Exception { public InputStream downLoad(String filePath) throws Exception {
// 本地资源路径 // 标准化路径
String normalizedPath = normalizeFilePath(filePath);
// 获取本地存储根路径
String localPath = RuoYiConfig.getProfile(); String localPath = RuoYiConfig.getProfile();
// 数据库资源地址
String downloadPath = localPath + StringUtils.substringAfter(filePath, Constants.RESOURCE_PREFIX); // 拼接完整路径确保分隔符正确
// 下载名称 String fullPath = localPath + File.separator + normalizedPath;
File file = new File(downloadPath);
// 创建文件对象并检查
File file = new File(fullPath);
if (!file.exists()) { if (!file.exists()) {
throw new FileNotFoundException("未找到文件"); throw new FileNotFoundException("文件不存在: " + fullPath);
} }
if (!file.isFile()) {
throw new FileNotFoundException("不是有效的文件: " + fullPath);
}
return new FileInputStream(file); return new FileInputStream(file);
} }
@ -88,5 +103,61 @@ public class DiskFileService implements FileService {
fileEntity.setFileInputSteam(fileInputStream); fileEntity.setFileInputSteam(fileInputStream);
fileEntity.setByteCount(file.length()); fileEntity.setByteCount(file.length());
return fileEntity; return fileEntity;
}; }
@Override
public URL generatePresignedUrl(String filePath) throws Exception {
try {
// 生成临时访问凭证
String normalizedPath = normalizeFilePath(filePath);
long expireTime = System.currentTimeMillis() + URL_EXPIRATION;
String toHex = Md5Utils.hash(normalizedPath + expireTime);
// 构建访问URL
String urlString = getUrl() +
"/common/download/resource?resource=" +
normalizedPath +
"&toHex=" + toHex +
"&expires=" + expireTime;
return new URL(urlString);
} catch (Exception e) {
throw new RuntimeException("生成访问URL失败: " + e.getMessage(), e);
}
}
/**
* 标准化文件路径
*/
private String normalizeFilePath(String filePath) {
if (StringUtils.isEmpty(filePath)) {
return "";
}
// 统一使用正斜杠并去除前缀
String normalizedPath = filePath.replace('\\', '/')
.replace("ruoyi/uploadPath/", "")
.replace("/profile/", "");
// 去除开头和结尾的斜杠
normalizedPath = StringUtils.strip(normalizedPath, "/");
// 处理文件存储重复的斜杠
normalizedPath = normalizedPath.replaceAll("/+", "/");
return normalizedPath;
}
/**
* 获取完整的请求路径包括域名端口上下文访问路径
*
* @return 服务地址
*/
public String getUrl()
{
HttpServletRequest request = ServletUtils.getRequest();
return getDomain(request);
}
public static String getDomain(HttpServletRequest request)
{
StringBuffer url = request.getRequestURL();
String contextPath = request.getSession().getServletContext().getContextPath();
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
}
} }

View File

@ -2,6 +2,7 @@ package com.ruoyi.common.service.file;
import java.io.File; import java.io.File;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
@ -90,4 +91,13 @@ public interface FileService {
* @throws Exception * @throws Exception
*/ */
public FileEntity getFile(String filePath) throws Exception; public FileEntity getFile(String filePath) throws Exception;
/**
* 生成预签名URL
*
* @param filePath 文件路径
* @return 预签名URL
* @throws Exception 如果生成过程中出现错误
*/
public URL generatePresignedUrl(String filePath) throws Exception;
} }

View File

@ -6,7 +6,7 @@ public class MinioClientProperties {
private String url; private String url;
private String accessKey; private String accessKey;
private String secretKey; private String secretKey;
private String buketName; private String bucketName;
private MinioClient client; private MinioClient client;
@ -34,14 +34,6 @@ public class MinioClientProperties {
this.secretKey = secretKey; this.secretKey = secretKey;
} }
public String getBuketName() {
return buketName;
}
public void setBuketName(String buketName) {
this.buketName = buketName;
}
public MinioClient getClient() { public MinioClient getClient() {
return client; return client;
} }
@ -50,13 +42,21 @@ public class MinioClientProperties {
this.client = client; this.client = client;
} }
public MinioClientProperties(String url, String accessKey, String secretKey, String buketName) { public MinioClientProperties(String url, String accessKey, String secretKey, String bucketName) {
this.url = url; this.url = url;
this.accessKey = accessKey; this.accessKey = accessKey;
this.secretKey = secretKey; this.secretKey = secretKey;
this.buketName = buketName; this.bucketName = bucketName;
} }
public MinioClientProperties() { public MinioClientProperties() {
} }
public String getBucketName() {
return bucketName;
}
public void setBucketName(String bucketName) {
this.bucketName = bucketName;
}
} }

View File

@ -15,6 +15,8 @@ import com.ruoyi.common.config.RuoYiConfig;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.middleware.minio.domain.MinioBucket; import com.ruoyi.middleware.minio.domain.MinioBucket;
import com.ruoyi.middleware.minio.exception.MinioClientErrorException;
import com.ruoyi.middleware.minio.exception.MinioClientNotFundException;
import io.minio.BucketExistsArgs; import io.minio.BucketExistsArgs;
import io.minio.MinioClient; import io.minio.MinioClient;
@ -34,7 +36,17 @@ public class MinioConfig implements InitializingBean {
@Override @Override
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
client.forEach((name, props) -> targetMinioBucket.put(name, createMinioClient(name, props))); if (client == null || client.isEmpty()) {
throw new RuntimeException("Client properties cannot be null or empty");
}
client.forEach((name, props) -> {
try {
targetMinioBucket.put(name, createMinioClient(name, props));
} catch (Exception e) {
logger.error("Failed to create MinIO client for {}: {}", name, e.getMessage(), e);
}
});
if (targetMinioBucket.get(primary) == null) { if (targetMinioBucket.get(primary) == null) {
throw new RuntimeException("Primary client " + primary + " does not exist"); throw new RuntimeException("Primary client " + primary + " does not exist");
} }
@ -71,12 +83,34 @@ public class MinioConfig implements InitializingBean {
.credentials(props.getAccessKey(), props.getSecretKey()) .credentials(props.getAccessKey(), props.getSecretKey())
.build(); .build();
} }
MinioBucket minioBucket = new MinioBucket(client, props.getBuketName()); MinioBucket minioBucket = new MinioBucket(client, props.getBucketName());
validateMinioBucket(minioBucket); validateMinioBucket(minioBucket);
logger.info("数据桶:{} - 链接成功", name); logger.info("数据桶:{} - 链接成功", name);
return minioBucket; return minioBucket;
} }
/**
* 根据主配置信息创建并返回MinIO客户端实例
*
* @return MinioClient 实例
* @throws MinioClientNotFundException 如果找不到对应的配置时抛出
* @throws MinioClientErrorException 如果在创建过程中发生错误时抛出
*/
public MinioClient getPrimaryMinioClient() throws MinioClientNotFundException, MinioClientErrorException {
MinioClientProperties primaryClientProps = this.getClient().get(this.getPrimary());
if (primaryClientProps == null) {
throw new MinioClientNotFundException("未找到该Minio对象存储服务");
}
try {
return MinioClient.builder()
.endpoint(primaryClientProps.getUrl())
.credentials(primaryClientProps.getAccessKey(), primaryClientProps.getSecretKey())
.build();
} catch (Exception e) {
throw new MinioClientErrorException("创建MinIO客户端失败: " + e.getMessage(), e);
}
}
public int getMaxSize() { public int getMaxSize() {
return maxSize; return maxSize;
} }

View File

@ -89,7 +89,7 @@ public class MinioBucket {
MinioFileVO minioFileVO = new MinioFileVO(); MinioFileVO minioFileVO = new MinioFileVO();
minioFileVO.setFileInputSteam(inputStream); minioFileVO.setFileInputSteam(inputStream);
minioFileVO.setByteCount(Convert.toLong(inputStream.headers().get("Content-Length"),null)); minioFileVO.setByteCount(Convert.toLong(inputStream.headers().get("Content-Length"), null));
minioFileVO.setFilePath(filePath); minioFileVO.setFilePath(filePath);
minioFileVO.setObject(inputStream.object()); minioFileVO.setObject(inputStream.object());
minioFileVO.setRegion(inputStream.region()); minioFileVO.setRegion(inputStream.region());

View File

@ -1,7 +1,16 @@
package com.ruoyi.middleware.minio.exception; package com.ruoyi.middleware.minio.exception;
public class MinioClientErrorException extends RuntimeException{ /**
public MinioClientErrorException(String msg){ * 当与MinIO客户端交互过程中发生错误时抛出此异常
*/
public class MinioClientErrorException extends RuntimeException {
public MinioClientErrorException(String msg) {
super(msg); super(msg);
} }
public MinioClientErrorException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -1,4 +1,15 @@
package com.ruoyi.middleware.minio.exception; package com.ruoyi.middleware.minio.exception;
public class MinioClientNotFundException extends RuntimeException{ /**
* 当尝试获取MinIO客户端实例但未能找到相应的配置或客户端实例时抛出此异常
*/
public class MinioClientNotFundException extends RuntimeException {
public MinioClientNotFundException(String msg) {
super(msg);
}
public MinioClientNotFundException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -1,7 +1,11 @@
package com.ruoyi.middleware.minio.service; package com.ruoyi.middleware.minio.service;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
@ -13,14 +17,21 @@ import com.ruoyi.common.utils.file.FileOperateUtils;
import com.ruoyi.common.utils.file.FileUtils; import com.ruoyi.common.utils.file.FileUtils;
import com.ruoyi.middleware.minio.config.MinioConfig; import com.ruoyi.middleware.minio.config.MinioConfig;
import com.ruoyi.middleware.minio.domain.MinioFileVO; import com.ruoyi.middleware.minio.domain.MinioFileVO;
import com.ruoyi.middleware.minio.exception.MinioClientErrorException;
import com.ruoyi.middleware.minio.exception.MinioClientNotFundException;
import com.ruoyi.middleware.minio.utils.MinioUtil; import com.ruoyi.middleware.minio.utils.MinioUtil;
import io.minio.GetPresignedObjectUrlArgs;
import io.minio.MinioClient;
import io.minio.http.Method;
/** /**
* Minio文件操作实现类 * Minio文件操作实现类
*/ */
@Component("file:strategy:minio") @Component("file:strategy:minio")
@ConditionalOnProperty(prefix = "minio", name = { "enable" }, havingValue = "true", matchIfMissing = false) @ConditionalOnProperty(prefix = "minio", name = { "enable" }, havingValue = "true", matchIfMissing = false)
public class MinioFileService implements FileService { public class MinioFileService implements FileService {
private static final Logger logger = LoggerFactory.getLogger(MinioFileService.class);
@Autowired @Autowired
private MinioConfig minioConfig; private MinioConfig minioConfig;
@ -57,5 +68,35 @@ public class MinioFileService implements FileService {
@Override @Override
public FileEntity getFile(String filePath) throws Exception { public FileEntity getFile(String filePath) throws Exception {
return MinioUtil.getFile(minioConfig.getPrimary(), filePath); return MinioUtil.getFile(minioConfig.getPrimary(), filePath);
}; }
/**
* 生成预签名Minio URL.
*
* @param filePath 文件路径
* @return 预签名URL
* @throws MinioClientNotFundException 如果找不到对应的配置时抛出
* @throws MinioClientErrorException 如果在创建或获取预签名URL过程中发生错误时抛出
*/
@Override
public URL generatePresignedUrl(String filePath) throws MinioClientNotFundException, MinioClientErrorException {
MinioClient minioClient = null; // 创建并且实例化
try {
minioClient = minioConfig.getPrimaryMinioClient(); // 调用封装好的MinioConfig中的方法获取Minio客户端
String bucketName = minioConfig.getClient().get(minioConfig.getPrimary()).getBucketName();
GetPresignedObjectUrlArgs request = GetPresignedObjectUrlArgs.builder()
.method(Method.GET)
.bucket(bucketName)
.object(filePath)
.expiry(1, TimeUnit.HOURS) // 设置过期时间为1小时
.build();
// 生成预签名URL
String presignedUrl = minioClient.getPresignedObjectUrl(request);
URL url = new URL(presignedUrl); // 将字符串形式的预签名URL转换为URL对象并返回
return url;
} catch (Exception e) {
logger.error("生成Minio预签名URL失败: {}", e.getMessage(), e); // 添加日志记录
throw new MinioClientErrorException("生成Minio预签名URL失败: " + e.getMessage(), e);
}
}
} }

View File

@ -15,18 +15,146 @@ import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder; import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException; import com.aliyun.oss.OSSException;
import com.ruoyi.alibaba.oss.domain.AliOssBucket; import com.ruoyi.alibaba.oss.domain.AliOssBucket;
import com.ruoyi.alibaba.oss.exception.AliOssClientErrorException;
import com.ruoyi.alibaba.oss.exception.AliOssClientNotFundException;
/**
* 配置类用于管理阿里云OSS客户端实例及其相关属性
*/
@Configuration("AliOssConfiguration") @Configuration("AliOssConfiguration")
@ConditionalOnProperty(prefix = "oss", name = "enable", havingValue = "true", matchIfMissing = false) @ConditionalOnProperty(prefix = "oss", name = "enable", havingValue = "true", matchIfMissing = false)
@ConfigurationProperties(prefix = "oss") @ConfigurationProperties(prefix = "oss")
public class AliOssConfig implements InitializingBean { public class AliOssConfig implements InitializingBean {
private static final Logger logger = LoggerFactory.getLogger(AliOssConfig.class); private static final Logger logger = LoggerFactory.getLogger(AliOssConfig.class);
public static int maxSize;
public static int maxSize; // 最大文件大小或其他配置项
private String prefix = "/oss"; // 根据需要调整前缀 private String prefix = "/oss"; // 根据需要调整前缀
private Map<String, AliOssProperties> client = new HashMap<>();
private String primary; private Map<String, AliOssProperties> client = new HashMap<>(); // 存储所有OSS客户端配置信息
private Map<String, AliOssBucket> targetAliOssBucket = new HashMap<>();
private AliOssBucket masterBucket; private String primary; // 主要使用的OSS客户端名称
private Map<String, AliOssBucket> targetAliOssBucket = new HashMap<>(); // 存储已创建的OSS客户端与桶名映射
private AliOssBucket masterBucket; // 主要使用的OSS客户端对应的桶对象
/**
* 初始化后检查客户端配置是否正确并创建相应的OSS客户端实例
*/
@Override
public void afterPropertiesSet() throws Exception {
if (client == null || client.isEmpty()) {
throw new RuntimeException("Client properties cannot be null or empty");
}
client.forEach((name, props) -> {
try {
AliOssBucket aliOssBucket = createOssClient(name, props);
targetAliOssBucket.put(name, aliOssBucket);
} catch (Exception e) {
logger.error("Failed to create OSS client for {}: {}", name, e.getMessage(), e);
}
});
if (targetAliOssBucket.get(primary) == null) {
throw new RuntimeException("Primary client " + primary + " does not exist");
}
masterBucket = targetAliOssBucket.get(primary);
}
/**
* 创建并返回一个指定名称的OSS客户端实例
*
* @param name 客户端名称
* @param props 客户端配置属性
* @return 包含OSS客户端和桶名的对象
*/
private AliOssBucket createOssClient(String name, AliOssProperties props) {
if (props == null || props.getEndpoint() == null || props.getAccessKeyId() == null ||
props.getAccessKeySecret() == null || props.getBucketName() == null) {
throw new IllegalArgumentException("AliOssProperties or its required fields cannot be null");
}
OSS client = new OSSClientBuilder().build(props.getEndpoint(), props.getAccessKeyId(),
props.getAccessKeySecret());
AliOssBucket ossBucket = new AliOssBucket(client, props.getBucketName());
validateOssBucket(ossBucket);
logger.info("数据桶:{} - 链接成功", name);
return ossBucket;
}
/**
* 验证给定的OSS桶是否存在
*
* @param aliOssBucket 包含OSS客户端和桶名的对象
*/
private static void validateOssBucket(AliOssBucket aliOssBucket) {
OSS ossClient = aliOssBucket.getOssClient();
String bucketName = aliOssBucket.getBucketName();
try {
if (!ossClient.doesBucketExist(bucketName)) {
throw new RuntimeException("Bucket " + bucketName + " does not exist");
}
} catch (OSSException oe) {
logger.error("OSSException: " + oe.getMessage(), oe);
throw new RuntimeException("OSS error: " + oe.getMessage());
} catch (ClientException ce) {
logger.error("ClientException: " + ce.getMessage(), ce);
throw new RuntimeException("Client error: " + ce.getMessage());
} catch (Exception e) {
logger.error("Exception: " + e.getMessage(), e);
throw new RuntimeException("Error validating OSS bucket: " + e.getMessage());
}
}
/**
* 获取主桶的名称
*
* @return 主桶的名称如果未设置则返回null
*/
public String getMasterBucketName() {
if (masterBucket != null) {
return masterBucket.getBucketName();
}
return null; // 或者抛出异常
}
/**
* 根据客户端名称获取对应的桶名
*
* @param client 客户端名称
* @return 对应的桶名如果未找到则返回null
*/
public String getBucketName(String client) {
if (client != null && targetAliOssBucket.containsKey(client)) {
return targetAliOssBucket.get(client).getBucketName();
}
return null; // 或者抛出异常
}
/**
* 根据主配置信息创建并返回OSS客户端实例
*
* @return OSS客户端实例
* @throws AliOssClientNotFundException 如果找不到对应配置时抛出
* @throws AliOssClientErrorException 如果在创建过程中发生错误时抛出
*/
public OSS getPrimaryOssClient() throws AliOssClientNotFundException, AliOssClientErrorException {
AliOssProperties primaryClientProps = this.getClient().get(this.getPrimary());
if (primaryClientProps == null) {
throw new AliOssClientNotFundException("未找到该Oss对象存储服务");
}
try {
return new OSSClientBuilder().build(
primaryClientProps.getEndpoint(),
primaryClientProps.getAccessKeyId(),
primaryClientProps.getAccessKeySecret());
} catch (Exception e) {
// 在尝试构建OSS客户端时发生任何异常抛出 AliOssClientErrorException
throw new AliOssClientErrorException("创建OSS客户端失败", e);
}
}
public int getMaxSize() { public int getMaxSize() {
return maxSize; return maxSize;
@ -63,73 +191,4 @@ public class AliOssConfig implements InitializingBean {
public void setPrefix(String prefix) { public void setPrefix(String prefix) {
this.prefix = prefix; this.prefix = prefix;
} }
@Override
public void afterPropertiesSet() throws Exception {
if (client == null || client.isEmpty()) {
throw new RuntimeException("Client properties cannot be null or empty");
}
client.forEach((name, props) -> {
try {
AliOssBucket aliOssBucket = createOssClient(name, props);
targetAliOssBucket.put(name, aliOssBucket);
} catch (Exception e) {
logger.error("Failed to create OSS client for {}: {}", name, e.getMessage(), e);
}
});
if (targetAliOssBucket.get(primary) == null) {
throw new RuntimeException("Primary client " + primary + " does not exist");
}
masterBucket = targetAliOssBucket.get(primary);
}
private AliOssBucket createOssClient(String name, AliOssProperties props) {
if (props == null || props.getEndpoint() == null || props.getAccessKeyId() == null ||
props.getAccessKeySecret() == null || props.getBucketName() == null) {
throw new IllegalArgumentException("AliOssProperties or its required fields cannot be null");
}
OSS client = new OSSClientBuilder().build(props.getEndpoint(), props.getAccessKeyId(), props.getAccessKeySecret());
AliOssBucket ossBucket = new AliOssBucket(client, props.getBucketName());
validateOssBucket(ossBucket);
logger.info("数据桶:{} - 链接成功", name);
return ossBucket;
}
private static void validateOssBucket(AliOssBucket aliOssBucket) {
OSS ossClient = aliOssBucket.getOssClient();
String bucketName = aliOssBucket.getBucketName();
try {
if (!ossClient.doesBucketExist(bucketName)) {
throw new RuntimeException("Bucket " + bucketName + " does not exist");
}
} catch (OSSException oe) {
logger.error("OSSException: " + oe.getMessage(), oe);
throw new RuntimeException("OSS error: " + oe.getMessage());
} catch (ClientException ce) {
logger.error("ClientException: " + ce.getMessage(), ce);
throw new RuntimeException("Client error: " + ce.getMessage());
} catch (Exception e) {
logger.error("Exception: " + e.getMessage(), e);
throw new RuntimeException("Error validating OSS bucket: " + e.getMessage());
}
}
public String getMasterBucketName() {
if (masterBucket != null) {
return masterBucket.getBucketName();
}
return null; // 或者抛出异常根据业务需求决定
}
public String getBucketName(String client) {
if (client != null && targetAliOssBucket.containsKey(client)) {
return targetAliOssBucket.get(client).getBucketName();
}
return null; // 或者抛出异常根据业务需求决定
}
} }

View File

@ -14,9 +14,7 @@ public class AliOssProperties {
private OSSClient ossClient; private OSSClient ossClient;
public AliOssProperties(){ public AliOssProperties(){ }
}
public AliOssProperties(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) { public AliOssProperties(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
this.endpoint = endpoint; this.endpoint = endpoint;

View File

@ -1,4 +1,27 @@
package com.ruoyi.alibaba.oss.exception; package com.ruoyi.alibaba.oss.exception;
public class AliOssClientNotFundException extends RuntimeException{ /**
* 当尝试获取阿里云OSS客户端实例但未能找到相应的配置或客户端实例时抛出此异常
* 此异常表明系统中存在配置问题或者客户端初始化失败的问题
*/
public class AliOssClientNotFundException extends RuntimeException {
/**
* 使用指定的详细信息创建一个新的 {@code AliOssClientNotFundException} 实例
*
* @param msg 描述异常原因的信息
*/
public AliOssClientNotFundException(String msg) {
super(msg);
}
/**
* 使用指定的详细信息和导致此异常的原因创建一个新的 {@code AliOssClientNotFundException} 实例
*
* @param message 描述异常原因的信息
* @param cause 导致此异常的根本原因
*/
public AliOssClientNotFundException(String message, Throwable cause) {
super(message, cause);
}
} }

View File

@ -1,14 +1,22 @@
package com.ruoyi.alibaba.oss.service; package com.ruoyi.alibaba.oss.service;
import java.io.InputStream; import java.io.InputStream;
import java.net.URL;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import com.aliyun.oss.OSS;
import com.aliyun.oss.model.GeneratePresignedUrlRequest;
import com.ruoyi.alibaba.oss.config.AliOssConfig; import com.ruoyi.alibaba.oss.config.AliOssConfig;
import com.ruoyi.alibaba.oss.domain.AliOssFileVO; import com.ruoyi.alibaba.oss.domain.AliOssFileVO;
import com.ruoyi.alibaba.oss.exception.AliOssClientErrorException;
import com.ruoyi.alibaba.oss.exception.AliOssClientNotFundException;
import com.ruoyi.alibaba.oss.utils.AliOssUtil; import com.ruoyi.alibaba.oss.utils.AliOssUtil;
import com.ruoyi.common.core.domain.entity.FileEntity; import com.ruoyi.common.core.domain.entity.FileEntity;
import com.ruoyi.common.service.file.FileService; import com.ruoyi.common.service.file.FileService;
@ -21,6 +29,9 @@ import com.ruoyi.common.utils.file.FileUtils;
@Component("file:strategy:oss") @Component("file:strategy:oss")
@ConditionalOnProperty(prefix = "oss", name = { "enable" }, havingValue = "true", matchIfMissing = false) @ConditionalOnProperty(prefix = "oss", name = { "enable" }, havingValue = "true", matchIfMissing = false)
public class AliOssFileService implements FileService { public class AliOssFileService implements FileService {
private static final Logger logger = LoggerFactory.getLogger(AliOssConfig.class);
@Autowired @Autowired
private AliOssConfig aliOssConfig; private AliOssConfig aliOssConfig;
@ -57,4 +68,33 @@ public class AliOssFileService implements FileService {
public FileEntity getFile(String filePath) throws Exception { public FileEntity getFile(String filePath) throws Exception {
return AliOssUtil.getFile(filePath); return AliOssUtil.getFile(filePath);
}; };
/**
* 生成预签名Oss URL.
*
* @param filePath 文件路径
* @return 预签名URL
* @throws AliOssClientNotFundException 如果找不到对应的配置时抛出
* @throws AliOssClientErrorException 如果在创建或获取预签名URL过程中发生错误时抛出
*/
@Override
public URL generatePresignedUrl(String filePath) throws AliOssClientNotFundException, AliOssClientErrorException {
OSS ossClient = null; // 创建并且实例化
try {
ossClient = aliOssConfig.getPrimaryOssClient(); // 调用封装好的AliOssConfig中的方法获取OSS客户端
String bucketName = aliOssConfig.getClient().get(aliOssConfig.getPrimary()).getBucketName();
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, filePath);
Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000); // 设置过期时间为1小时
request.setExpiration(expiration);
// 生成预签名URL
return ossClient.generatePresignedUrl(request);
} catch (Exception e) {
logger.error("生成Oss预签名URL失败: {}", e.getMessage(), e); // 添加日志记录
throw new AliOssClientErrorException("生成Oss预签名URL失败: " + e.getMessage(), e);
} finally {
if (ossClient != null) {
ossClient.shutdown(); // 手动关闭OSS客户端资源
}
}
}
} }