1. 依赖管理与版本说明

Maven 依赖配置:
    <dependencies>
        <!-- AWS SDK for S3 (兼容Cloudflare R2) -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <version>2.29.52</version>
        </dependency>
        <!-- EC2依赖用于区域自动识别 -->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>ec2</artifactId>
            <version>2.29.52</version>
        </dependency>
        <!-- HTTP客户端用于底层请求 -->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>
    </dependencies>
版本选择注意事项:
  • 2.30.0 + 版本需额外配置签名算法

在这里插入图片描述

2. 配置文件与常量管理

application.yml 完整配置:
    cloud:
      aws:
        s3:
          endpoint: https://abc123.r2.cloudflarestorage.com  # 替换为实际accountID
          bucket-name: my-spring-boot-bucket                # 替换为实际存储桶名
          cdn-domain: img.example.com                        # 替换为自定义域名
          region: auto                                       # 自动识别区域
          credentials:
            access-key: YOUR_ACCESS_KEY                      # 替换为API访问密钥
            secret-key: YOUR_SECRET_KEY                      # 替换为API秘密密钥

3. 核心代码实现

config代码
@Component
public class R2FileUtils implements InitializingBean {

    public static String END_POINT;
    public static String REGION;
    public static String BUCKET_NAME;
    public static String CDN_DOMAIN;
    public static String ACCESS_KEY;
    public static String SECRET_KEY;

    @Value("${cloud.aws.s3.endpoint}")
    private String endpoint;

    @Value("${cloud.aws.s3.region}")
    private String region;

    @Value("${cloud.aws.s3.bucket-name}")
    private String bucketName;

    @Value("${cloud.aws.s3.cdn-domain}")
    private String cdnDomain;

    @Value("${cloud.aws.s3.credentials.access-key}")
    private String accessKey;

    @Value("${cloud.aws.s3.credentials.secret-key}")
    private String secretKey;

    @Override
    public void afterPropertiesSet() throws Exception {
        END_POINT = this.endpoint;
        REGION = this.region;
        BUCKET_NAME = this.bucketName;
        CDN_DOMAIN = this.cdnDomain;
        ACCESS_KEY = this.accessKey;
        SECRET_KEY = this.secretKey;
    }
}
controller代码

    @RestController
    @RequestMapping("/api/file")
    @Api(tags = "文件上传接口")
    public class FileUploadController {
        
        @Resource
        private FileUploadService fileUploadService;
        
        @PostMapping("/r2/upload")
        @ApiOperation("Cloudflare R2文件上传")
        @ApiImplicitParam(name = "file", value = "上传文件", required = true, 
                           dataType = "MultipartFile")
        public CommonResult<String> uploadToR2(@RequestPart("file") MultipartFile file) {
            // 前置校验
            if (file.isEmpty()) {
                return CommonResult.error(ErrorCode.FILE_EMPTY);
            }
            // 调用服务层
            String url = fileUploadService.uploadToR2(file);
            return CommonResult.success(url, "上传成功");
        }
    }
serviceImpl核心代码

    @Service
    public class FileUploadServiceImpl implements FileUploadService {
        
        @Override
        public String uploadToR2(MultipartFile file) {
            try (InputStream inputStream = file.getInputStream()) {
                // 构建S3客户端
                S3Client s3Client = S3Client.builder()
                    .endpointOverride(URI.create(R2Config.END_POINT))
                    .credentialsProvider(() -> AwsBasicCredentials.create(
                        R2Config.ACCESS_KEY, R2Config.SECRET_KEY))
                    .region(Region.of(R2Config.REGION))
                    .build();
                
                // 生成唯一文件名(含日期路径)
                String datePath = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
                String originalFilename = file.getOriginalFilename();
                String fileExt = originalFilename.substring(originalFilename.lastIndexOf("."));
                String objectKey = datePath + "/" + UUID.randomUUID() + fileExt;
                
                // 构建上传请求
                PutObjectRequest putRequest = PutObjectRequest.builder()
                    .bucket(R2Config.BUCKET_NAME)
                    .key(objectKey)
                    .contentType(file.getContentType())
                    .build();
                
                // 执行上传
                s3Client.putObject(putRequest, 
                    RequestBody.fromInputStream(inputStream, file.getSize()));
                
                // 生成可访问URL(含CDN域名)
                return R2Config.CDN_DOMAIN + "/" + objectKey;
                
            } catch (IOException | S3Exception e) {
                log.error("R2文件上传失败: {}", e.getMessage(), e);
                throw new FileUploadException("文件上传失败,请稍后再试");
            }
        }
    }
接口测试

在这里插入图片描述

除此之外还可以限制文件大小,格式,设置定期删除等功能,示例中不再赘述。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