介绍

OSS:阿里云分布式文件系统

网址:OSS控制台

作用

如果在应用程序所在服务器上做文件上传与下载会给服务器造成很大压力,所以项目会使用独立的文件系统。

业务

用户头像功能

  • 文件上传:用户上传头像
  • 文件删除:用户上传了新头像之后,删除旧的头像
  • 文件下载:用户头像下载到本地

OSS控制台

创建Bucket(存储空间)

一个Bucket相当于一个文件系统服务器(可以理解为一个Nacos的namespace)

读写权限

  • 公共读:读不需要权限控制,写操作需要权限控制
  • 公共读写:读不需要权限控制,写不操作需要权限控制
  • 私有:读写都需要权限

上传文件到Bucket

获取图片的URL,在浏览器输入URL可以访问并下载图片

创建用户

ios OC OSS 上传 oss文件上传下载_System

ios OC OSS 上传 oss文件上传下载_阿里云_02

给用户添加OSS的权限

ios OC OSS 上传 oss文件上传下载_System_03

获取AccessKey ID和AccessKey Secret

ios OC OSS 上传 oss文件上传下载_spring_04

建议下载CSV文件,点击确定之后将无法查看AccessKey Secret

获取endPoint

获取endPoint:访问域名和数据中心

Java API使用

Java API文档:Java API文档地址

导入依赖(安装SDK)

SDK:是软件开发工具包的意思

<!--aliyun分布式文件系统OSS-->
 <dependency>
     <groupId>com.aliyun.oss</groupId>
     <artifactId>aliyun-sdk-oss</artifactId>
     <version>3.10.2</version>
 </dependency>

配置文件

aliyun:
   oss:
     endpoint: oss-cn-qingdao.aliyuncs.com
     keyId: ******
     keySecret: ********
     bucketName: lixianhe
     module: avatar

配置类

把配置文件中的内容赋值给静态变量

import lombok.Getter;
 import lombok.Setter;
 import org.springframework.beans.factory.InitializingBean;
 import org.springframework.boot.context.properties.ConfigurationProperties;
 import org.springframework.stereotype.Component;
 
 @Setter
 @Getter
 @Component
 @ConfigurationProperties(prefix = "aliyun.oss")
 public class OssConfig implements InitializingBean {
     private String endpoint;
     private String keyId;
     private String keySecret;
     private String bucketName;
     private String module;

     public static String ENDPOINT;
     public static String KEY_ID;
     public static String KEY_SECRET;
     public static String BUCKET_NAME;
     public static String MODULE;

 
     //当私有成员被赋值后,此方法自动被调用,从而初始化常量
     @Override
     public void afterPropertiesSet() throws Exception {
         ENDPOINT = endpoint;
         KEY_ID = keyId;
         KEY_SECRET = keySecret;
         BUCKET_NAME = bucketName;
         MODULE = module;
     }
 }

文件上传

返回文件在Oss的url

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.event.ProgressEvent;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.PutObjectRequest;
import com.lixianhe.config.OssProperties;
import com.lixianhe.result.R;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;

// 使用进度条,需要实现ProgressListener方法
@RestController
@RequestMapping("/api/oss/file")
public class PutObjectProgressListenerDemo implements ProgressListener {
    private long bytesWritten = 0;
    private long totalBytes = -1;

    @PostMapping("/upload")
    public R uploadFile(@RequestParam("file") MultipartFile file, @RequestParam String username) throws IOException {

        // 创建OSSClient实例(OSS客户端实例)
        OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
                OssProperties.KEY_ID, OssProperties.KEY_SECRET);

        // 获取选择文件的输入流
        InputStream inputStream = file.getInputStream();

        // 获取文件名称
        String originalFilename = file.getOriginalFilename();

        // 拼接Oss中文件的路径
        String objectName = OssProperties.MODULE + "/" + originalFilename;

        // 判断文件上传是否成功
        boolean uploadSucceed = false;

        try {
            // 上传文件的同时指定进度条参数。此处PutObjectProgressListenerDemo为调用类的类名,请在实际使用时替换为相应的类名。
            ossClient.putObject(new PutObjectRequest(OssProperties.BUCKET_NAME, objectName, inputStream).
                    withProgressListener(new PutObjectProgressListenerDemo()));

            uploadSucceed = true;
        } 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();
            }
        }
        if (uploadSucceed) {
            return R.ok().message("上传成功").data("URL", "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/" + objectName);
        } else {
            return R.error().message("上传失败");
        }
    }

    // 使用进度条需要您重写回调方法,以下仅为参考示例。
    @Override
    public void progressChanged(ProgressEvent progressEvent) {
        long bytes = progressEvent.getBytes();
        ProgressEventType eventType = progressEvent.getEventType();
        switch (eventType) {
            case TRANSFER_STARTED_EVENT:
                System.out.println("Start to upload......");
                break;
            case REQUEST_CONTENT_LENGTH_EVENT:
                this.totalBytes = bytes;
                System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
                break;
            case REQUEST_BYTE_TRANSFER_EVENT:
                this.bytesWritten += bytes;
                if (this.totalBytes != -1) {
                    int percent = (int) (this.bytesWritten * 100.0 / this.totalBytes);
                    System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
                } else {
                    System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
                }
                break;
            case TRANSFER_COMPLETED_EVENT:
                System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
                break;
            case TRANSFER_FAILED_EVENT:
                System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
                break;
            default:
                break;
        }
    }
}

