【需要域名】SpringBoot项目连接免费对象存储服务CloudFlare R2实现资源URL绑定域名访问

前人栽树后人乘凉。就当做是前辈们的文章补充分支。

参考链接:

https://github.com/idinging/cloudflare-r2-demo

在springboot集成Cloudflare R2对象存储-优快云博客

玩转云服务(8):使用 Cloudflare R2 对象存储 - 知乎

情景:你的SpingBoot项目已经能够通过域名访问。你开通了CloudFlare的Free计划,并正确地将域名的DNS服务器托管到了CloudFlare上

在账户主页找到R2。填写支付信息开通CloudFlare的R2服务。


一、在R2上创建一个存储桶,位置根据自己需要选择。

二、设置->自定义域->添加,添加自己的域名连接到你的存储桶

域名以CloudFlare的DNS管理页面左上角为主。

创建完成后会自动给你添加一条R2类型的DNS记录,等待状态变为【活动】

注意中文域名发生了转码,访问资源时是根据转码后的域名的URL访问的

三、SpringBoot项目添加Maven依赖

        <!--与 Cloudflare R2 对象存储服务交互-->
        <dependency>
            <groupId>software.amazon.awssdk</groupId>
            <artifactId>s3</artifactId>
            <version>2.29.52</version>
        </dependency>
        <!--提供底层 HTTP 客户端功能,支持 AWS SDK 的 HTTP 请求发送和响应处理-->
        <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.13</version>
        </dependency>

四、获取你的配置信息

查看账户ID与访问端点endpoint

选择API->S3兼容API,点击创建API令牌。然后选择上面那一个。

  

创建成功,获得访问密钥ID机密访问密钥

注意复制下来,令牌值只显示一次,否则就只能刷新了。

访问密钥IDaccess-key机密访问密钥secret-key

为S3客户端使用管辖权地特定的终结点endpoint

五、在SpringBoot配置文件中配置,并编写工具类获取配置信息

选择yml配置时:

# Cloudflare R2 配置
cloud:
  aws:
    s3:
      endpoint: https://your-account-id.r2.cloudflarestorage.com   #访问端点
      bucket-name: your-bucket-name    #存储桶名
      cdn-domain: your-cdn-domain    #存储桶连接的域名
      region: auto    #区域
      credentials:    #访问凭证
        access-key: your-access-key    #访问秘钥ID
        secret-key: your-secret-key    #机密访问秘钥

选择properties配置时:

# Cloudflare R2 配置
cloud.aws.s3.endpoint=https://your-account-id.r2.cloudflarestorage.com    # 访问端点
cloud.aws.s3.bucket-name=your-bucket-name    # 存储桶名
cloud.aws.s3.cdn-domain=your-cdn-domain    # 存储桶连接的域名
cloud.aws.s3.region=auto    # 区域
cloud.aws.s3.credentials.access-key=your-access-key    # 访问秘钥ID
cloud.aws.s3.credentials.secret-key=your-secret-key    # 机密访问秘钥

不是中文域名的忽略此条。 

此处填写的cdn-domain没有中文域名和转码后的域名限制。

如果填写中文域名,访问资源时需要使用转码后的域名访问。

如果填写转码后的域名,上传后生成的资源URL可以直接访问。所以建议使用转码后的域名

 编写Util工具类获取配置中的参数:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@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;
    }
}

六、编写服务类,实现上传文件到CloudFlare R2的逻辑

import com.niit.util.R2FileUtils;    //替换为实际的util类路径
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.PutObjectRequest;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.regions.Region;

import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;
@Service
public class CloudFlareR2ServiceImpl {
    public String upload(MultipartFile file) throws IOException {
        //使用try-with, S3Client在使用完毕后需要自动关闭
        try(InputStream inputStream = file.getInputStream();
            S3Client client = S3Client.builder()
                .endpointOverride(URI.create(R2FileUtils.END_POINT))    //访问端点
                .credentialsProvider(() -> AwsBasicCredentials.create(R2FileUtils.ACCESS_KEY, R2FileUtils.SECRET_KEY))  //访问凭证
                .region(Region.of(R2FileUtils.REGION))  //地区
                .build()) {

            //获取当前日期, 利用当前日期构建对象键的路径, 如2025/05/27
            //实际路径可根据开发情况修改
            String date = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));

            //获取文件扩展名
            //获取上传文件的原始文件名, 即包含扩展名
            String originalFilename = file.getOriginalFilename();
            assert originalFilename != null;
            //获取源文件扩展名
            String fileExtension = originalFilename.substring(originalFilename.lastIndexOf("."));

            //构建对象键, 包含日期路径、使用UUID随机生成的文件名
            //实际文件名可根据开发情况修改
            String objectKey = date + "/" + UUID.randomUUID() + fileExtension;

            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(R2FileUtils.BUCKET_NAME)    //设置存储桶名称
                    .key(objectKey)     //设置对象键
                    .contentType(file.getContentType()) //设置内容类型
                    .build();
            //使用S3Client将文件上传到R2
            client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, file.getSize()));

            //返回上传后的文件访问URL
            return R2FileUtils.CDN_DOMAIN + "/" + objectKey;
        }catch (Exception e){
            //抛异常
            throw new IOException("文件上传失败"+e.getMessage());
        }
    }
}

七、调用与效果示例

在控制类中注入服务类,直接调用方法。

@Autowired
private CloudFlareR2ServiceImpl cloudFlareR2Service;

//在路径方法上使用, 上传到R2
String r2Url = cloudFlareR2Service.upload(photo);
//查看生成的路径, 可直接通过URL访问资源
System.out.println(r2Url);

以一个上传多用户信息的demo为例:

 

效果如图:

完成,可以直接通过URL访问你的资源了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值