spring boot集成 RustFS服务
1、安装maven依赖
<!-- AWS S3 SDK --><dependency><groupId>software.amazon.awssdk</groupId><artifactId>s3</artifactId><version>2.21.42</version></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency>
2、在yml配置文件中添加如下配置
rustfs:endpoint: http://IP:9000access-key: adminsecret-key: 123456bucket-name: zmtestspring:servlet:multipart:max-file-size: 10MBmax-request-size: 100MB
3、新建配置类RustFSConfig
package com.example.mcp_server_api.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;import java.net.URI;@Configuration
@ConfigurationProperties(prefix = "rustfs")
@Data
public class RustFSConfig {private String endpoint;private String accessKey;private String secretKey;private String bucketName;@Beanpublic S3Client s3Client() {return S3Client.builder().endpointOverride(URI.create(endpoint)).region(Region.US_EAST_1).credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey))).forcePathStyle(true) // 关键配置!RustFS 需启用 Path-Style.build();}@Beanpublic S3Presigner s3Presigner() {return S3Presigner.builder().endpointOverride(URI.create(endpoint)) // 您的RustFS地址.region(Region.US_EAST_1) // 区域,对于自建服务通常可设为任意值.credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, secretKey)))//.fipsEnabled( true).build();}
}
4、服务接口IRustFService
package com.example.mcp_server_api.service;import org.springframework.web.multipart.MultipartFile;import java.time.Duration;public interface IRustFService {//上传文件String uploadFile(MultipartFile file);//删除文件void deleteFile(String fileName);//生成预签名URLString generatePresignedUrl(String fileName, Duration expiration);
}
5、实现类
package com.example.mcp_server_api.service.impl;import com.example.mcp_server_api.service.IRustFService;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import software.amazon.awssdk.core.ResponseInputStream;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;import java.time.Duration;
import java.util.UUID;@Service
@Slf4j
public class RustFServiceImpl implements IRustFService {@Resource@Lazyprivate S3Client s3Client;@Resource@Lazyprivate S3Presigner s3Presigner;@Value("${rustfs.bucket-name}")private String bucketName;/*** 上传文件*/@Overridepublic String uploadFile(MultipartFile file) {try {// 检查存储桶是否存在,不存在则创建if (!bucketExists(bucketName)) {createBucket(bucketName);}String fileName = generateFileName(file.getOriginalFilename());s3Client.putObject(PutObjectRequest.builder().bucket(bucketName).key(fileName).contentType(file.getContentType()).build(),RequestBody.fromInputStream(file.getInputStream(),file.getSize()));return fileName;} catch (Exception e) {log.error("文件上传失败", e);throw new RuntimeException("文件上传失败: " + e.getMessage());}}/*** 下载文件*/public byte[] downloadFile(String fileName) {try {ResponseInputStream<GetObjectResponse> response =s3Client.getObject(GetObjectRequest.builder().bucket(bucketName).key(fileName).build());return response.readAllBytes();} catch (Exception e) {log.error("文件下载失败", e);throw new RuntimeException("文件下载失败: " + e.getMessage());}}/*** 删除文件*/public void deleteFile(String fileName) {try {s3Client.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(fileName).build());} catch (Exception e) {log.error("文件删除失败", e);throw new RuntimeException("文件删除失败: " + e.getMessage());}}@Overridepublic String generatePresignedUrl(String fileName, Duration expiration) {// 1. 构建获取对象的请求GetObjectRequest getObjectRequest = GetObjectRequest.builder().bucket(bucketName).key(fileName).build();// 2. 构建预签名请求,并设置有效期GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder().signatureDuration(expiration) // 例如: Duration.ofMinutes(10).getObjectRequest(getObjectRequest).build();// 3. 生成预签名URLPresignedGetObjectRequest presignedRequest = s3Presigner.presignGetObject(presignRequest);String url = presignedRequest.url().toString();return url;}/*** 检查存储桶是否存在*/private boolean bucketExists(String bucketName) {try {s3Client.headBucket(HeadBucketRequest.builder().bucket(bucketName).build());return true;} catch (NoSuchBucketException e) {return false;}}/*** 创建存储桶*/private void createBucket(String bucketName) {s3Client.createBucket(CreateBucketRequest.builder().bucket(bucketName).build());// 设置存储桶策略为公开可读//setBucketPolicy(bucketName);}/*** 生成唯一文件名*/private String generateFileName(String originalFileName) {String extension = "";if (originalFileName != null && originalFileName.contains(".")) {extension = originalFileName.substring(originalFileName.lastIndexOf("."));}return UUID.randomUUID() + extension;}
}
6、测试控制器
package com.example.mcp_server_api.controller;import com.example.mcp_server_api.service.IRustFService;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;import java.time.Duration;
import java.util.Map;@RestController
@RequestMapping("/file")
public class FileController {@Resourceprivate IRustFService rustFService;//上传附件@PostMapping("/fileUpload")public String fileUpload(@RequestParam("file") MultipartFile file) {return rustFService.uploadFile(file);}//删除文件@DeleteMapping("/deleteFile")public String deleteFile(@RequestBody Map<String,String> paramsMap) {rustFService.deleteFile(paramsMap.get("fileName"));return "OK";}//获取临时访问的Url@PostMapping("/getFileUrl")public String getFileUrl(@RequestBody Map<String,String> map) {return rustFService.generatePresignedUrl(map.get("filePath"), Duration.ofDays(7));}}