diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 6a58c3f9..7c2ccfed 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -73,6 +73,19 @@ ruoyi-cost + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + com.squareup.okio + okio + 3.6.0 + + diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java index 7701881e..acb84461 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java @@ -13,7 +13,6 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; -import com.ruoyi.common.config.MinioConfig; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.AjaxResult; @@ -41,9 +40,6 @@ public class CommonController @Autowired(required = false) private MinioService minioService; - @Autowired(required = false) - private MinioConfig minioConfig; - private static final String FILE_DELIMETER = ","; /** @@ -220,6 +216,6 @@ public class CommonController */ private boolean isMinioEnabled() { - return minioService != null && minioConfig != null && minioConfig.isEnabled(); + return minioService != null && minioService.isInitialized(); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/FileUploadController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/FileUploadController.java index ab07fc54..e3469ca2 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/FileUploadController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/FileUploadController.java @@ -1,7 +1,6 @@ package com.ruoyi.web.controller.common; import com.ruoyi.common.annotation.Anonymous; -import com.ruoyi.common.config.MinioConfig; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.exception.NonCaptureException; @@ -31,9 +30,6 @@ public class FileUploadController { @Autowired(required = false) private MinioService minioService; - @Autowired(required = false) - private MinioConfig minioConfig; - @Anonymous @PostMapping("/upload") @SuppressWarnings("DuplicatedCode") @@ -75,6 +71,6 @@ public class FileUploadController { */ private boolean isMinioEnabled() { - return minioService != null && minioConfig != null && minioConfig.isEnabled(); + return minioService != null && minioService.isInitialized(); } } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java index 0d50d067..51e1f2ee 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java @@ -11,7 +11,6 @@ import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import com.ruoyi.common.annotation.Log; -import com.ruoyi.common.config.MinioConfig; import com.ruoyi.common.config.RuoYiConfig; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -44,9 +43,6 @@ public class SysProfileController extends BaseController @Autowired(required = false) private MinioService minioService; - @Autowired(required = false) - private MinioConfig minioConfig; - /** * 个人信息 */ @@ -159,6 +155,6 @@ public class SysProfileController extends BaseController */ private boolean isMinioEnabled() { - return minioService != null && minioConfig != null && minioConfig.isEnabled(); + return minioService != null && minioService.isInitialized(); } } diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index bab877ce..39a7124c 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -18,7 +18,7 @@ minio: # 是否启用(false 则使用本地文件系统) enabled: true # MinIO 服务地址 - endpoint: http://140.143.206.120:10990 + endpoint: http://140.143.206.120:10900 # 访问密钥 accessKey: m4X4SsEOhEfTTiv7wI8X # 秘密密钥 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index de359faf..1f242277 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -125,6 +125,12 @@ okhttp 4.12.0 + + + com.squareup.okio + okio + 3.6.0 + diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioService.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioService.java index b03f1eeb..abb8abfe 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioService.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MinioService.java @@ -12,16 +12,10 @@ import io.minio.PutObjectArgs; import io.minio.RemoveObjectArgs; import io.minio.StatObjectArgs; import io.minio.errors.ErrorResponseException; -import io.minio.errors.InsufficientDataException; -import io.minio.errors.InternalException; -import io.minio.errors.InvalidResponseException; -import io.minio.errors.ServerException; -import io.minio.errors.XmlParserException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; @@ -35,45 +29,63 @@ import io.minio.http.Method; * @author ruoyi */ @Service -@ConditionalOnProperty(prefix = "minio", name = "enabled", havingValue = "true") public class MinioService { private static final Logger log = LoggerFactory.getLogger(MinioService.class); private MinioClient minioClient; - private MinioConfig minioConfig; + private volatile boolean initialized = false; @Autowired public MinioService(MinioConfig minioConfig) { this.minioConfig = minioConfig; - this.minioClient = MinioClient.builder() - .endpoint(minioConfig.getEndpoint()) - .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()) - .build(); - ensureBucketExists(); + if (!minioConfig.isEnabled()) + { + log.info("MinIO 未启用(minio.enabled=false),跳过初始化"); + return; + } + try + { + this.minioClient = MinioClient.builder() + .endpoint(minioConfig.getEndpoint()) + .credentials(minioConfig.getAccessKey(), minioConfig.getSecretKey()) + .build(); + ensureBucketExists(); + this.initialized = true; + log.info("MinIO 客户端初始化成功: endpoint={}, bucket={}", + minioConfig.getEndpoint(), minioConfig.getBucketName()); + } + catch (Exception e) + { + log.warn("MinIO 初始化失败(应用将继续运行,上传降级为本地文件系统): {}", e.getMessage()); + this.minioClient = null; + this.initialized = false; + } + } + + /** + * 检查 MinIO 客户端是否已正确初始化 + */ + private void checkInitialized() + { + if (!initialized || minioClient == null) + { + throw new IllegalStateException("MinIO 未启用或初始化失败,请检查配置"); + } } /** * 确保存储桶存在,不存在则自动创建 */ - private void ensureBucketExists() + private void ensureBucketExists() throws Exception { - try + String bucketName = minioConfig.getBucketName(); + if (!minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) { - String bucketName = minioConfig.getBucketName(); - boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build()); - if (!exists) - { - minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); - log.info("MinIO 存储桶 [{}] 已自动创建", bucketName); - } - } - catch (Exception e) - { - log.error("MinIO 存储桶初始化失败", e); - throw new RuntimeException("MinIO 存储桶初始化失败: " + e.getMessage(), e); + minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build()); + log.info("MinIO 存储桶 [{}] 已自动创建", bucketName); } } @@ -86,6 +98,7 @@ public class MinioService */ public String upload(MultipartFile file, String objectName) throws IOException { + checkInitialized(); try { String contentType = file.getContentType() != null ? file.getContentType() : "application/octet-stream"; @@ -117,6 +130,7 @@ public class MinioService */ public String upload(InputStream stream, String objectName, long size, String contentType) throws IOException { + checkInitialized(); try { String ct = (contentType != null) ? contentType : "application/octet-stream"; @@ -144,6 +158,7 @@ public class MinioService */ public String getUrl(String objectName) { + checkInitialized(); try { return minioClient.getPresignedObjectUrl( @@ -151,13 +166,12 @@ public class MinioService .method(Method.GET) .bucket(minioConfig.getBucketName()) .object(objectName) - .expiry(7 * 24 * 60 * 60) // 7天有效期 + .expiry(7 * 24 * 60 * 60) .build()); } catch (Exception e) { log.warn("MinIO 获取 URL 失败: {}", objectName, e); - // 返回拼接直连地址 return minioConfig.getEndpoint() + "/" + minioConfig.getBucketName() + "/" + objectName; } } @@ -170,6 +184,7 @@ public class MinioService */ public void download(String objectName, OutputStream os) throws IOException { + checkInitialized(); try { try (InputStream is = minioClient.getObject( @@ -200,6 +215,7 @@ public class MinioService */ public void delete(String objectName) throws IOException { + checkInitialized(); try { minioClient.removeObject( @@ -224,6 +240,10 @@ public class MinioService */ public boolean exists(String objectName) { + if (!initialized || minioClient == null) + { + return false; + } try { minioClient.statObject( @@ -244,6 +264,14 @@ public class MinioService } } + /** + * 判断 MinIO 是否已正确初始化并可用 + */ + public boolean isInitialized() + { + return initialized && minioClient != null; + } + /** * 获取 MinIO 配置 */