From 9c7549a3e811afc3a02fb0e56f21602a0782ff2c Mon Sep 17 00:00:00 2001 From: 17752985069 Date: Sun, 27 Oct 2024 15:01:06 +0800 Subject: [PATCH 1/2] =?UTF-8?q?oss=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/application-oss.yml | 10 + .../src/main/resources/application.yml | 4 +- ruoyi-plugins/pom.xml | 16 ++ ruoyi-plugins/ruoyi-alibaba-oss/pom.xml | 28 +++ .../alibaba/oss/config/AliOssConfig.java | 135 +++++++++++++ .../alibaba/oss/config/AliOssProperties.java | 62 ++++++ .../oss/controller/AliOssController.java | 68 +++++++ .../alibaba/oss/domain/AliOssBucket.java | 150 +++++++++++++++ .../alibaba/oss/domain/AliOssFileVO.java | 52 +++++ .../exception/AliOssClientErrorException.java | 11 ++ .../AliOssClientNotFundException.java | 4 + .../oss/service/AliOssFileService.java | 87 +++++++++ .../ruoyi/alibaba/oss/utils/AliOssUtil.java | 182 ++++++++++++++++++ ruoyi-plugins/ruoyi-plugins-starter/pom.xml | 6 + 14 files changed, 813 insertions(+), 2 deletions(-) create mode 100644 ruoyi-admin/src/main/resources/application-oss.yml create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/pom.xml create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssConfig.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssProperties.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/controller/AliOssController.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssBucket.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssFileVO.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientErrorException.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientNotFundException.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/service/AliOssFileService.java create mode 100644 ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/utils/AliOssUtil.java diff --git a/ruoyi-admin/src/main/resources/application-oss.yml b/ruoyi-admin/src/main/resources/application-oss.yml new file mode 100644 index 0000000..c8e72d1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/application-oss.yml @@ -0,0 +1,10 @@ +# oss配置 +oss: + enable: false + primary: MASTER + client: + MASTER: + accessKeyId: + accessKeySecret: + bucketName: szb-resource + endpoint: oss-cn-shenzhen.aliyuncs.com diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 45c0a29..07bd6a3 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -12,7 +12,7 @@ ruoyi: addressEnabled: false # 验证码类型 math 数组计算 char 字符验证 captchaType: math - # 指定默认文件服务类型(值为disk代表使用磁盘作为文件操作服务,minio代表使用minio作为文件操作服务) + # 指定默认文件服务类型(值为disk代表使用磁盘作为文件操作服务,minio代表使用minio作为文件操作服务,oss代表使用oss作为文件操作服务) fileServer: disk # 开发环境配置 @@ -69,7 +69,7 @@ spring: # 国际化资源文件路径 basename: i18n/messages profiles: - active: druid,mybatis,auth,pay,middleware,lp + active: druid,mybatis,auth,pay,middleware,lp,oss # 文件上传 servlet: multipart: diff --git a/ruoyi-plugins/pom.xml b/ruoyi-plugins/pom.xml index 9807d98..80a91f1 100644 --- a/ruoyi-plugins/pom.xml +++ b/ruoyi-plugins/pom.xml @@ -14,6 +14,7 @@ 3.10.8 3.5.8 4.1.112.Final + 3.18.1 @@ -87,6 +88,20 @@ ${netty.version} + + + com.ruoyi + ruoyi-alibaba-oss + ${ruoyi.version} + + + + + com.aliyun.oss + aliyun-sdk-oss + ${oss.version} + + @@ -99,6 +114,7 @@ ruoyi-plugins-starter ruoyi-mybatis-interceptor ruoyi-netty + ruoyi-alibaba-oss pom diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/pom.xml b/ruoyi-plugins/ruoyi-alibaba-oss/pom.xml new file mode 100644 index 0000000..0871d9b --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/pom.xml @@ -0,0 +1,28 @@ + + + 4.0.0 + + ruoyi-plugins + com.ruoyi + 3.8.8.3.1 + + com.ruoyi + ruoyi-alibaba-oss + oss中间件 + + + + + com.ruoyi + ruoyi-common + + + + + com.aliyun.oss + aliyun-sdk-oss + 3.10.2 + + + diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssConfig.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssConfig.java new file mode 100644 index 0000000..c814cb7 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssConfig.java @@ -0,0 +1,135 @@ +package com.ruoyi.alibaba.oss.config; + +import java.util.HashMap; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +import com.aliyun.oss.ClientException; +import com.aliyun.oss.OSS; +import com.aliyun.oss.OSSClientBuilder; +import com.aliyun.oss.OSSException; +import com.ruoyi.alibaba.oss.domain.AliOssBucket; + +@Configuration("AliOssConfiguration") +@ConditionalOnProperty(prefix = "oss", name = "enable", havingValue = "true", matchIfMissing = false) +@ConfigurationProperties(prefix = "oss") +public class AliOssConfig implements InitializingBean { + private static final Logger logger = LoggerFactory.getLogger(AliOssConfig.class); + public static int maxSize; + private String prefix = "/oss"; // 根据需要调整前缀 + private Map client = new HashMap<>(); + private String primary; + private Map targetAliOssBucket = new HashMap<>(); + private AliOssBucket masterBucket; + + public int getMaxSize() { + return maxSize; + } + + public AliOssBucket getMasterBucket() { + return this.masterBucket; + } + + public AliOssBucket getBucket(String client) { + return targetAliOssBucket.get(client); + } + + public Map getClient() { + return client; + } + + public void setClient(Map client) { + this.client = client; + } + + public String getPrimary() { + return primary; + } + + public void setPrimary(String primary) { + this.primary = primary; + } + + public String getPrefix() { + return prefix; + } + + public void setPrefix(String 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; // 或者抛出异常,根据业务需求决定 + } + +} diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssProperties.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssProperties.java new file mode 100644 index 0000000..f20341a --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/config/AliOssProperties.java @@ -0,0 +1,62 @@ +package com.ruoyi.alibaba.oss.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +import com.aliyun.oss.OSSClient; + +@ConfigurationProperties(prefix = "oss.client") +public class AliOssProperties { + + private String endpoint; + private String accessKeyId; + private String accessKeySecret; + private String bucketName; + + private OSSClient ossClient; + + public AliOssProperties(){ + + } + + public AliOssProperties(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) { + this.endpoint = endpoint; + this.accessKeyId = accessKeyId; + this.accessKeySecret = accessKeySecret; + this.bucketName = bucketName; + } + public String getEndpoint() { + return endpoint; + } + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + public String getAccessKeyId() { + return accessKeyId; + } + public void setAccessKeyId(String accessKeyId) { + this.accessKeyId = accessKeyId; + } + public String getAccessKeySecret() { + return accessKeySecret; + } + public void setAccessKeySecret(String accessKeySecret) { + this.accessKeySecret = accessKeySecret; + } + public String getBucketName() { + return bucketName; + } + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public OSSClient getOssClient() { + return ossClient; + } + + public void setOssClient(OSSClient ossClient) { + this.ossClient = ossClient; + } + + + +} \ No newline at end of file diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/controller/AliOssController.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/controller/AliOssController.java new file mode 100644 index 0000000..598f864 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/controller/AliOssController.java @@ -0,0 +1,68 @@ +package com.ruoyi.alibaba.oss.controller; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; + +import com.ruoyi.alibaba.oss.domain.AliOssFileVO; +import com.ruoyi.alibaba.oss.utils.AliOssUtil; + +import io.swagger.v3.oas.annotations.Operation; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@RestController +@RequestMapping("/oss") +public class AliOssController { + + @Autowired + private AliOssUtil aliOssUtil; + + @Operation(summary = "下载接口oss") + @GetMapping("/{client}") + public void downLoadFile(HttpServletRequest request, HttpServletResponse response,@PathVariable("client") String client, + @RequestParam("fileName") String fileName) throws Exception { + AliOssFileVO file = aliOssUtil.getFile(client, fileName); + // 设置响应头 + String contentType = file.getHeaders().getOrDefault("Content-Type", "application/octet-stream"); + response.setContentType(contentType); + + // 设置内容长度 + String contentLength = file.getHeaders().get("Content-Length"); + if (contentLength != null) { + response.setContentLengthLong(Long.parseLong(contentLength)); + } + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\""); + // 写入文件内容到响应流 + try (InputStream inputStream = file.getFileInputSteam(); + OutputStream outputStream = response.getOutputStream()) { + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + } catch (IOException e) { + throw new IOException("Error writing file to output stream", e); + } + } + + + //上传接口 + @Operation(summary = "上传接口oss") + @PutMapping("/{client}") + public String uploadFile(HttpServletRequest request, HttpServletResponse response, + @PathVariable("client") String client, @RequestParam("file") MultipartFile file) throws Exception { + return AliOssUtil.uploadFile(client, file); + } +} diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssBucket.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssBucket.java new file mode 100644 index 0000000..3658edb --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssBucket.java @@ -0,0 +1,150 @@ +package com.ruoyi.alibaba.oss.domain; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.web.multipart.MultipartFile; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.model.DeleteObjectsRequest; +import com.aliyun.oss.model.GetObjectRequest; +import com.aliyun.oss.model.OSSObject; +import com.aliyun.oss.model.ObjectMetadata; +import com.aliyun.oss.model.PutObjectRequest; +import com.ruoyi.alibaba.oss.exception.AliOssClientErrorException; + +public class AliOssBucket { + + private static final Logger logger = LoggerFactory.getLogger(AliOssBucket.class); + + private String bucketName; + private OSS ossClient; + + public AliOssBucket() { + } + + // 构造函数 + public AliOssBucket(OSS ossClient, String bucketName) { + this.ossClient = ossClient; + this.bucketName = bucketName; + } + + public OSS getOssClient() { + return ossClient; + } + + public void setOssClient(OSS ossClient) { + this.ossClient = ossClient; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public void put(String fileName, MultipartFile file) throws Exception { + put(fileName, file.getContentType(), file.getInputStream()); + } + + // 上传文件 + public void put(String filePath, String contentType, InputStream inputStream) throws Exception { + try { + // 创建 ObjectMetadata 对象,并设置内容类型 + ObjectMetadata metadata = new ObjectMetadata(); + metadata.setContentType(contentType); + metadata.setContentLength(inputStream.available()); // 使用 InputStream 的 available 方法 + + // 创建 PutObjectRequest 对象 + PutObjectRequest putRequest = new PutObjectRequest(bucketName, filePath, inputStream, metadata); + + // 上传对象 + ossClient.putObject(putRequest); + } catch (Exception e) { + logger.error("Error uploading file: {}", e.getMessage(), e); + throw new AliOssClientErrorException("Error uploading file: " + e.getMessage(), e); + } + } + + public void put(PutObjectRequest putObjectRequest) throws Exception { + try { + this.ossClient.putObject(putObjectRequest); + } catch (Exception e) { + logger.error("Error uploading file: {}", e.getMessage(), e); + throw new AliOssClientErrorException("Error uploading file: " + e.getMessage(), e); + } + } + + public void remove(String filePath) throws Exception { + // 删除单个对象 + ossClient.deleteObject(bucketName, filePath); + } + + public void removeMultiple(List filePaths) throws Exception { + // 删除多个对象 + try { + DeleteObjectsRequest deleteRequest = new DeleteObjectsRequest(bucketName).withKeys(filePaths); + ossClient.deleteObjects(deleteRequest); + } catch (Exception e) { + logger.error("Error deleting files: {}", e.getMessage(), e); + throw new AliOssClientErrorException("Error deleting files: " + e.getMessage(), e); + } + } + + public AliOssFileVO get(GetObjectRequest getObjectRequest) throws Exception { + try (OSSObject ossObject = this.ossClient.getObject(getObjectRequest)) { + if (ossObject == null) { + throw new Exception("Failed to retrieve object from OSS."); + } + + // 读取OSSObject的内容到ByteArrayOutputStream中 + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + byte[] bytes = new byte[1024]; // 根据需要调整缓冲区大小 + int length; + while ((length = ossObject.getObjectContent().read(bytes)) != -1) { + byteArrayOutputStream.write(bytes, 0, length); + } + + // 获取 headers + Map headers = new HashMap<>(); + for (Map.Entry entry : ossObject.getObjectMetadata().getUserMetadata().entrySet()) { + headers.put(entry.getKey(), entry.getValue()); + } + headers.put("Content-Type", ossObject.getObjectMetadata().getContentType()); + headers.put("Content-Length", String.valueOf(ossObject.getObjectMetadata().getContentLength())); + + // 设置 AliOssFileVO 对象的属性 + AliOssFileVO fileVO = new AliOssFileVO(); + fileVO.setFileInputSteam(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); + fileVO.setHeaders(headers); + fileVO.setKey(ossObject.getKey()); + fileVO.setBucketName(ossObject.getBucketName()); + + return fileVO; + } + } catch (Exception e) { + logger.error("Error retrieving file: {}", e.getMessage(), e); + throw new AliOssClientErrorException("Error retrieving file: " + e.getMessage(), e); + } + } + + /** + * 文件下载 + * + * @param filePath 文件路径 + * @return 返回封装的OSS下载文件对象 + * @throws Exception 如果下载过程中出现问题 + */ + public AliOssFileVO get(String filePath) throws Exception { + GetObjectRequest request = new GetObjectRequest(this.bucketName, filePath); + return get(request); + } +} \ No newline at end of file diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssFileVO.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssFileVO.java new file mode 100644 index 0000000..caee70b --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/domain/AliOssFileVO.java @@ -0,0 +1,52 @@ +package com.ruoyi.alibaba.oss.domain; + +import java.io.InputStream; +import java.util.Map; + +public class AliOssFileVO { + private InputStream fileInputSteam; + private String key; + private Map headers; + private String bucketName; + + public AliOssFileVO(){} + + public AliOssFileVO(InputStream fileInputSteam, String key, Map headers, String bucketName) { + this.fileInputSteam = fileInputSteam; + this.key = key; + this.headers = headers; + this.bucketName = bucketName; + } + + public InputStream getFileInputSteam() { + return fileInputSteam; + } + + public void setFileInputSteam(InputStream fileInputSteam) { + this.fileInputSteam = fileInputSteam; + } + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } + + public Map getHeaders() { + return headers; + } + + public void setHeaders(Map headers) { + this.headers = headers; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } +} \ No newline at end of file diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientErrorException.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientErrorException.java new file mode 100644 index 0000000..9659061 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientErrorException.java @@ -0,0 +1,11 @@ +package com.ruoyi.alibaba.oss.exception; + +public class AliOssClientErrorException extends RuntimeException{ + public AliOssClientErrorException(String msg){ + super(msg); + } + + public AliOssClientErrorException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientNotFundException.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientNotFundException.java new file mode 100644 index 0000000..5596ac5 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/exception/AliOssClientNotFundException.java @@ -0,0 +1,4 @@ +package com.ruoyi.alibaba.oss.exception; + +public class AliOssClientNotFundException extends RuntimeException{ +} diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/service/AliOssFileService.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/service/AliOssFileService.java new file mode 100644 index 0000000..0e9fe73 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/service/AliOssFileService.java @@ -0,0 +1,87 @@ +package com.ruoyi.alibaba.oss.service; + +import java.io.File; +import java.io.InputStream; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.ruoyi.alibaba.oss.config.AliOssConfig; +import com.ruoyi.alibaba.oss.domain.AliOssFileVO; +import com.ruoyi.alibaba.oss.utils.AliOssUtil; +import com.ruoyi.common.config.RuoYiConfig; +import com.ruoyi.common.service.file.FileService; +import com.ruoyi.common.utils.file.FileOperateUtils; +import com.ruoyi.common.utils.file.FileUtils; + +/** + * oss文件操作实现类 + */ +@Component("file:strategy:oss") +@ConditionalOnProperty(prefix = "oss", name = { "enable" }, havingValue = "true", matchIfMissing = false) +public class AliOssFileService implements FileService { + @Autowired + private AliOssConfig aliOssConfig; + + @Override + public String upload(String filePath, MultipartFile file) throws Exception { + String relativePath = null; + if (FileUtils.isAbsolutePath(filePath)) { + relativePath = FileUtils.getRelativePath(filePath); + } else { + relativePath = filePath; + } + + String fullPath = AliOssUtil.uploadFile(aliOssConfig.getPrimary(), relativePath, file); + return extractFileName(fullPath); + } + + @Override + public String upload(MultipartFile file, String name) throws Exception { + String fullPath = AliOssUtil.uploadFile(aliOssConfig.getPrimary(), name, file); + return extractFileName(fullPath); + } + + @Override + public String upload(MultipartFile file) throws Exception { + String filePath = RuoYiConfig.getProfile() + File.separator + FileUtils.fastFilePath(file); + return upload(filePath, file); + } + + @Override + public String upload(String baseDir, String fileName, MultipartFile file) throws Exception { + return upload(baseDir + File.pathSeparator + fileName, file); + } + + @Override + public InputStream downLoad(String filepath) throws Exception { + AliOssFileVO file = AliOssUtil.getFile(filepath); + return file.getFileInputSteam(); + } + + @Override + public boolean deleteFile(String fileUrl) throws Exception { + AliOssUtil.removeFile(aliOssConfig.getPrimary(), fileUrl); + FileOperateUtils.deleteFileAndMd5ByFilePath(fileUrl); + return true; + } + + /** + * 提取文件名 + * + * @param fullPath 完整的文件路径 + * @return 文件名 + */ + private String extractFileName(String fullPath) { + if (fullPath == null || !fullPath.contains("fileName=")) { + return fullPath; + } + int startIndex = fullPath.indexOf("fileName=") + "fileName=".length(); + if (startIndex < 0 || startIndex >= fullPath.length()) { + return fullPath; // 如果没有找到 "fileName=",则返回原路径 + } + return fullPath.substring(startIndex); + } +} \ No newline at end of file diff --git a/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/utils/AliOssUtil.java b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/utils/AliOssUtil.java new file mode 100644 index 0000000..60fac12 --- /dev/null +++ b/ruoyi-plugins/ruoyi-alibaba-oss/src/main/java/com/ruoyi/alibaba/oss/utils/AliOssUtil.java @@ -0,0 +1,182 @@ +package com.ruoyi.alibaba.oss.utils; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +import com.aliyun.oss.OSS; +import com.aliyun.oss.model.GetObjectRequest; +import com.aliyun.oss.model.OSSObject; +import com.ruoyi.alibaba.oss.config.AliOssConfig; +import com.ruoyi.alibaba.oss.domain.AliOssBucket; +import com.ruoyi.alibaba.oss.domain.AliOssFileVO; +import com.ruoyi.alibaba.oss.exception.AliOssClientErrorException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.file.FileUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.common.utils.uuid.UUID; + +/** + * oss工具 + */ +@Component +public class AliOssUtil { + + private static AliOssConfig aliOssConfig; + + private static AliOssConfig getAliOssConfig() { + if (aliOssConfig == null) { + synchronized (AliOssUtil.class) { + if (aliOssConfig == null) { + aliOssConfig = SpringUtils.getBean(AliOssConfig.class); + } + } + } + return aliOssConfig; + } + + /** + * 文件上传 + * + * @param client 连接名 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + * @throws IOException 比如读写文件出错时 + */ + public static String uploadFile(String client, MultipartFile file) throws Exception { + String fileName = DateUtils.dateTimeNow() + UUID.fastUUID().toString().substring(0, 5) + "." + FileUtils.getExtension(file); + return uploadFile(client, fileName, file); + } + + /** + * 文件上传 + * + * @param client 连接名 + * @param fileName 上传文件名 + * @param file 上传的文件 + * @return 返回上传成功的文件名 + * @throws IOException 比如读写文件出错时 + */ + public static String uploadFile(String client, String fileName, MultipartFile file) throws Exception { + getAliOssConfig().getBucket(client).put(fileName, file); + return getURL(client, fileName); + } + + /** + * 获取文件URL + * + * @param client 连接名 + * @param filePath 文件路径 + * @return 返回上传成功的文件路径 + */ + public static String getURL(String client, String filePath) throws Exception { + try { + StringBuilder url = new StringBuilder(); + url.append(getAliOssConfig().getPrefix()).append("/").append(client) + .append("?").append("fileName=").append(filePath); + return url.toString(); + } catch (Exception e) { + throw new AliOssClientErrorException(e.getMessage()); + } + } + + /** + * 文件删除 + * + * @param filePath 上传文件路径 + * @throws IOException 比如读写文件出错时 + */ + public static void removeFile(String filePath) throws Exception { + getAliOssConfig().getMasterBucket().remove(filePath); + } + + /** + * 文件删除 + * + * @param client 连接名 + * @param filePath 上传文件路径 + * @throws IOException 比如读写文件出错时 + */ + public static void removeFile(String client, String filePath) throws Exception { + getAliOssConfig().getBucket(client).remove(filePath); + } + + /** + * 文件下载 + * + * @param filePath 文件路径 + * @return 返回封装的Oss下载文件对象 + * @throws IOException 比如读写文件出错时 + */ + public static AliOssFileVO getFile(String filePath) throws Exception { + return getFile(null, filePath); + } + + /** + * 文件下载 + * + * @param client 连接名 + * @param filePath 文件路径 + * @return 返回封装的Oss下载文件对象 + * @throws IOException 比如读写文件出错时 + */ + public static AliOssFileVO getFile(String client, String filePath) throws Exception { + AliOssBucket ossBucket = client == null ? getAliOssConfig().getMasterBucket() : getAliOssConfig().getBucket(client); + String bucketName = client == null ? getAliOssConfig().getMasterBucketName() : getAliOssConfig().getBucketName(client); + + if (bucketName == null) { + throw new AliOssClientErrorException("参数 \"bucketName\" 为空指针"); + } + + GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, filePath); + + return get(getObjectRequest, ossBucket.getOssClient()); + } + /** + * 从OSS中获取文件并封装成AliOssFileVO对象 + * + * @param getObjectRequest 获取对象请求 + * @param ossClient OSS客户端 + * @return 返回封装的Oss下载文件对象 + * @throws Exception 如果获取文件失败 + */ + private static AliOssFileVO get(GetObjectRequest getObjectRequest, OSS ossClient) throws Exception { + OSSObject ossObject = ossClient.getObject(getObjectRequest); + if (ossObject == null) { + throw new Exception("Failed to retrieve object from OSS."); + } + + // 读取OSSObject的内容到ByteArrayOutputStream中 + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] bytes = new byte[1024]; // 根据需要调整缓冲区大小 + int length; + while ((length = ossObject.getObjectContent().read(bytes)) != -1) { + byteArrayOutputStream.write(bytes, 0, length); + } + + // 获取 headers + Map headers = new HashMap<>(); + for (Map.Entry entry : ossObject.getObjectMetadata().getUserMetadata().entrySet()) { + headers.put(entry.getKey(), entry.getValue()); + } + headers.put("Content-Type", ossObject.getObjectMetadata().getContentType()); + headers.put("Content-Length", String.valueOf(ossObject.getObjectMetadata().getContentLength())); + + // 设置 AliOssFileVO 对象的属性 + AliOssFileVO fileVO = new AliOssFileVO(); + fileVO.setFileInputSteam(new ByteArrayInputStream(byteArrayOutputStream.toByteArray())); + fileVO.setHeaders(headers); + fileVO.setKey(ossObject.getKey()); + fileVO.setBucketName(ossObject.getBucketName()); + + // 关闭OSSObject + ossObject.close(); + + return fileVO; + } +} \ No newline at end of file diff --git a/ruoyi-plugins/ruoyi-plugins-starter/pom.xml b/ruoyi-plugins/ruoyi-plugins-starter/pom.xml index fc7eb6d..a32aacf 100644 --- a/ruoyi-plugins/ruoyi-plugins-starter/pom.xml +++ b/ruoyi-plugins/ruoyi-plugins-starter/pom.xml @@ -55,6 +55,12 @@ com.ruoyi ruoyi-netty + + + + com.ruoyi + ruoyi-alibaba-oss + -- Gitee From d7a2d9f7a98a69d962b991107e94e88c079e3fb5 Mon Sep 17 00:00:00 2001 From: 17752985069 Date: Sun, 27 Oct 2024 17:37:20 +0800 Subject: [PATCH 2/2] =?UTF-8?q?oss=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/src/main/resources/application-oss.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ruoyi-admin/src/main/resources/application-oss.yml b/ruoyi-admin/src/main/resources/application-oss.yml index c8e72d1..579c36b 100644 --- a/ruoyi-admin/src/main/resources/application-oss.yml +++ b/ruoyi-admin/src/main/resources/application-oss.yml @@ -6,5 +6,5 @@ oss: MASTER: accessKeyId: accessKeySecret: - bucketName: szb-resource - endpoint: oss-cn-shenzhen.aliyuncs.com + bucketName: + endpoint: -- Gitee