diff --git a/.idea/sonarlint/securityhotspotstore/e/6/e6de4bae11e5f329670d8eefa8f2efcb19f7ff88 b/.idea/sonarlint/securityhotspotstore/e/6/e6de4bae11e5f329670d8eefa8f2efcb19f7ff88 deleted file mode 100644 index e69de29..0000000 diff --git a/.idea/sonarlint/securityhotspotstore/e/9/e9e9c8aa0ae1931dc6e028fc6aa2a4445d3ba19e b/.idea/sonarlint/securityhotspotstore/e/9/e9e9c8aa0ae1931dc6e028fc6aa2a4445d3ba19e deleted file mode 100644 index e69de29..0000000 diff --git a/bonus-modules/bonus-obs/pom.xml b/bonus-modules/bonus-obs/pom.xml new file mode 100644 index 0000000..74ce240 --- /dev/null +++ b/bonus-modules/bonus-obs/pom.xml @@ -0,0 +1,103 @@ + + + 4.0.0 + + com.bonus + bonus-modules + 3.6.4 + + + bonus-modules-obs + + bonus-modules-obs存储服务 + + + 8 + 8 + UTF-8 + + + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-sentinel + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + com.github.tobato + fastdfs-client + + + + + io.minio + minio + ${minio.version} + + + + + com.bonus + bonus-api-system + + + + + com.bonus + bonus-common-swagger + + + + com.huaweicloud + esdk-obs-java-bundle + 3.23.9 + + + + org.projectlombok + lombok + provided + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + \ No newline at end of file diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/BonusObsApplication.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/BonusObsApplication.java new file mode 100644 index 0000000..d4b93fd --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/BonusObsApplication.java @@ -0,0 +1,25 @@ +package com.bonus.obs; + +import com.bonus.common.swagger.annotation.EnableCustomSwagger2; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; + +@EnableCustomSwagger2 +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class }) +public class BonusObsApplication { + public static void main(String[] args) + { + SpringApplication.run(BonusObsApplication.class, args); + System.out.println("(♥◠‿◠)ノ゙ obs存储服务模块启动成功 ლ(´ڡ`ლ)゙ \n" + + " .-------. ____ __ \n" + + " | _ _ \\ \\ \\ / / \n" + + " | ( ' ) | \\ _. / ' \n" + + " |(_ o _) / _( )_ .' \n" + + " | (_,_).' __ ___(_ o _)' \n" + + " | |\\ \\ | || |(_,_)' \n" + + " | | \\ `' /| `-' / \n" + + " | | \\ / \\ / \n" + + " ''-' `'-' `-..-' "); + } +} diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/config/ObsConfig.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/config/ObsConfig.java new file mode 100644 index 0000000..0867f98 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/config/ObsConfig.java @@ -0,0 +1,50 @@ +package com.bonus.obs.config; + +import com.obs.services.ObsClient; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ConfigurationProperties(prefix = "obs") +public class ObsConfig { + + private String endpoint; + private String ak; + private String sk; + private String bucket; + + + + public String getEndpoint() { + return endpoint; + } + + public void setEndpoint(String endpoint) { + this.endpoint = endpoint; + } + + public String getAk() { + return ak; + } + + public void setAk(String ak) { + this.ak = ak; + } + + public String getSk() { + return sk; + } + + public void setSk(String sk) { + this.sk = sk; + } + + public String getBucket() { + return bucket; + } + + public void setBucket(String bucket) { + this.bucket = bucket; + } +} diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/controller/ObsController.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/controller/ObsController.java new file mode 100644 index 0000000..10cafc3 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/controller/ObsController.java @@ -0,0 +1,90 @@ +package com.bonus.obs.controller; + +import com.bonus.common.core.domain.R; +import com.bonus.obs.service.ObsService; +import com.bonus.obs.utils.FileUtils; +import com.obs.services.model.DeleteObjectResult; +import com.obs.services.model.ObsObject; +import com.obs.services.model.PutObjectResult; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; + +@RestController +@RequestMapping("/obs") +public class ObsController { + @Resource + private ObsService service; + + /** + * 文件上传 + * + * @param param 文件流 + * @return 文件信息 + */ + @PostMapping("/upload") + public R uploadFile(MultipartFile param) { + return service.uploadFile(param); + } + + /** + * 删除文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + @PostMapping("/delete") + public R deleteFile(String objectKey) { + return service.deleteFile(objectKey); + } + + + /** + * 文件下载 + * + * @param objectKey obs文件存储地址 + */ + @GetMapping("/download") + public void download(HttpServletResponse response, @RequestParam String objectKey) { + R obsObjectR = service.downloadFile(objectKey); + try { + if (R.isError(obsObjectR)) { + response.setStatus(HttpStatus.BAD_REQUEST.value()); + return; + } + if (obsObjectR.getData() == null) { + response.setStatus(HttpStatus.NOT_FOUND.value()); + return; + } + InputStream inputStream = obsObjectR.getData().getObjectContent(); + String safeFileName = FileUtils.getFileNameFromPath(objectKey); + String encodedFileName = URLEncoder.encode(safeFileName, StandardCharsets.UTF_8.toString()); + response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); + response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + encodedFileName + "\""); + try (OutputStream outputStream = response.getOutputStream()) { + byte[] buffer = new byte[8192]; + int bytesRead; + while ((bytesRead = inputStream.read(buffer)) != -1) { + outputStream.write(buffer, 0, bytesRead); + } + outputStream.flush(); + } catch (IOException e) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + } + } catch (IllegalArgumentException e) { + response.setStatus(HttpStatus.BAD_REQUEST.value()); + } catch (Exception e) { + response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value()); + } + } + +} diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/domain/ObsInfo.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/domain/ObsInfo.java new file mode 100644 index 0000000..4253fb8 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/domain/ObsInfo.java @@ -0,0 +1,42 @@ +package com.bonus.obs.domain; + +import lombok.Builder; +import lombok.Data; + +/** + * OBS(Object Storage Service)信息类。 + * 用于封装与OBS对象相关的元数据信息。 + */ +@Data +@Builder +public class ObsInfo { + /** + * 对象的名称。 + * 代表OBS对象的唯一标识。 + */ + private String name; + + /** + * 对象在OBS中的存储路径。 + * 包含桶(bucket)名称和对象在桶内的相对路径。 + */ + private String path; + + /** + * 对象的大小。 + * 以字符串形式表示,可能包含单位(如字节、KB、MB等)。 + */ + private String length; + + /** + * 对象的文件类型。 + * 用于标识对象的MIME类型,例如text/plain、image/jpeg等。 + */ + private String fileType; + + /** + * 对象所属的桶(bucket)的名称。 + * 每个桶在OBS中都是唯一的,用于存储对象。 + */ + private String bucketName; +} diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/ObsService.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/ObsService.java new file mode 100644 index 0000000..c9c64ce --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/ObsService.java @@ -0,0 +1,31 @@ +package com.bonus.obs.service; + +import com.bonus.common.core.domain.R; +import com.obs.services.model.DeleteObjectResult; +import com.obs.services.model.ObsObject; +import com.obs.services.model.PutObjectResult; +import org.springframework.web.multipart.MultipartFile; + +public interface ObsService { + /** + * 文件上传 + * + * @param param 文件流 + * @return 文件信息 + */ + R uploadFile(MultipartFile param); + + /** + * 删除文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + public R deleteFile(String objectKey); + + /** + * 下载文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + public R downloadFile(String objectKey); +} diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/impl/ObsServiceImpl.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/impl/ObsServiceImpl.java new file mode 100644 index 0000000..8042338 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/service/impl/ObsServiceImpl.java @@ -0,0 +1,58 @@ +package com.bonus.obs.service.impl; + +import com.bonus.common.core.domain.R; +import com.bonus.obs.service.ObsService; +import com.bonus.obs.utils.FileUtils; +import com.bonus.obs.utils.ObsUtils; +import com.obs.services.model.DeleteObjectResult; +import com.obs.services.model.ObsObject; +import com.obs.services.model.PutObjectResult; +import org.springframework.stereotype.Service; +import org.springframework.web.multipart.MultipartFile; + +import javax.annotation.Resource; +import java.io.File; + +@Service +public class ObsServiceImpl implements ObsService { + @Resource + private ObsUtils obsUtils; + + /** + * 文件上传 + * + * @param param 文件流 + * @return 文件信息 + */ + @Override + public R uploadFile(MultipartFile param) { + try { + String objectKey = param.getOriginalFilename(); + File file = FileUtils.multipartFileToFile(param); + objectKey = FileUtils.generateObjectName(objectKey); + return obsUtils.uploadFile(objectKey, file); + } catch (Exception e) { + return R.fail(e.getMessage()); + } + } + + /** + * 删除文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + @Override + public R deleteFile(String objectKey) { + return obsUtils.deleteFile(objectKey); + } + + /** + * 下载文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + @Override + public R downloadFile(String objectKey) { + return obsUtils.downloadFile(objectKey); + } +} diff --git a/bonus-modules/bonus-oss/src/main/java/com/bonus/oss/utils/FileUtils.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/FileUtils.java similarity index 98% rename from bonus-modules/bonus-oss/src/main/java/com/bonus/oss/utils/FileUtils.java rename to bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/FileUtils.java index 61c379f..c40d5d0 100644 --- a/bonus-modules/bonus-oss/src/main/java/com/bonus/oss/utils/FileUtils.java +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/FileUtils.java @@ -1,4 +1,4 @@ -package com.bonus.oss.utils; +package com.bonus.obs.utils; import com.bonus.common.core.utils.StringUtils; import org.springframework.web.multipart.MultipartFile; diff --git a/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/ObsUtils.java b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/ObsUtils.java new file mode 100644 index 0000000..f54e772 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/java/com/bonus/obs/utils/ObsUtils.java @@ -0,0 +1,87 @@ +package com.bonus.obs.utils; + +import com.bonus.common.core.domain.R; +import com.bonus.obs.config.ObsConfig; +import com.obs.services.ObsClient; +import com.obs.services.model.DeleteObjectResult; +import com.obs.services.model.GetObjectRequest; +import com.obs.services.model.ObsObject; +import com.obs.services.model.PutObjectResult; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import javax.annotation.Resource; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; + +@Service +public class ObsUtils { + + @Resource + private ObsConfig obsConfig; + /** + * obs 客户端 + */ + private ObsClient obsClient; + + /** + * 初始化信息 + * 构建OSS客户端实例 + */ + @PostConstruct + public void init() { + obsClient = new ObsClient(obsConfig.getAk(), obsConfig.getSk(), obsConfig.getEndpoint()); + } + + + /** + * 上传文件到OBS + * + * @param file 要上传的文件 + * @return 上传结果 + */ + public R uploadFile(String objectKey, File file) { + return R.ok(obsClient.putObject(obsConfig.getBucket(), objectKey, file)); + } + + /** + * 下载文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + public R downloadFile(String objectKey) { + if (!doesObjectExist(objectKey)) { + return R.fail("文件不存在"); + } + return R.ok(obsClient.getObject(new GetObjectRequest(obsConfig.getBucket(), objectKey))); + } + + /** + * 删除文件从OBS + * + * @param objectKey 文件在OBS中的键 + */ + public R deleteFile(String objectKey) { + if (!doesObjectExist(objectKey)) { + return R.fail("文件不存在"); + } + return R.ok(obsClient.deleteObject(obsConfig.getBucket(), objectKey)); + } + + /** + * 判断文件是否存在 + * + * @param objectKey 文件在OBS中的键 + * @return 如果文件存在则返回true,否则返回false + */ + public boolean doesObjectExist(String objectKey) { + try { + return obsClient.doesObjectExist(obsConfig.getBucket(), objectKey); + } catch (Exception e) { + return false; + } + } + +} diff --git a/bonus-modules/bonus-obs/src/main/resources/banner.txt b/bonus-modules/bonus-obs/src/main/resources/banner.txt new file mode 100644 index 0000000..7046037 --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/resources/banner.txt @@ -0,0 +1,9 @@ +Spring Boot Version: ${spring-boot.version} +Spring Application Name: ${spring.application.name} + _ _ + | | | | + | |__ ___ _ __ _ _ ___ ______ ___ | |__ ___ + | '_ \ / _ \ | '_ \ | | | | / __| |______| / _ \ | '_ \ / __| + | |_) | | (_) | | | | | | |_| | \__ \ | (_) | | |_) | \__ \ + |_.__/ \___/ |_| |_| \__,_| |___/ \___/ |_.__/ |___/ + diff --git a/bonus-modules/bonus-obs/src/main/resources/bootstrap.yml b/bonus-modules/bonus-obs/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..333abac --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/resources/bootstrap.yml @@ -0,0 +1,29 @@ +# Tomcat +server: + port: 9205 + +# Spring +spring: + application: + # 应用名称 + name: bonus-obs + profiles: + # 环境配置 + active: dev + cloud: + nacos: + username: nacos + password: nacos + discovery: + # 服务注册地址 + server-addr: 192.168.0.14:8848 + namespace: f1fcd3ea-9460-4597-8acd-0f334527017c + config: + # 配置中心地址 + server-addr: 192.168.0.14:8848 + namespace: f1fcd3ea-9460-4597-8acd-0f334527017c + # 配置文件格式 + file-extension: yml + # 共享配置 + shared-configs: + - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} diff --git a/bonus-modules/bonus-obs/src/main/resources/logback.xml b/bonus-modules/bonus-obs/src/main/resources/logback.xml new file mode 100644 index 0000000..7607fdf --- /dev/null +++ b/bonus-modules/bonus-obs/src/main/resources/logback.xml @@ -0,0 +1,74 @@ + + + + + + + + + + + ${log.pattern} + + + + + + ${log.path}/info.log + + + + ${log.path}/info.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + INFO + + ACCEPT + + DENY + + + + + ${log.path}/error.log + + + + ${log.path}/error.%d{yyyy-MM-dd}.log + + 60 + + + ${log.pattern} + + + + ERROR + + ACCEPT + + DENY + + + + + + + + + + + + + + + + + + \ No newline at end of file