springBoot使用阿里云oss服务实现文件上传下载

一、首先开通并购买阿里云oss数据存储服务

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

能白嫖尽量白嫖,足够学习使用了。

在这里插入图片描述
跟着视频创建obs bucket桶,理解公共读,公共读写以及私有的含义,并根据自己的需求合理设置。小编的建议是桶的读写属性为私有化比较好,安全!对于部分文件的管理可以选择其他访问权限属性。这样能够将危险隔离在一个小的空间中。
创建视频教程链接:创建OSS

在这里插入图片描述

使用RAM用户访问控制组的原因是什么?或者有什么好处?

如果你是企业用户,那么这个配置就显得比较重要了。举个例子来说,你作为企业在云上资源的管理员,控制着企业中不同的业务资源,而普通员工能够接触到并使用的只是他个人所在业务部门所配备的资源,他应该掌握着公司属下的一个子账号,并给该账号赋予一定的资源使用权限。而不是整个公司管理员的账号。正如官方在OBS中介绍的一样,访问控制(Resource Access Management,RAM)是阿里云提供的一项管理用户身份与资源访问权限的服务。使用 RAM,您可以创建、管理 RAM 子用户(例如员工、系统或应用程序),并可以控制这些 RAM 子用户对资源的操作权限。当您的企业存在多用户协同操作资源时,使用 RAM 可以让您避免与其他用户共享云账号密钥,按需为用户分配最小权限,从而降低企业信息安全风险。

二、配置阿里云oss相关设置

1、首先在springboot中引入阿里云oss服务sdk依赖。

<!--        阿里云oss服务sdk-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>

下面是我的整个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>
    <groupId>com.example</groupId>
    <artifactId>learnDemo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>learnDemo</name>
    <description>learnDemo</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
<!--        阿里云oss服务sdk-->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.10.2</version>
        </dependency>
<!--        开启@Data注解-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

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

        <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>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.example.learndemo.LearnDemoApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

三、相关设置参数信息说明

这里配置文件我们采用的是.yml文件格式,这种格式相较于.application文件能够更好的区分显示不同模块的配置。

#服务器端口配置
server:
  port: 8081

#阿里云oss服务配置
aliyun:
  oss:
      bucketName: "桶的名称"
      endPoint: "地域节点"
      accessKeyId: "用户 AccessKeyID"
      accessKeySecret: "用户 AccessKey密匙"

我们就是基于这四个配置信息,来与服务器端的文件存储桶建立安全连接,并进行相关操作。
相关配置信息位置查看参照下图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意用户AccessKey一旦创建对应的密匙,只能显示一次,建议读者谨慎保存!(比心!)

四、配置springBoot阿里云oss服务

创建OSS配置信息的实体。部分方法使用注解代理生成了,快一点(我就是懒),但一定要注意引入相关依赖。

package com.example.learndemo.entity;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;


/**
 * @创建人 ChenYangming
 * @创建时间 2022/3/23
 * 描述:创建实例类操作阿里云OSS服务的原子数据存储
 */
@Data
@Component
@ConfigurationProperties(prefix = "aliyun.oss")
//获取配置文件内容注入类属性,方便同一修改
public class OSSConstantProperties {

    private String bucketName;

    private String endPoint;

    private String accessKeyId;

    private  String accessKeySecret;

}

将实体类作为OSS工具类中的一个属性,自动注入,每次操作时关注方法就可以了。相关操作说明以注释的形式插入代码中了。
这里涉及到的方法包括文件类型判断(不全,需要读者根据实际需求增加或者减少)目的是在上传文件的时候,顺带着设置一下文件类型,虽然阿里这一块有对文件类型的自动判断,可以严谨。
文件直接上传不同于官方提供的断点上传或分片上传等多种上传方式,我愿称自己的上传为简单傻瓜式上传,如果你的业务需要考虑上传的环境、效率的话建议查看文档
多种上传方法说明
文件删除根据文件路径包含文件名称,从桶中删除指定文件。

package com.example.learndemo.util;

import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.example.learndemo.entity.OSSConstantProperties;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @创建人 ChenYangming
 * @创建时间 2022/3/23
 * 描述与 aliyun SDK直接相互作用的工具实现类
 *
 */

@Component
@RunWith(SpringRunner.class)
@SpringBootTest
public class AliyunOssUtil {

    @Autowired
    private OSSConstantProperties ossConstantProperties;

