文章目录

  • 前言
  • 一、初步阶段
  • 1.1、认识OSS服务与开通OSS服务(创建Bucket、配置用户权限以及允许跨域)
  • 1.2、起步demo:GetStartedSample(上传、删除案例)
  • 二、实战系列
  • 2.1、上传文件-简单上传
  • 2.2、集成OSS的SDK包及封装阿里云OSS存储服务(上传、删除功能,含源码)
  • 2.3、集成SpringCloud-Alibaba-OSS
  • 环境依赖配置
  • 2.3.1、实现普通上传
  • 2.3.2、获取服务端签名(web端来实现上传功能)
  • 注意点
  • 参考资料

前言

学习文档:

学习视频:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot


一、初步阶段

1.1、认识OSS服务与开通OSS服务(创建Bucket、配置用户权限以及允许跨域)

阿里云开通OSS存储服务可见我的博客:阿里云开通OSS存储服务详细流程

2022.11.11编辑最新流程文档:创建Bucket、配置用户权限以及允许跨域

若是我们仅仅用来自己项目测试的话可以按照下面的来进行创建:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_java_02

记住要为对应的bucket设置对应的用户权限:对于创建子用户操作见我上面的文章链接跟着走一遍就行!

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_System_03

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_04

配置跨域请求:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_java_05

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_上传_06


1.2、起步demo:GetStartedSample(上传、删除案例)

首先来到官方文档:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot_07

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_08

依赖:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.14.0</version>
</dependency>

代码:已调试其中的带中文注释

package com.changlu.test.common;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;

/**
 * This sample demonstrates how to get started with basic requests to Aliyun OSS 
 * using the OSS SDK for Java.
 */
public class GetStartedSample {
    
    private static String endpoint = "";
    private static String accessKeyId = "";
    private static String accessKeySecret = "";
//    private static String bucketName = "pictured-bed";
    private static String bucketName = "";
    private static String key = "test/test2/";//若是目录,一定要设置/

    //方便之后拼接
    private static String shortEndpoint = "oss-cn-beijing.aliyuncs.com";
    