注意:要想重定向访问到文件资源下载链接要在oss工作台配置bucket跨域

ios OC OSS 上传 oss文件上传下载_ios OC OSS 上传_05

文件删除

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.lixianhe.config.OssProperties;
import com.lixianhe.result.R;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api/oss/file")
public class DeleteFile {

    @DeleteMapping("/del")
    public R deleteFile(@RequestParam String url) {
        // 创建OSSClient实例(OSS客户端实例)
        OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
                OssProperties.KEY_ID, OssProperties.KEY_SECRET);

        //文件名(服务器上的文件路径)
        String host = "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/";
        String objectName = url.substring(host.length());

        // 判断是否删除成功
        boolean deleteFileSucceed = false;

        try {
            // 删除文件或目录。如果要删除目录,目录必须为空。
            ossClient.deleteObject(OssProperties.BUCKET_NAME, objectName);

            deleteFileSucceed = true;
        } 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();
            }
        }

        if (deleteFileSucceed) {
            return R.ok().message("删除成功");
        } else {
            return R.error().message("删除失败");
        }
    }
}

文件下载

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.event.ProgressEvent;
import com.aliyun.oss.event.ProgressEventType;
import com.aliyun.oss.event.ProgressListener;
import com.aliyun.oss.model.GetObjectRequest;
import com.lixianhe.config.OssProperties;
import com.lixianhe.result.R;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.util.Map;

@RestController
@RequestMapping("/api/oss/file")
public class GetObjectProgressListener implements ProgressListener {
    private long bytesRead = 0;
    private long totalBytes = -1;

    @PostMapping("/download")
    public R downloadFile(@RequestBody Map<String, Object> map) {
        // 获取用户名
        String username = (String) map.get("username");

        // 创建OSSClient实例(OSS客户端实例)
        OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
                OssProperties.KEY_ID, OssProperties.KEY_SECRET);
        // 拼接文件名称
        String fileName = username + ".webp";

        // 拼接oss中文件的路径avatar/lixianhe.webp
        String objectName = OssProperties.MODULE + "/" + fileName;
        // 目标文件下载位置
        String pathName = "C:\\Users\\Administrator\\Downloads\\" + fileName;

        // 下载是否成功
        boolean downloadIsSucceed = false;

        try {
            // 下载文件的同时指定了进度条参数。
            ossClient.getObject(new GetObjectRequest(OssProperties.BUCKET_NAME, objectName).
                    withProgressListener(new GetObjectProgressListener()), new File(pathName));
            downloadIsSucceed = true;
        } 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();
            }
        }

        if (downloadIsSucceed) {
            return R.ok().message("下载成功");
        } else {
            return R.error().message("下载失败");
        }
    }

    @Override
    public void progressChanged(ProgressEvent progressEvent) {
        long bytes = progressEvent.getBytes();
        ProgressEventType eventType = progressEvent.getEventType();
        switch (eventType) {
            case TRANSFER_STARTED_EVENT:
                System.out.println("Start to download......");
                break;
            case RESPONSE_CONTENT_LENGTH_EVENT:
                this.totalBytes = bytes;
                System.out.println(this.totalBytes + " bytes in total will be downloaded to a local file");
                break;
            case RESPONSE_BYTE_TRANSFER_EVENT:
                this.bytesRead += bytes;
                if (this.totalBytes != -1) {
                    int percent = (int) (this.bytesRead * 100.0 / this.totalBytes);
                    System.out.println(bytes + " bytes have been read at this time, download progress: " +
                            percent + "%(" + this.bytesRead + "/" + this.totalBytes + ")");
                } else {
                    System.out.println(bytes + " bytes have been read at this time, download ratio: unknown" +
                            "(" + this.bytesRead + "/...)");
                }
                break;
            case TRANSFER_COMPLETED_EVENT:
                System.out.println("Succeed to download, " + this.bytesRead + " bytes have been transferred in total");
                break;
            case TRANSFER_FAILED_EVENT:
                System.out.println("Failed to download, " + this.bytesRead + " bytes have been transferred");
                break;
            default:
                break;
        }
    }
}

测试

上传文件测试

ios OC OSS 上传 oss文件上传下载_spring_06

删除文件测试

ios OC OSS 上传 oss文件上传下载_阿里云_07

 下载文件测试

ios OC OSS 上传 oss文件上传下载_System_08