阿里云文件上传oss存储

文档地址

https://help.aliyun.com/zh/oss/object-file-object/

创建存储空间(Bucket)

https://oss.console.aliyun.com/bucket

出于安全考虑,OSS 控制台默认开启阻止公共访问,仅支持创建私有权限的Bucket。

如需改为 公共读 或 公共读写,请按以下步骤操作:

  1. 单击目标Bucket名称进入该Bucket。

  2. 在左侧导航栏选择 权限控制 > 阻止公共访问,关闭该策略。

  3. 切换至 读写权限 页签,单击 设置。

  4. 按引导修改 Bucket 的读写权限为公共读或公共读写。

引入sdk

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.17.4</version>
</dependency>
如果使用的是Java 9及以上的版本,则需要添加以下JAXB相关依赖。
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

方法一:静态工具类

@Slf4j
public class OssFileUploaderUtil {
    private static final String accessKeyId = "xxxxxxx";
    private static final String accessKeySecret = "xxxxxxxxx";

    // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
    private static final String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    private static final String bucketName = "work";
    // 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
    private static final String region = "cn-hangzhou";
    private final boolean isPublicBucket = false; // 是否为公开Bucket(影响下载链接生成方式)


    /**
     * 上传字节流到OSS并返回下载链接
     * @param fileBytes 文件字节数组(如Excel模板的字节流)
     * @param fileName 文件名(含扩展名,如:用户模板_20250910.xlsx)
     * @param fileDir OSS存储目录(如:user/templates/,末尾需带斜杠)
     * @param contentType 文件MIME类型(如:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
     * @return 可直接访问的下载链接
     * @throws IOException 流处理异常
     */
    public static String upload(byte[] fileBytes, String fileName, String fileDir, String contentType) throws IOException {
        // 1. 构建OSS文件完整路径(目录+文件名)
        String objectPath = fileDir + fileName;
        log.info("开始上传文件到OSS,路径:{}", objectPath);

        OSS ossClient = null;
        ByteArrayInputStream inputStream = null;
        try {
            // 2. 初始化OSS客户端
            DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
            ClientBuilderConfiguration clientConfig = new ClientBuilderConfiguration();
            clientConfig.setSignatureVersion(SignVersion.V4); // 使用V4签名算法
            ossClient = OSSClientBuilder.create()
                    .endpoint(endpoint)
                    .credentialsProvider(credentialProvider)
                    .clientConfiguration(clientConfig)
                    .region(region)
                    .build();

            // 3. 配置文件元数据
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType(contentType); // 关键:指定文件类型,避免下载异常
            metadata.setContentLength(fileBytes.length); // 设置文件大小
            metadata.setContentEncoding("UTF-8");

            // 4. 上传文件流
            inputStream = new ByteArrayInputStream(fileBytes);
            PutObjectRequest putRequest = new PutObjectRequest(bucketName, objectPath, inputStream, metadata);
            ossClient.putObject(putRequest);
            log.info("文件上传OSS成功,路径:{}", objectPath);

            // 5. 生成下载链接
            return generateDownloadUrl(objectPath, ossClient);

        } catch (OSSException e) {
            log.error("OSS上传失败!错误码:{},请求ID:{}", e.getErrorCode(), e.getRequestId(), e);
            throw new RuntimeException("文件上传OSS失败:" + e.getMessage(), e);
        } finally {
            // 6. 释放资源
            if (inputStream != null) {
                inputStream.close();
            }
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }

    /**
     * 生成文件下载链接
     * @param objectPath OSS上的文件完整路径(如:user/templates/用户模板.xlsx)
     * @return 下载链接(公开Bucket返回永久链接,私有Bucket返回带签名的临时链接)
     */
    private static String generateDownloadUrl(String objectPath, Oss ossClient) {
        try {
            // 编码文件名(处理中文/特殊字符)
            String encodedPath = URLEncoder.encode(objectPath, StandardCharsets.UTF_8.name())
                    .replaceAll("\\+", "%20");

            if (isPublicBucket) {
                // 公开Bucket:直接拼接HTTP URL
                String endpointHost = endpoint.replace("https://", "");
                String fileUrl = String.format("https://%s.%s/%s", bucketName, endpointHost, encodedPath);
                log.info("文件地址:{}", fileUrl);
                return fileUrl;
            } else {
                // 私有Bucket:生成带签名的临时URL(有效期1小时)
                Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
                return ossClient.generatePresignedUrl(bucketName, objectPath, expiration).toString();
            }
        } catch (Exception e) {
            log.error("生成下载链接失败", e);
            throw new RuntimeException("生成文件下载链接失败", e);
        }
    }

}

方法二:spring管理上述方法需要自动注入OSS

application.yml或者bootstrap.yml对应的nacos

# application.yml
aliyun:
  oss:
    access-key-id: xxx
    access-key-secret: xxx
    endpoint: https://oss-cn-shanghai.aliyuncs.com
    bucket-name: work
    region: cn-shanghai
    is-public-bucket: false

OssConfig配置


@Data
@Configuration
@ConfigurationProperties(prefix = "aliyun.oss")
public class OSSConfig {