    public static void main(String[] args) throws IOException {
        /*
         * Constructs a client instance with your account for accessing OSS
         */
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        
        System.out.println("Getting Started with OSS SDK for Java\n");
        
        try {

//            /*
//             * Determine whether the bucket exists 查看桶是否存在
//             */
//            if (!ossClient.doesBucketExist(bucketName)) {  //创建桶
//                /*
//                 * Create a new OSS bucket
//                 */
//                System.out.println("Creating bucket " + bucketName + "\n");
//                ossClient.createBucket(bucketName);//根据当前的认证信息来进行创建Bucket桶,默认是私有
//                CreateBucketRequest createBucketRequest= new CreateBucketRequest(bucketName);
//                createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);//设置读写权限为公开读
//                ossClient.createBucket(createBucketRequest);//来
//            }

            /*
             * List the buckets in your account:获取所有的桶名称
             */
//            System.out.println("Listing buckets");
//
//            ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
//            listBucketsRequest.setMaxKeys(500);
//
//            for (Bucket bucket : ossClient.listBuckets()) { //发起请求
//                System.out.println(" - " + bucket.getName());
//            }
//            System.out.println();
//
            /*
             * 上传文件
             * Upload an object to your bucket:上传对象到你的桶中
             */
//            System.out.println("Uploading a new object to OSS from a file\n");
//            File file = new File("C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png");
//            String saveFilePath = key + file.getName();//拼接目标路径 + 图片名称
//            //第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录
//            //第三个参数为:文件对象
//            ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , file));
//            //拼接获取公共访问地址
//            String publicVisitPath = "http://" + bucketName + '.' +  shortEndpoint + "/" + saveFilePath;
//            System.out.println("访问路径:" + publicVisitPath);
//
//            /*
//             * 删除文件
//             * Delete an object:删除对象
//             */
            System.out.println("Deleting an object\n");
            File file = new File("C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png");
            String saveFilePath = key + file.getName();//拼接目标路径 + 图片名称
            ossClient.deleteObject(bucketName, saveFilePath);

//            /*
//             * Determine whether an object residents in your bucket:判断对象是否存在你的桶
//             */
//            boolean exists = ossClient.doesObjectExist(bucketName, key);
//            System.out.println("Does object " + bucketName + " exist? " + exists + "\n");
//
//            ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.PublicRead);
//            ossClient.setObjectAcl(bucketName, key, CannedAccessControlList.Default);
//
//            ObjectAcl objectAcl = ossClient.getObjectAcl(bucketName, key);
//            System.out.println("ACL:" + objectAcl.getPermission().toString());
//
//            /*
//             * Download an object from your bucket
//             */
//            System.out.println("Downloading an object");
//            OSSObject object = ossClient.getObject(bucketName, key);
//            System.out.println("Content-Type: "  + object.getObjectMetadata().getContentType());
//            displayTextInputStream(object.getObjectContent());
//
//            /*
//             * List objects in your bucket by prefix
//             */
//            System.out.println("Listing objects");
//            ObjectListing objectListing = ossClient.listObjects(bucketName, "My");
//            for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
//                System.out.println(" - " + objectSummary.getKey() + "  " +
//                                   "(size = " + objectSummary.getSize() + ")");
//            }
//            System.out.println();
//

            
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message: " + oe.getErrorMessage());
            System.out.println("Error Code:       " + oe.getErrorCode());
            System.out.println("Request ID:      " + oe.getRequestId());
            System.out.println("Host ID:           " + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message: " + ce.getMessage());
        } finally {
            /*
             * Do not forget to shut down the client finally to release all allocated resources.
             */
            ossClient.shutdown();
        }
    }
    
    private static File createSampleFile() throws IOException {
        File file = File.createTempFile("oss-java-sdk-", ".txt");
        file.deleteOnExit();

        Writer writer = new OutputStreamWriter(new FileOutputStream(file));
        writer.write("abcdefghijklmnopqrstuvwxyz\n");
        writer.write("0123456789011234567890\n");
        writer.close();

        return file;
    }

    private static void displayTextInputStream(InputStream input) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(input));
        while (true) {
            String line = reader.readLine();
            if (line == null) break;

            System.out.println("    " + line);
        }
        System.out.println();
        
        reader.close();
    }

}

二、实战系列

2.1、上传文件-简单上传

配套代码:AliyunOss-SDK—GiteeAliyunOss-SDK—Github

文档可见官网有对应不同功能的代码示例:简单上传文档

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot_09

测试其中的上传文件流:直接复制的上面文件流的示例代码,然后去修改一下配置信息即可

package com.changlu;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import java.io.FileInputStream;
import java.io.InputStream;

public class Demo {

