• 阿里云分布式文件系统OSS实现文件上传与下载


    介绍

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

    网址:OSS控制台

    作用

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

    业务

    用户头像功能

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

    OSS控制台

    创建Bucket(存储空间)

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

    读写权限

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

    上传文件到Bucket

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

    创建用户

    给用户添加OSS的权限

    获取AccessKey ID和AccessKey Secret

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

    获取endPoint

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

    Java API使用

    Java API文档:Java API文档地址

    导入依赖(安装SDK)

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

    1. <dependency>
    2. <groupId>com.aliyun.ossgroupId>
    3. <artifactId>aliyun-sdk-ossartifactId>
    4. <version>3.10.2version>
    5. dependency>

    配置文件

    1. aliyun:
    2. oss:
    3. endpoint: oss-cn-qingdao.aliyuncs.com
    4. keyId: ******
    5. keySecret: ********
    6. bucketName: lixianhe
    7. module: avatar

    配置类

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

    1. import lombok.Getter;
    2. import lombok.Setter;
    3. import org.springframework.beans.factory.InitializingBean;
    4. import org.springframework.boot.context.properties.ConfigurationProperties;
    5. import org.springframework.stereotype.Component;
    6. @Setter
    7. @Getter
    8. @Component
    9. @ConfigurationProperties(prefix = "aliyun.oss")
    10. public class OssConfig implements InitializingBean {
    11. private String endpoint;
    12. private String keyId;
    13. private String keySecret;
    14. private String bucketName;
    15. private String module;
    16. public static String ENDPOINT;
    17. public static String KEY_ID;
    18. public static String KEY_SECRET;
    19. public static String BUCKET_NAME;
    20. public static String MODULE;
    21. //当私有成员被赋值后,此方法自动被调用,从而初始化常量
    22. @Override
    23. public void afterPropertiesSet() throws Exception {
    24. ENDPOINT = endpoint;
    25. KEY_ID = keyId;
    26. KEY_SECRET = keySecret;
    27. BUCKET_NAME = bucketName;
    28. MODULE = module;
    29. }
    30. }

    文件上传

    返回文件在Oss的url

    1. import com.aliyun.oss.ClientException;
    2. import com.aliyun.oss.OSS;
    3. import com.aliyun.oss.OSSClientBuilder;
    4. import com.aliyun.oss.OSSException;
    5. import com.aliyun.oss.event.ProgressEvent;
    6. import com.aliyun.oss.event.ProgressEventType;
    7. import com.aliyun.oss.event.ProgressListener;
    8. import com.aliyun.oss.model.PutObjectRequest;
    9. import com.lixianhe.config.OssProperties;
    10. import com.lixianhe.result.R;
    11. import org.springframework.web.bind.annotation.PostMapping;
    12. import org.springframework.web.bind.annotation.RequestMapping;
    13. import org.springframework.web.bind.annotation.RequestParam;
    14. import org.springframework.web.bind.annotation.RestController;
    15. import org.springframework.web.multipart.MultipartFile;
    16. import java.io.IOException;
    17. import java.io.InputStream;
    18. // 使用进度条,需要实现ProgressListener方法
    19. @RestController
    20. @RequestMapping("/api/oss/file")
    21. public class PutObjectProgressListenerDemo implements ProgressListener {
    22. private long bytesWritten = 0;
    23. private long totalBytes = -1;
    24. @PostMapping("/upload")
    25. public R uploadFile(@RequestParam("file") MultipartFile file, @RequestParam String username) throws IOException {
    26. // 创建OSSClient实例(OSS客户端实例)
    27. OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
    28. OssProperties.KEY_ID, OssProperties.KEY_SECRET);
    29. // 获取选择文件的输入流
    30. InputStream inputStream = file.getInputStream();
    31. // 获取文件名称
    32. String originalFilename = file.getOriginalFilename();
    33. // 拼接Oss中文件的路径
    34. String objectName = OssProperties.MODULE + "/" + originalFilename;
    35. // 判断文件上传是否成功
    36. boolean uploadSucceed = false;
    37. try {
    38. // 上传文件的同时指定进度条参数。此处PutObjectProgressListenerDemo为调用类的类名,请在实际使用时替换为相应的类名。
    39. ossClient.putObject(new PutObjectRequest(OssProperties.BUCKET_NAME, objectName, inputStream).
    40. withProgressListener(new PutObjectProgressListenerDemo()));
    41. uploadSucceed = true;
    42. } catch (OSSException oe) {
    43. System.out.println("Caught an OSSException, which means your request made it to OSS, "
    44. + "but was rejected with an error response for some reason.");
    45. System.out.println("Error Message:" + oe.getErrorMessage());
    46. System.out.println("Error Code:" + oe.getErrorCode());
    47. System.out.println("Request ID:" + oe.getRequestId());
    48. System.out.println("Host ID:" + oe.getHostId());
    49. } catch (ClientException ce) {
    50. System.out.println("Caught an ClientException, which means the client encountered "
    51. + "a serious internal problem while trying to communicate with OSS, "
    52. + "such as not being able to access the network.");
    53. System.out.println("Error Message:" + ce.getMessage());
    54. } finally {
    55. if (ossClient != null) {
    56. ossClient.shutdown();
    57. }
    58. }
    59. if (uploadSucceed) {
    60. return R.ok().message("上传成功").data("URL", "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/" + objectName);
    61. } else {
    62. return R.error().message("上传失败");
    63. }
    64. }
    65. // 使用进度条需要您重写回调方法,以下仅为参考示例。
    66. @Override
    67. public void progressChanged(ProgressEvent progressEvent) {
    68. long bytes = progressEvent.getBytes();
    69. ProgressEventType eventType = progressEvent.getEventType();
    70. switch (eventType) {
    71. case TRANSFER_STARTED_EVENT:
    72. System.out.println("Start to upload......");
    73. break;
    74. case REQUEST_CONTENT_LENGTH_EVENT:
    75. this.totalBytes = bytes;
    76. System.out.println(this.totalBytes + " bytes in total will be uploaded to OSS");
    77. break;
    78. case REQUEST_BYTE_TRANSFER_EVENT:
    79. this.bytesWritten += bytes;
    80. if (this.totalBytes != -1) {
    81. int percent = (int) (this.bytesWritten * 100.0 / this.totalBytes);
    82. System.out.println(bytes + " bytes have been written at this time, upload progress: " + percent + "%(" + this.bytesWritten + "/" + this.totalBytes + ")");
    83. } else {
    84. System.out.println(bytes + " bytes have been written at this time, upload ratio: unknown" + "(" + this.bytesWritten + "/...)");
    85. }
    86. break;
    87. case TRANSFER_COMPLETED_EVENT:
    88. System.out.println("Succeed to upload, " + this.bytesWritten + " bytes have been transferred in total");
    89. break;
    90. case TRANSFER_FAILED_EVENT:
    91. System.out.println("Failed to upload, " + this.bytesWritten + " bytes have been transferred");
    92. break;
    93. default:
    94. break;
    95. }
    96. }
    97. }

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

    文件删除

    1. import com.aliyun.oss.ClientException;
    2. import com.aliyun.oss.OSS;
    3. import com.aliyun.oss.OSSClientBuilder;
    4. import com.aliyun.oss.OSSException;
    5. import com.lixianhe.config.OssProperties;
    6. import com.lixianhe.result.R;
    7. import org.springframework.web.bind.annotation.DeleteMapping;
    8. import org.springframework.web.bind.annotation.RequestMapping;
    9. import org.springframework.web.bind.annotation.RequestParam;
    10. import org.springframework.web.bind.annotation.RestController;
    11. @RestController
    12. @RequestMapping("/api/oss/file")
    13. public class DeleteFile {
    14. @DeleteMapping("/del")
    15. public R deleteFile(@RequestParam String url) {
    16. // 创建OSSClient实例(OSS客户端实例)
    17. OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
    18. OssProperties.KEY_ID, OssProperties.KEY_SECRET);
    19. //文件名(服务器上的文件路径)
    20. String host = "https://" + OssProperties.BUCKET_NAME + "." + OssProperties.ENDPOINT + "/";
    21. String objectName = url.substring(host.length());
    22. // 判断是否删除成功
    23. boolean deleteFileSucceed = false;
    24. try {
    25. // 删除文件或目录。如果要删除目录,目录必须为空。
    26. ossClient.deleteObject(OssProperties.BUCKET_NAME, objectName);
    27. deleteFileSucceed = true;
    28. } catch (OSSException oe) {
    29. System.out.println("Caught an OSSException, which means your request made it to OSS, "
    30. + "but was rejected with an error response for some reason.");
    31. System.out.println("Error Message:" + oe.getErrorMessage());
    32. System.out.println("Error Code:" + oe.getErrorCode());
    33. System.out.println("Request ID:" + oe.getRequestId());
    34. System.out.println("Host ID:" + oe.getHostId());
    35. } catch (ClientException ce) {
    36. System.out.println("Caught an ClientException, which means the client encountered "
    37. + "a serious internal problem while trying to communicate with OSS, "
    38. + "such as not being able to access the network.");
    39. System.out.println("Error Message:" + ce.getMessage());
    40. } finally {
    41. if (ossClient != null) {
    42. ossClient.shutdown();
    43. }
    44. }
    45. if (deleteFileSucceed) {
    46. return R.ok().message("删除成功");
    47. } else {
    48. return R.error().message("删除失败");
    49. }
    50. }
    51. }

    文件下载

    1. import com.aliyun.oss.ClientException;
    2. import com.aliyun.oss.OSS;
    3. import com.aliyun.oss.OSSClientBuilder;
    4. import com.aliyun.oss.OSSException;
    5. import com.aliyun.oss.event.ProgressEvent;
    6. import com.aliyun.oss.event.ProgressEventType;
    7. import com.aliyun.oss.event.ProgressListener;
    8. import com.aliyun.oss.model.GetObjectRequest;
    9. import com.lixianhe.config.OssProperties;
    10. import com.lixianhe.result.R;
    11. import org.springframework.web.bind.annotation.*;
    12. import java.io.File;
    13. import java.util.Map;
    14. @RestController
    15. @RequestMapping("/api/oss/file")
    16. public class GetObjectProgressListener implements ProgressListener {
    17. private long bytesRead = 0;
    18. private long totalBytes = -1;
    19. @PostMapping("/download")
    20. public R downloadFile(@RequestBody Map map) {
    21. // 获取用户名
    22. String username = (String) map.get("username");
    23. // 创建OSSClient实例(OSS客户端实例)
    24. OSS ossClient = new OSSClientBuilder().build(OssProperties.ENDPOINT,
    25. OssProperties.KEY_ID, OssProperties.KEY_SECRET);
    26. // 拼接文件名称
    27. String fileName = username + ".webp";
    28. // 拼接oss中文件的路径avatar/lixianhe.webp
    29. String objectName = OssProperties.MODULE + "/" + fileName;
    30. // 目标文件下载位置
    31. String pathName = "C:\\Users\\Administrator\\Downloads\\" + fileName;
    32. // 下载是否成功
    33. boolean downloadIsSucceed = false;
    34. try {
    35. // 下载文件的同时指定了进度条参数。
    36. ossClient.getObject(new GetObjectRequest(OssProperties.BUCKET_NAME, objectName).
    37. withProgressListener(new GetObjectProgressListener()), new File(pathName));
    38. downloadIsSucceed = true;
    39. } catch (OSSException oe) {
    40. System.out.println("Caught an OSSException, which means your request made it to OSS, "
    41. + "but was rejected with an error response for some reason.");
    42. System.out.println("Error Message:" + oe.getErrorMessage());
    43. System.out.println("Error Code:" + oe.getErrorCode());
    44. System.out.println("Request ID:" + oe.getRequestId());
    45. System.out.println("Host ID:" + oe.getHostId());
    46. } catch (ClientException ce) {
    47. System.out.println("Caught an ClientException, which means the client encountered "
    48. + "a serious internal problem while trying to communicate with OSS, "
    49. + "such as not being able to access the network.");
    50. System.out.println("Error Message:" + ce.getMessage());
    51. } finally {
    52. if (ossClient != null) {
    53. ossClient.shutdown();
    54. }
    55. }
    56. if (downloadIsSucceed) {
    57. return R.ok().message("下载成功");
    58. } else {
    59. return R.error().message("下载失败");
    60. }
    61. }
    62. @Override
    63. public void progressChanged(ProgressEvent progressEvent) {
    64. long bytes = progressEvent.getBytes();
    65. ProgressEventType eventType = progressEvent.getEventType();
    66. switch (eventType) {
    67. case TRANSFER_STARTED_EVENT:
    68. System.out.println("Start to download......");
    69. break;
    70. case RESPONSE_CONTENT_LENGTH_EVENT:
    71. this.totalBytes = bytes;
    72. System.out.println(this.totalBytes + " bytes in total will be downloaded to a local file");
    73. break;
    74. case RESPONSE_BYTE_TRANSFER_EVENT:
    75. this.bytesRead += bytes;
    76. if (this.totalBytes != -1) {
    77. int percent = (int) (this.bytesRead * 100.0 / this.totalBytes);
    78. System.out.println(bytes + " bytes have been read at this time, download progress: " +
    79. percent + "%(" + this.bytesRead + "/" + this.totalBytes + ")");
    80. } else {
    81. System.out.println(bytes + " bytes have been read at this time, download ratio: unknown" +
    82. "(" + this.bytesRead + "/...)");
    83. }
    84. break;
    85. case TRANSFER_COMPLETED_EVENT:
    86. System.out.println("Succeed to download, " + this.bytesRead + " bytes have been transferred in total");
    87. break;
    88. case TRANSFER_FAILED_EVENT:
    89. System.out.println("Failed to download, " + this.bytesRead + " bytes have been transferred");
    90. break;
    91. default:
    92. break;
    93. }
    94. }
    95. }

    测试

    上传文件测试

    删除文件测试

     下载文件测试

  • 相关阅读:
    如何在 Spring Security 中自定义权限表达式
    【Java多线程】线程同步机制(含同步方法)及不安全案例讲解
    UIView Animation 动画学习总结
    [附源码]SSM计算机毕业设计在线二手车交易信息管理系统JAVA
    条码软件中如何设置纵向条码
    SQL奇遇记:解锁 SQL 的秘密
    LeetCode75——Day8
    【SpringCloud-学习笔记】Ribbon负载均衡
    百利天恒更新招股书:上半年收入约3亿元,持续加大研发投入
    2022年6月电子学会Python等级考试试卷(四级)答案解析
  • 原文地址:https://blog.csdn.net/m0_56750901/article/details/126566423