    private SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 处理文件类型,用于文件存储时设置对应存储类型和访问权限
     * @param FilenameExtension
     * @return
     */
    public static String getcontentType(String FilenameExtension) {
        if (FilenameExtension.equalsIgnoreCase(".bmp")) {
            return "image/bmp";
        }
        if (FilenameExtension.equalsIgnoreCase(".gif")) {
            return "image/gif";
        }
        if (FilenameExtension.equalsIgnoreCase(".jpeg") ||
                FilenameExtension.equalsIgnoreCase(".jpg") ||
                FilenameExtension.equalsIgnoreCase(".png")) {
            return "image/jpg";
        }
        if (FilenameExtension.equalsIgnoreCase(".html")) {
            return "text/html";
        }
        if (FilenameExtension.equalsIgnoreCase(".txt")) {
            return "text/plain";
        }
        if (FilenameExtension.equalsIgnoreCase(".vsd")) {
            return "application/vnd.visio";
        }
        if (FilenameExtension.equalsIgnoreCase(".pptx") ||
                FilenameExtension.equalsIgnoreCase(".ppt")) {
            return "application/vnd.ms-powerpoint";
        }
        if (FilenameExtension.equalsIgnoreCase(".docx") ||
                FilenameExtension.equalsIgnoreCase(".doc")) {
            return "application/msword";
        }
        if (FilenameExtension.equalsIgnoreCase(".pdf")){
            return "application/pdf";
        }
        if (FilenameExtension.equalsIgnoreCase(".zip")){
            return "application/zip";
        }
        if (FilenameExtension.equalsIgnoreCase(".xls") ||
                FilenameExtension.equalsIgnoreCase(".xlsx")){
            return "application/vnd.ms-excel";
        }
        if (FilenameExtension.equalsIgnoreCase(".xml")) {
            return "text/xml";
        }
        return "application/octet-stream";
    }

@Test
    //简单的文件上传测试
    //文件上传接口需要的参数是被上传文件的本地绝对地址
    //文件上传返回值应该是在bucket中的位置信息。
    public void upload()  {

    String endpoint= this.ossConstantProperties.getEndPoint();
    String accessKeyId= this.ossConstantProperties.getAccessKeyId();
    String accessKeySecret=this.ossConstantProperties.getAccessKeySecret();
    String bucketName=this.ossConstantProperties.getBucketName();
    //上传到阿里云的位置和项目名称,默认从bucket开始。
    //    String objectName="文件/test01";
    //本地被上传文件的地址,要求为绝对路路径
   // String filePath="D:\\Game\\test.txt";
    File file=new File("D:\\企业应用开发\\笔记\\img\\图片11.png");
    //创建OSSClient实例
    String dateStr= sdf.format(new Date());
    OSS ossClient =new OSSClientBuilder().build(endpoint,accessKeyId,accessKeySecret);

    try{
        //容器不存在,就创建,权限为私有的
        if(! ossClient.doesBucketExist(bucketName)){
            ossClient.createBucket(bucketName);
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            createBucketRequest.setCannedACL(CannedAccessControlList.Private);
            ossClient.createBucket(createBucketRequest);
        }
        //上传时设置存储类型和访问权限
        ObjectMetadata objectMetadata=new ObjectMetadata();
        String type =  getcontentType(file.getName().substring(file.getName().lastIndexOf('.')));
        String fileUrl="";

        objectMetadata.setContentType(getcontentType(file.getName().substring(file.getName().lastIndexOf("."))));
        objectMetadata.setObjectAcl(CannedAccessControlList.Default);

        //创建文件路径
        fileUrl = (dateStr + "/" + UUID.randomUUID().toString().replace("-","")+"-"+file.getName());

        //上传文件,附带有桶、文件地址、文件、文件存储属性,
        PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, fileUrl, file,objectMetadata));
        System.out.println(result.toString());
        if (result!=null)
        {
            System.out.println(("==========>OSS文件上传成功,OSS地址:"+fileUrl));
        }
    } 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();
        }
    }

}
@Test
    //从bucket中下载文件到本地,有文件直接下载、流式下载、断点下载
    //参考文档代码 https://help.aliyun.com/document_detail/84824.html
    //1、参数一:objectName:文件在bucket中的位置
    //2、参数二:pathName:下载到本地的保存路径
public void exportOssFile(){
    String endpoint= ossConstantProperties.getEndPoint();
    String accessKeyId= ossConstantProperties.getAccessKeyId();
    String accessKeySecret=ossConstantProperties.getAccessKeySecret();
    String bucketName=ossConstantProperties.getBucketName();
    // 填写不包含Bucket名称在内的Object完整路径,例如testfolder/exampleobject.txt。
    //这里需要考虑一下文件路径加名称问题
    String objectName = "文件/计算机系统实践.doc";
    String pathName = "E:\\小组学习\\测试下载\\计算机系统实践.doc";
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

    try {
        // 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
        // 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
        ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));
    } 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();
        }
    }
}
@Test
    //从bucket中根据url删除指定文件
    //参数就一个被删除文件的地址