    public static void main(String[] args) throws Exception {
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "";
        // 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
        String accessKeyId = "";
        String accessKeySecret = "";
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "2.png";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png";

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        try {
            InputStream inputStream = new FileInputStream(filePath);            
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_上传_10

若是你的配置没有问题,程序不会报任何代码错误!

接下来检查一下对应阿里云的bucket文件列表是否有对应的文件:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_11

2.2、集成OSS的SDK包及封装阿里云OSS存储服务(上传、删除功能,含源码)

配套代码:AliyunOssService-GiteeAliyunOssService-Github

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_12

上传、删除方法已经封装到Utils中,controller只需要调用工具类的上传、删除即可!

application.yml:

# 图片文件上传
spring:
  servlet:
    multipart:
      max-file-size: 100MB
      max-request-size: 1000MB

# 阿里云OSS配置
aliyun:
  oss:
    endpoint:   # 坐标地区示例:oss-cn-beijing.aliyuncs.com
    accessKeyId:  # 注册用户的keyID
    accessKeySecret:   # 注册用户的密钥
    bucketName:   # 桶名称 示例:pictured-st
    key:     # 存储根路径,例如:img/,以目录形式为结尾,之后图片会自动生成并添加到后缀
package com.changlu.config;

import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @ClassName AliyunOssConfig
 * @Author ChangLu
 * @Date 3/26/2022 4:22 PM
 * @Description 阿里云OOS配置
 */
@Component
// 指定配置文件中自定义属性前缀
@ConfigurationProperties(prefix = "aliyun.oss")
@Data
@ToString
public class AliyunOssConfig {

    private String endpoint;
    private String accessKeyId;
    private String accessKeySecret;
    private String bucketName;
    private String key;

}
package com.changlu.controller;

import com.changlu.domain.ResponseResult;
import com.changlu.utils.AliyunOssUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.HashMap;
import java.util.Map;

/**
 * @ClassName UploadController
 * @Author ChangLu
 * @Date 3/26/2022 5:23 PM
 * @Description Oss文件控制器
 */
@RestController
public class OssFileController {

    @Autowired
    private AliyunOssUtil aliOssUtil;

    /**
     * 上传图片
     * @param file
     * @return
     */
    @PostMapping("/upload")
    public ResponseResult uploadFile(@RequestParam("file")MultipartFile file){
       try {
           String visitUrl = aliOssUtil.uploadFile(file);
           Map<String,String> result = new HashMap<>(1);
           result.put("visitUrl", visitUrl);
           return new ResponseResult(200,"上传成功!", result);
       }catch (Exception e){
           e.printStackTrace();
           return new ResponseResult(500,"上传失败!");
       }
    }

    /**
     * 删除图片
     * @param fileName 文件名称如:b8809d28-82ec-4b06-af5f-8d3d7a16107c.jpg
     * @return
     */
    @GetMapping("/deleFile/{fileName}")
    public ResponseResult deleteFile(@PathVariable("fileName")String fileName){
        try {
            aliOssUtil.deleteFile(fileName);
            return new ResponseResult(200,"删除成功!");
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseResult(500,"删除失败!");
        }
    }

}
import com.fasterxml.jackson.annotation.JsonInclude;

/**
 * @Author changlu
 */
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ResponseResult<T> {
    /**
     * 状态码
     */
    private Integer code;
    /**
     * 提示信息,如果有错误时,前端可以获取该字段进行提示
     */
    private String msg;
    /**
     * 查询到的结果数据,
     */
    private T data;

    public ResponseResult(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }

    public ResponseResult(Integer code, T data) {
        this.code = code;
        this.data = data;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public ResponseResult(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}
package com.changlu.utils;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.changlu.config.AliyunOssConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.InputStream;
import java.util.UUID;

/**
 * @ClassName AliyunOssUtil
 * @Author ChangLu
 * @Date 3/26/2022 4:51 PM
 * @Description OSS对象存储工具类
 */
@Component
public class AliyunOssUtil {

    @Autowired
    private AliyunOssConfig aliyunOssConfig;

    /**
     * 创建一个OSS连接
     * @return OssClient
     */
    private OSS createOssClient(){
        String endpoint = "http://" + aliyunOssConfig.getEndpoint();
        String accessKeyId = aliyunOssConfig.getAccessKeyId();
        String accessKeySecret = aliyunOssConfig.getAccessKeySecret();
        return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    }

    /**
     * 关闭连接
     * @param ossClient
     */
    private void close(OSS ossClient){
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }

    /**
     * 上传文件
     * @param file File类型
     * @return
     */
    public String uploadFile(File file){
        String key = aliyunOssConfig.getKey();
        String bucketName = aliyunOssConfig.getBucketName();
        String endpoint = aliyunOssConfig.getEndpoint();
        //1、取得保存文件路径saveFilePath:拼接目标路径 + 图片名称
        String originFileName = file.getName();
        String filePrefix = UUID.randomUUID().toString();
        String saveFileName = filePrefix + originFileName.substring(file.getName().indexOf("."));
        String saveFilePath = key + saveFileName;
        OSS ossClient = null;
        try {
            ossClient = createOssClient();
            //2、上传文件
            //第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录
            //第三个参数为:文件对象
            ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , file));
        }catch (Exception e){
            e.printStackTrace();
            return null;
        }finally {
            this.close(ossClient);
        }
        //3、拼接获取公共访问地址
        String publicVisitPath = "http://" + bucketName + '.' +  endpoint + "/" + saveFilePath;
        return publicVisitPath;
    }

    /**
     * 上传文件
     * @param file MultipartFile类型
     * @return
     */
    public String uploadFile(MultipartFile file)throws Exception{
        String key = aliyunOssConfig.getKey();
        String bucketName = aliyunOssConfig.getBucketName();
        String endpoint = aliyunOssConfig.getEndpoint();
        //1、取得保存文件路径saveFilePath:拼接目标路径 + 图片名称
        String originFileName = file.getOriginalFilename();
        String filePrefix = UUID.randomUUID().toString();
        String saveFileName = filePrefix + originFileName.substring(originFileName.indexOf("."));
        String saveFilePath = key + saveFileName;
        OSS ossClient = null;
        try {
            ossClient = createOssClient();
            //2、上传文件
            //第一个参数为:桶的名称;第二个参数为路径+上你的文件名,如test/1.png,若是test/test2/1.png,也会给我们自动创建目录
            //第三个参数为:文件对象
            /**
             * 阿里云OSS 默认图片上传ContentType是image/jpeg
             * 图片链接后,图片是下载链接,而并非在线浏览链接
             * 这里在上传的时候要解决ContentType的问题,将其改为image/jpg
             */
            InputStream is = file.getInputStream();
            ObjectMetadata meta = new ObjectMetadata();
            meta.setContentType("image/jpg");
            ossClient.putObject(new PutObjectRequest(bucketName,saveFilePath , is, meta));
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            this.close(ossClient);
        }
        //3、拼接获取公共访问地址
        String publicVisitPath = "http://" + bucketName + '.' +  endpoint + "/" + saveFilePath;
        return publicVisitPath;
    }


    /**
     * 删除文件
     * @param fileName 待删除的文件名
     * @return
     */
    public void deleteFile(String fileName)throws Exception{
        String key = aliyunOssConfig.getKey();
        String bucketName = aliyunOssConfig.getBucketName();
        //1、拼接待删除路径
        String deleteFilePath = key + fileName;
        OSS ossClient = null;
        try {
            ossClient = createOssClient();
            //2、删除文件
            ossClient.deleteObject(bucketName, deleteFilePath);
        }catch (Exception e){
            throw new RuntimeException(e);
        }finally {
            this.close(ossClient);
        }
    }

}

2.3、集成SpringCloud-Alibaba-OSS

环境依赖配置

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_13

pom.xml:三个版本依次为springboot2.1.8springcloud Greenwich.SR3SpringCloud Alibaba2.1.0.RELEASE

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.8.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <java.version>1.8</java.version>
    <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
    </dependency>
</dependencies>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
        </plugin>
    </plugins>
</build>

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>2.1.0.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

2.3.1、实现普通上传

配套代码:springcloud-alibaba-oss-Giteespringcloud-alibaba-oss-Github

server:
  port: 8888
spring:
  cloud:
    alicloud:
      access-key: 
      secret-key: 
      oss:
        endpoint: 
        # 这是自定义的,需要自己来去读取
        bucketname:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_System_14

接着对应demo写在了test的示例中:下面黄色框的就是我们需要自己额外编写的,其他的上传操作和之前的普通上传基本一致

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot_15

package com.changlu;

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;

/**
 * @Description:
 * @Author: changlu
 * @Date: 5:44 PM
 */

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringCloudOSSApplicationTest {

    @Autowired
    private OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.bucketname}")
    private String bucketName;

    //普通上传文件服务
    @Test
    public void test() {
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "4.png";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "C:\\Users\\93997\\Desktop\\桌面壁纸\\1.png";
        try {
            InputStream inputStream = new FileInputStream(filePath);
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, inputStream);
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ossClient != null) {
                ossClient.shutdown();
            }
        }
    }
}