    // 从配置文件注入参数
    private String accessKeyId;
    private String accessKeySecret;
    private String endpoint;
    private String bucketName;
    private String region;
    private boolean isPublicBucket;

    // 单例OSS客户端(全局唯一实例)
    private OSS ossClient;

    /**
     * 初始化OSS客户端(服务启动时执行,创建一次)
     */
    @Bean
    public OSS ossClient() {
        // 配置客户端参数
        DefaultCredentialProvider credentialProvider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
        ClientBuilderConfiguration clientConfig = new ClientBuilderConfiguration();
        clientConfig.setSignatureVersion(SignVersion.V4); // 使用V4签名

        // 创建客户端实例(单例,由Spring管理)
        ossClient = OSSClientBuilder.create()
                .endpoint(endpoint)
                .credentialsProvider(credentialProvider)
                .clientConfiguration(clientConfig)
                .region(region)
                .build();

        System.out.println("OSS客户端初始化完成(单例模式)");
        return ossClient;
    }

    /**
     * 服务停止时自动关闭OSS客户端(@PreDestroy确保Spring销毁Bean时执行)
     */
    @PreDestroy
    public void shutdownOssClient() {
        if (ossClient != null) {
            ossClient.shutdown();
            System.out.println("服务停止,OSS客户端已关闭");
        }
    }
}

 调用

  @Autowired
    private OSS ossClient;
    @Autowired
    private OSSConfig ossConfig;

    /**
     * 上传字节流到OSS并返回下载链接
     * @param fileBytes 文件字节数组(如Excel模板的字节流)
     * @param fileName 文件名(含扩展名,如:用户信息模板_20250910.xlsx)
     * @param fileDir OSS存储目录(如:user/templates/,末尾需带斜杠)
     * @param contentType 文件MIME类型(如:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet)
     * @return 可直接访问的下载链接
     * @throws IOException 流处理异常
     */
    public String upload(byte[] fileBytes, String fileName, String fileDir, String contentType) throws IOException {
        // 1. 构建OSS文件完整路径(目录+文件名)
        String objectPath = fileDir + fileName;
        log.info("开始上传文件到OSS,路径:{}/{}", ossConfig.getBucketName(), objectPath);
        log.info("配置信息:ossConfig:{}",ossConfig );
        ObjectMetadata metadata = new ObjectMetadata();
        metadata.setContentType(contentType); // 关键:指定文件类型,避免下载异常
        metadata.setContentLength(fileBytes.length); // 设置文件大小
        metadata.setContentEncoding("UTF-8");

        try (ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBytes)){
            PutObjectRequest putRequest = new PutObjectRequest(ossConfig.getBucketName(), objectPath, inputStream, metadata);
            ossClient.putObject(putRequest);
            log.info("文件上传OSS成功,路径:{}", objectPath);
            return generateDownloadUrl(objectPath);
        } catch (OSSException e) {
            log.error("OSS上传失败!错误码:{},请求ID:{}", e.getErrorCode(), e.getRequestId(), e);
            throw new RuntimeException("文件上传OSS失败:" + e.getMessage(), e);
        }
    }

    /**
     * 生成文件下载链接
     * @param objectPath OSS上的文件完整路径(如:user/templates/用户模板.xlsx)
     * @return 下载链接(公开Bucket返回永久链接,私有Bucket返回带签名的临时链接)
     */
    private String generateDownloadUrl(String objectPath) {
        try {
            // 编码文件名(处理中文/特殊字符)
            String encodedPath = URLEncoder.encode(objectPath, StandardCharsets.UTF_8.name())
                    .replaceAll("\\+", "%20");

            if (ossConfig.getIsPublicBucket()) {
                // 公开Bucket:直接拼接HTTP URL
                String endpointHost = ossConfig.getEndpoint().replace("https://", "");
                String fileUrl = String.format("https://%s.%s/%s", ossConfig.getBucketName(), endpointHost, encodedPath);
                log.info("文件地址:{}", fileUrl);
                return fileUrl;
            } else {
                // 私有Bucket:生成带签名的临时URL(有效期1小时)
                Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
                return ossClient.generatePresignedUrl(ossConfig.getBucketName(), objectPath, expiration).toString();
            }
        } catch (Exception e) {
            log.error("生成下载链接失败", e);
            throw new RuntimeException("生成文件下载链接失败", e);
        }
    }

 

posted @ 2025-09-09 15:45  白玉神驹  阅读(36)  评论(0)    收藏  举报