public void deletBlog(){
    String endpoint= this.ossConstantProperties.getEndPoint();
    String accessKeyId= this.ossConstantProperties.getAccessKeyId();
    String accessKeySecret=this.ossConstantProperties.getAccessKeySecret();
    String bucketName=this.ossConstantProperties.getBucketName();
    // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
    String objectName = "exampledir/exampleobject.txt";
    // 创建OSSClient实例。
    OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
    try {
        // 删除文件或目录。如果要删除目录,目录必须为空。
        ossClient.deleteObject(bucketName, objectName);
    } 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();
        }
    }
}
}

测试类代码如下:

package com.example.learndemo.util;

import org.junit.Test;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;

/**
 * @创建人 ChenYangming
 * @创建时间 2022/3/24
 * 描述:建立这个模块的作用是验证各个函数的具体使用功能,输出内容
 */
public class test {
    @Test
    public  void test01(){
        File file=new File("D:\\Game\\test.txt");
        System.out.println("1:"+file.getName());
        System.out.println("2:"+file.getName().lastIndexOf('.'));
        //字符之间的比较是通过ascll值来比较的
//        int ch='.';
//        System.out.println('.'==ch);
//        System.out.println(ch);
    }
    @Test
    public void test02(){
        //简单的日期格式工具类,输入日期对象new Date(),能够格式化为String类型的日期字符串
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String date= sdf.format(new Date());
        Date date1=new Date();
        System.out.println(date1);
        System.out.println(date);
        /*
        输出1:Thu Mar 24 18:47:42 CST 2022
        输出2:2022-03-24
         */
    }
    @Test
    public void test03(){
        //UUID是1.5中新增的一个类,在java.util下,用它可以产生一个号称全球唯一的ID
        System.out.println(UUID.randomUUID().toString());
        System.out.println(UUID.randomUUID().toString().replace("-",""));
    }
    @Test
    public  void test04(){
        /**
         * 结合了时间,UUID和文件名,构建了以日为单位的文件夹,文件名称全局唯一再加上文件名称,包含了后缀。
         */
        SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
        String date= sdf.format(new Date());
        File file=new File("D:\\企业应用开发\\笔记\\img\\图片11.png");
        String fileUrl=(date+"/"+UUID.randomUUID().toString().replace("-","")+"-"+file.getName());
        System.out.println(fileUrl);
        //输出:2022-03-24/d3a286fe514e45b780f29ce6dfb0b196-图片11.png
    }

}

五、上传文件测试

在这里插入图片描述
在这里插入图片描述
通过更改上传到阿里云上项目的信息分别是“文件/test.text”,“文件/test01”,有无文件类型后缀,显然是不一样的。
在这里插入图片描述
通过文件url在浏览器上预览两个文件的区别:在这里插入图片描述
两者的在线查看都是乱码可能原因是浏览器的解码和原本文件的编码格式不一样。我们知道在线查看不一定你能够完整还原项目就可以了。

在这里插入图片描述
我们在测试将两个文件下载到桌面后是什么样的。
在这里插入图片描述
没有文件后缀的打开需要选择打开文件是用什么工具,而.txt文件直接由记事本打开了。
通过以上对比,我们还是在上传文件的时候添加上文件的后缀比较好,对用户比较友好一点。

解决文件后缀添加问题

前端选择的文件
后端判断文件类型手动添加

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
访问ACL为公共读的文件后直接弹出下载框。
由这个对比实验我们可以知道,bucket的ACL和文件的ACL的相関概念。

在句点(.)之后,文件的扩展名是文件名称的最后一部分,文件名拓展FilenameExtension(文件后缀名)

        System.out.println("1:"+file.getName());
        System.out.println("2:"+file.getName().substring(file.getName().lastIndexOf(".")));//一个参数时表示从此处到结尾

输出结果:

1:test.txt
2:.txt

涉及到的两个函数功能分别是:获得文件名、截取String字符串
public int lastIndexOf(int ch): 返回指定字符在此字符串中最后一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

PutObjectRequest(bucketName,objectName,new File(filePath),objectMetadata)
上传文件有四个参数,其中第四个设置上传文件的读写权限可以省略,省略则文件继承bucket读写权限acl。
bucketName:桶名(容器名)
objectName:相当于上传文件在bucketName下的路径,例如“asd/dasd.txt”
File:文件

六、总结

采用OSS存储服务最大优势在于简化我们的文件操作工作,无需管理存储文件,我们的操作之间的联系仅剩4个配置信息建立连接和数据库存储文件在桶中的地址值即可。每一次上传我们只需要将返回的地址值存入我们的数据库即可,如果前端需要获取或者展示相关文件,只需要我们后端结合数据库中的地址值然后拼接上地域端值,即可让前端根据地址自己去发起请求获取。

附一个公共读的文件供大家查看:图片

  • 11
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值