运行一下,若是没有任何报错信息的话,那么此时说就说上传成功:

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_System_16

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot_17


2.3.2、获取服务端签名(web端来实现上传功能)

后端代码

配套代码:springcloud-alibaba-oss-Giteespringcloud-alibaba-oss-Github

文档地址:最佳实践-web端上传数据至OSS-服务器端直传并设置上传回调

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_spring boot_18

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.8.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.changlu</groupId>
    <artifactId>springcloud-alibaba-oss</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springcloud-alibaba-oss</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.1.0.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

application.yml

server:
  port: 8888
spring:
  cloud:
    alicloud:
      access-key: 
      secret-key: 
      oss:
        endpoint: 
        # 这是自定义的,需要自己来去读取
        bucketname:

R.java:统一封装响应类

package com.changlu.utils;

import java.util.HashMap;
import java.util.Map;

/**
 * 返回数据
 * 
 * @author chenshun
 * @email sunlightcs@gmail.com
 * @date 2016年10月27日 下午9:59:27
 */
public class R extends HashMap<String, Object> {
	private static final long serialVersionUID = 1L;
	
	public R() {
		put("code", 0);
		put("msg", "success");
	}
	
	public static R error() {
		return error(500, "未知异常,请联系管理员");
	}
	
	public static R error(String msg) {
		return error(500, msg);
	}
	
	public static R error(int code, String msg) {
		R r = new R();
		r.put("code", code);
		r.put("msg", msg);
		return r;
	}

	public static R ok(String msg) {
		R r = new R();
		r.put("msg", msg);
		return r;
	}
	
	public static R ok(Map<String, Object> map) {
		R r = new R();
		r.putAll(map);
		return r;
	}
	
	public static R ok() {
		return new R();
	}

	public R put(String key, Object value) {
		super.put(key, value);
		return this;
	}
}

OssController.java:提供获取签名服务

package com.changlu.controller;

import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.changlu.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @Description:
 * @Author: changlu
 * @Date: 7:03 PM
 */
@RestController
public class OssController {

    @Autowired
    private OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.bucketname}")
    private String bucketName;

    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;

    @RequestMapping("/oss/policy")
    public R policy() {
        // 填写Host地址,格式为https://bucketname.endpoint。
        String host = "https://" + bucketName + "." + endpoint;
        String dirName = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        // 设置上传到OSS文件的前缀,可置空此项。置空后,文件将上传至Bucket的根目录下。
        String dir = dirName + "/";

        Map<String, String> respMap = null;
        try {
            long expireTime = 30;
            long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
            Date expiration = new Date(expireEndTime);
            PolicyConditions policyConds = new PolicyConditions();
            policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
            policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);
            //生成签名
            String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
            byte[] binaryData = postPolicy.getBytes("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            respMap = new LinkedHashMap<String, String>();
            respMap.put("accessid", accessId);
            respMap.put("policy", encodedPolicy);
            respMap.put("signature", postSignature);
            respMap.put("dir", dir);
            respMap.put("host", host);
            respMap.put("expire", String.valueOf(expireEndTime / 1000));
        } catch (Exception e) {
            // Assert.fail(e.getMessage());
            System.out.println(e.getMessage());
        }
        return R.ok().put("data", respMap);
    }

}

测试下:成功获取

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_上传_19

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_java_20

前端代码

这里组件源代码可以直接可以查看谷粒商城博客笔记:谷粒商城-基础篇(详细流程梳理+代码)

SpringBoot集成阿里云OSS存储服务(普通上传、服务端签名上传)_阿里云_21

这里面包含了组件源代码以及实际引入项目并使用的前端案例。

注意点

1、每次使用完OSSClient后要进行关闭,ossClient.shutdown()。

OSSClient不关闭,导致大量FullGC

2、可不可以设置OSSClient为单例?

  • new OSSClient只是初始化一堆对象,并未建立长连接,如果你endpoint和权限是固定的,定义成static变量都行,只有在有实际操作时,才会httpClient.execute(),我每次都new这个客户端,是因为包装sdk给业务用时,CredentialsProvider这个是动态的
  • 建议在方法中创建OSSClient 而不是使用@Bean注入,不然容易出现Connection pool shut down。

参考资料

[1] 一小时学会使用springboot操作阿里云OSS实现文件上传,下载,删除(附源码)

[2] SpringBoot整合阿里云OSS