文件系统FastDFS和阿里云OSS

发布于:2022-11-09 ⋅ 阅读:(21) ⋅ 点赞:(0) ⋅ 评论:(0)

1. 分布式文件存储-FastDFS

1.1 FastDFS简介

1.1.1 FastDFS体系结构

FastDFS是一个开源的轻量级分布式文件系统,它对文件进行管理,功能包括:文件存储文件同步文件访问(文件上传、文件下载)等,解决了大容量存储和负载均衡的问题。特别适合以文件为载体的在线服务,如相册网站、视频网站等等。

FastDFS为互联网量身定制,充分考虑了冗余备份负载均衡线性扩容等机制,并注重高可用、高性能等指标,使用FastDFS很容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务。
|
FastDFS 架构包括 Tracker server 和 Storage server。客户端请求 Tracker server 进行文件上传、下载通过Tracker server 调度最终由 Storage server 完成文件上传和下载。

Tracker server 作用是负载均衡调度,通过 Tracker server 在文件上传时可以根据一些策略找到Storage server 提供文件上传服务。可以将 tracker 称为追踪服务器或调度服务器。Storage server作用是文件存储,客户端上传的文件最终存储在 Storage 服务器上,Storageserver 没有实现自己的文件系统而是利用操作系统的文件系统来管理文件。可以将storage称为存储服务器。

1.1.2 上传流程

客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。

组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。

虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path对应。如果配置了

store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。

数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据

文件。

文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储

服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。

1.2 FastDFS搭建(容器化部署)

注意 :

提供的虚拟机中FastDFS已经搭建完成, 并且是开机自动启动, 配置好虚拟机网络后直接使用即可。

1.2.0 Vmware虚拟机配置

虚拟机ip地址固定为 : 自己默认地址

用户名 : xxx

密码 : xxx

  • 导入虚拟机镜像步骤:
  • 文件菜单 -> 打开选项 -> 选择需要打开的虚拟机镜像文件(镜像文件需要提前解压)

如需使用本课程提供的虚拟机镜像, Vmware软件配置如下:

  1. 点击vmware软件的编辑菜单, 虚拟网络编辑器

在这里插入图片描述

  1. 在弹出的框中配置如下:

注意: vmware软件中只能有一个nat模式网络连接, 如果没有点击添加网络添加一个,如果已经存在那么照着下面配置内容修改,
子网ip必须是: 192.168.200.0

因为虚拟机镜像中已经将虚拟机的ip锁死为192.168.200.128

在这里插入图片描述

  1. 点击Nat设置, 配置网关IP如下:

在这里插入图片描述

  1. 虚拟机配置好后, 需要本地和虚拟机网络连通

所以在本地windows网络适配器选项中找到 以太网8虚拟网卡进行配置.

因为我们vmware软件中配置的时候VMnet8, 右键属性配合如下:

在这里插入图片描述

注意 : 配置本地虚拟网卡的时候, ip地址一定要处于200网段

网关一定要写上面配置的网关地址, 否则windows本机和虚拟机网络无法连通

在这里插入图片描述

  1. 启动虚拟机后在windows的cmd中可以ping服务器, 看是否能够连通虚拟机
ping 192.168.200.128

在这里插入图片描述

我们使用Docker容器化搭建FastDFS

1.2.1. 拉取镜像

docker pull morunchang/fastdfs

1.2.2. 运行tracker

创建FastDFS管理端tracker容器

docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh

1.2.3. 运行storage

创建FastDFS存储端storage容器

docker run -d --name storage --net=host -e TRACKER_IP=<your tracker server address>:22122 -e GROUP_NAME=<group name> morunchang/fastdfs sh storage.sh

#创建storage容器例子:
docker run -d --name storage --net=host -e TRACKER_IP=192.168.200.128:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
  • 使用的网络模式是–net=host
  • 其中 位置替换为你机器的Ip即可
  • 其中 是组名,即storage的组, 例如: group1, group2, group3等
  • 如果想要增加新的storage服务器,再次运行该命令,注意更换 新组名

1.2.4. 修改nginx的配置

进入storage的容器内部,修改nginx.conf

# 进入到storage容器内部
docker exec -it storage  /bin/bash

进入到容器内部后

#1. 通过命令来查询Nginx的安装位置:
root@iZ8vb6w2xyjemtqcxtmaj4Z:/# whereis nginx
#显示如下:
nginx: /etc/nginx

#2. 查看当前Nginx的进程
root@iZ8vb6w2xyjemtqcxtmaj4Z:/# ps aux | grep nginx
#显示如下:
root        16  0.0  0.0  32480  1480 ?        Ss   13:18   0:00 nginx: master process /etc/nginx/sbin/nginx
nobody     100  0.0  0.0  33036  2116 ?        S    14:15   0:00 nginx: worker process
root       118  0.0  0.0  11272   728 pts/1    S+   14:54   0:00 grep --color=auto nginx

在这里插入图片描述

在storage存储端容器的nginx中添加以下内容:

#3. 修改Nginx的配置文件
vi /etc/nginx/conf/nginx.conf

#4. 修改Nginx配置内容
 server {
        listen       80;
        server_name  localhost;
        
        location ~ /M00 {
        		# storage 实际存储图片的位置
            root /data/fast_data/data;
            ngx_fastdfs_module;
        }
}

#5. 进入到Nginx sbin目录从新加载Nginx配置文件
cd /etc/nginx/sbin

#6. 重新加载配置文件, 让nginx配置生效
./nginx -s reload

修改后:

在这里插入图片描述

storage存储的位置/data/fast_data/data

在这里插入图片描述

1.2.5. 设置开机启动容器

docker update --restart=always  tracker
docker update --restart=always  storage

如果更新不成功,查看是否是下面错误

IPv4 forwarding is disabled. Networking will not work

解决:https://www.cnblogs.com/python-wen/p/11224828.html

1.3 文件存储微服务

1.3.1. 创建文件管理微服务

创建文件管理微服务fastdfsDemo,该工程主要用于实现文件上传以及文件删除等功能。

创建微服务时, 项目为Maven项目, 不要选择骨架.

1.3.2. 修改pom.xml引入依赖

<!-- 继承Spring boot工程 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>

<properties>
    <!-- 项目源码及编译输出的编码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <!-- 项目编译JDK版本 -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

    <!-- 依赖包版本管理 -->
    <spring.boot.version>2.1.5.RELEASE</spring.boot.version>
    <fastdfs.client.version>1.27.0.0</fastdfs.client.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring.boot.version}</version>
    </dependency>
    <dependency>
        <groupId>net.oschina.zcx7878</groupId>
        <artifactId>fastdfs-client-java</artifactId>
        <version>${fastdfs.client.version}</version>
    </dependency>
</dependencies>

1.3.3. 创建fasfDFS的配置文件

在resources文件夹下创建fasfDFS的配置文件fdfs_client.conf

connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 80
tracker_server = 192.168.200.128:22122

  • connect_timeout:连接超时时间,单位为秒。

  • network_timeout:通信超时时间,单位为秒。发送或接收数据时。假设在超时时间后还不能发送或接收数据,则本次网络通信失败

  • charset: 字符集

  • http.tracker_http_port :.tracker的http端口

  • tracker_server: tracker服务器IP和端口设置

1.3.4. 创建微服务配置文件

在resources文件夹下创建application.yml

spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  application:
    name: fastdfs-demo
server:
  port: 9001

max-file-size是单个文件大小,max-request-size是设置总上传的数据大小

1.3.5. 创建启动类

创建com.qianfeng包,创建启动类FastDFSApplication

package com.qianfeng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 项目启动类
 * @Author zhaojian
 */
@SpringBootApplication
public class FastDFSApplication {

    public static void main(String[] args) {
        SpringApplication.run(FastDFSApplication.class, args);
    }
}

1.4 文件上传

1.4.1 文件信息封装

文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性,代码如下:

创建com.ymk.pojo.FastDFSFile

package com.qianfeng.pojo;

/**
 * 自定义封装, 文件实体类
 * @Author zhaojian
 */
public class FastDFSFile {

    //文件名字
    private String name;
    //文件内容
    private byte[] content;
    //文件扩展名
    private String ext;
    //文件MD5摘要值
    private String md5;
    //文件创建作者
    private String author;

    public FastDFSFile(String name, byte[] content, String ext, String height, String width, String author) {
        super();
        this.name = name;
        this.content = content;
        this.ext = ext;
        this.author = author;
    }

    public FastDFSFile(String name, byte[] content, String ext) {
        super();
        this.name = name;
        this.content = content;
        this.ext = ext;
    }

	// getter and setter ...
}

1.4.2 文件操作

创建FastDFSClient类,放在com.ymk.util下, 在该类中实现FastDFS信息获取以及文件的相关操作,

代码如下:

package com.ymk.util;

import com.ymk.pojo.FastDFSFile;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.ClassPathResource;

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

/**
 * 上传下载等文件操作工具类
 * @Author zhaojian
 */
public class FastDFSClient {

    private static org.slf4j.Logger logger = LoggerFactory.getLogger(FastDFSClient.class);

    /***
     * 初始化加载FastDFS的TrackerServer配置
     */
    static {
        try {
            String filePath = new ClassPathResource("fdfs_client.conf").getFile().getAbsolutePath();
            ClientGlobal.init(filePath);
        } catch (Exception e) {
            logger.error("FastDFS Client Init Fail!",e);
        }
    }

    /***
     * 文件上传
     * @param file
     * @return
     */
    public static String[] upload(FastDFSFile file) {
        //获取文件的作者
        NameValuePair[] meta_list = new NameValuePair[1];
        meta_list[0] = new NameValuePair("author", file.getAuthor());

        //接收返回数据
        String[] uploadResults = null;
        StorageClient storageClient=null;
        try {
            //创建StorageClient客户端对象
            storageClient = getTrackerClient();

            /***
             * 文件上传
             * 1)文件字节数组
             * 2)文件扩展名
             * 3)文件作者
             */
            uploadResults = storageClient.upload_file(file.getContent(), file.getExt(), meta_list);
        } catch (Exception e) {
            logger.error("Exception when uploadind the file:" + file.getName(), e);
        }

        if (uploadResults == null && storageClient!=null) {
            logger.error("upload file fail, error code:" + storageClient.getErrorCode());
        }
        //获取组名
        String groupName = uploadResults[0];
        //获取文件存储路径
        String remoteFileName = uploadResults[1];
        return uploadResults;
    }

    /***
     * 获取文件信息
     * @param groupName:组名
     * @param remoteFileName:文件存储完整名
     * @return
     */
    public static FileInfo getFile(String groupName, String remoteFileName) {
        try {
            StorageClient storageClient = getTrackerClient();
            return storageClient.get_file_info(groupName, remoteFileName);
        } catch (Exception e) {
            logger.error("Exception: Get File from Fast DFS failed", e);
        }
        return null;
    }

    /***
     * 文件下载
     * @param groupName
     * @param remoteFileName
     * @return
     */
    public static InputStream downFile(String groupName, String remoteFileName) {
        try {
            //创建StorageClient
            StorageClient storageClient = getTrackerClient();

            //下载文件
            byte[] fileByte = storageClient.download_file(groupName, remoteFileName);
            InputStream ins = new ByteArrayInputStream(fileByte);
            return ins;
        } catch (Exception e) {
            logger.error("Exception: Get File from Fast DFS failed", e);
        }
        return null;
    }

    /***
     * 文件删除
     * @param groupName
     * @param remoteFileName
     * @throws Exception
     */
    public static void deleteFile(String groupName, String remoteFileName)
            throws Exception {
        //创建StorageClient
        StorageClient storageClient = getTrackerClient();

        //删除文件
        int i = storageClient.delete_file(groupName, remoteFileName);
    }

    /***
     * 获取Storage组
     * @param groupName
     * @return
     * @throws IOException
     */
    public static StorageServer[] getStoreStorages(String groupName)
            throws IOException {
        //创建TrackerClient
        TrackerClient trackerClient = new TrackerClient();
        //获取TrackerServer
        TrackerServer trackerServer = trackerClient.getConnection();
        //获取Storage组
        return trackerClient.getStoreStorages(trackerServer, groupName);
    }

    /***
     * 获取Storage信息,IP和端口
     * @param groupName
     * @param remoteFileName
     * @return
     * @throws IOException
     */
    public static ServerInfo[] getFetchStorages(String groupName,
                                                String remoteFileName) throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return trackerClient.getFetchStorages(trackerServer, groupName, remoteFileName);
    }

    /***
     * 获取Tracker服务地址
     * @return
     * @throws IOException
     */
    public static String getTrackerUrl() throws IOException {
        return "http://"+getTrackerServer().getInetSocketAddress().getHostString()+":"+ ClientGlobal.getG_tracker_http_port()+"/";
    }

    /***
     * 获取Storage客户端
     * @return
     * @throws IOException
     */
    private static StorageClient getTrackerClient() throws IOException {
        TrackerServer trackerServer = getTrackerServer();
        StorageClient storageClient = new StorageClient(trackerServer, null);
        return  storageClient;
    }

    /***
     * 获取Tracker
     * @return
     * @throws IOException
     */
    private static TrackerServer getTrackerServer() throws IOException {
        TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        return  trackerServer;
    }
}

1.4.3 文件上传

创建一个FileController,在该控制器中实现文件上传操作,代码如下:

package com.ymk.controller;

import com.ymk.pojo.FastDFSFile;
import com.ymk.util.FastDFSClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
 * 文件操作controller接口
 * @Author zhaojian
 */
@RestController
@CrossOrigin
@RequestMapping("/file")
public class FileController {

    /**
     * 上传接口
     * @param file 接收文件参数, 参数名必须叫做file
     * @Author zhaojian
     */
    @PostMapping("/upload")
    public String upload(@RequestParam("file") MultipartFile file) {
        String path ="";
        try {
            path=saveFile(file);
            System.out.println(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return path;
    }

    /**
     * 上传文件到FastDFS分布式文件系统
     * @param multipartFile
     * @Author zhaojian
     */
    public String saveFile(MultipartFile multipartFile) throws IOException {
        //1. 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        //2. 获取文件内容
        byte[] content = multipartFile.getBytes();
        //3. 获取文件扩展名
        String ext = "";
        if (fileName != null && !"".equals(fileName)) {
            ext = fileName.substring(fileName.lastIndexOf("."));
        }
        //4. 创建文件实体类对象
        FastDFSFile fastDFSFile = new FastDFSFile(fileName, content, ext);
        //5. 上传
        String[] uploadResults = FastDFSClient.upload(fastDFSFile);
        //6. 拼接上传后的文件的完整路径和名字, uploadResults[0]为组名, uploadResults[1]为文件名称和路径
        String path = FastDFSClient.getTrackerUrl() + uploadResults[0] + "/" + uploadResults[1];
        //7. 返回
        return path;
    }
}

1.5 Postman测试文件上传

步骤:

1、选择post请求方式,输入请求地址 http://localhost:9001/file/upload

2、填写Headers

Key:Content-Type
Value:multipart/form-data

3、填写body

选择form-data 然后选择文件file 点击添加文件,最后发送即可。

postman填写信息如下:

注意Headers请求头中内容

在这里插入图片描述

注意body请求体中内容:

在这里插入图片描述

上传结果可以通过浏览器访问显示如下:
在这里插入图片描述

2. 阿里云对象存储 - OSS

2.1. 什么是对象存储OSS

阿里云对象存储OSS(Object Storage Service)是阿里云提供的海量安全低成本高持久的云存储服务。其数据设计持久性不低于99.9999999999%(12个9),服务可用性(或业务连续性)不低于99.995%。

OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据

您可以使用阿里云提供的API、SDK接口或者OSS迁移工具轻松地将海量数据移入或移出阿里云OSS。数据存储到阿里云OSS以后,您可以选择标准存储(Standard)作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问存储(Infrequent
Access)、归档存储(Archive)、冷归档存储(Cold Archive)
作为不经常访问数据的存储方式。

2.2. 对象存储OSS作用

  • 阿里云对象存储OSS简单的说就是我们花钱在阿里购买存储空间

  • 然后我们可以将项目中的图片文件等资源存储在对象存储OSS服务器上

  • 对象存储OSS提供对文件的上传,下载, 删除等管理操作

  • 这样我们就省去了购买存储服务器, 搭建存储服务器, 运营管理存储服务器的繁琐操作.

  • 本方案适用于中小型规模公司, 对于并发量, 存储的数据量不大的情况下使用, 因为如果高并发大数据量阿里虽然也支持,

  • 但是每年付出的费用相当昂贵, 这个时候可以选用FastDFS自己去购买服务器搭建并运营管理. 则更省钱.

2.3. 对象存储OSS中的概念

  • 存储类型(Storage Class)

OSS提供标准、低频访问、归档、冷归档四种存储类型,全面覆盖从热到冷的各种数据存储场景。其中标准存储类型提供高持久、高可用、高性能的对象存储服务,能够支持频繁的数据访问;低频访问存储类型适合长期保存不经常访问的数据(平均每月访问频率1到2次),存储单价低于标准类型;归档存储类型适合需要长期保存(建议半年以上)的归档数据;冷归档存储适合需要超长时间存放的极冷数据。

  • 存储空间(Bucket)

存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。存储空间具有各种配置属性,包括地域、访问权限、存储类型等。您可以根据实际需求,创建不同类型的存储空间来存储不同的数据。

  • 对象(Object)

对象是OSS存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object
Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。对象元信息是一组键值对,表示了对象的一些属性,例如最后修改时间、大小等信息,同时您也可以在元信息中存储一些自定义的信息。

  • 地域(Region)

地域表示OSS的数据中心所在物理位置。您可以根据费用、请求来源等选择合适的地域创建Bucket。

  • 访问域名(Endpoint)

Endpoint表示OSS对外服务的访问域名。OSS以HTTP RESTful
API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。

  • 访问密钥(AccessKey)

AccessKey简称AK,指的是访问身份验证中用到的AccessKey ID和AccessKey
Secret。OSS通过使用AccessKey ID和AccessKey
Secret对称加密的方法来验证某个请求的发送者身份。AccessKey ID用于标识用户;AccessKey
Secret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,必须保密。

2.4. 对象存储OSS管理方式

OSS提供多种灵活的上传、下载和管理方式。

  • 通过控制台管理OSS

    OSS提供了Web服务页面,您可以登录OSS控制台管理您的OSS资源。

  • 通过API或SDK管理OSS

    OSS提供RESTful API和各种语言的SDK开发包,方便您快速进行二次开发。

  • 通过工具管理OSS

    OSS提供图形化管理工具ossbrowser、命令行管理工具ossutil、FTP管理工具ossftp等各种类型的管理工具。

  • 通过云存储网关管理OSS

    OSS的存储空间内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。如果您想要像使用本地文件夹和磁盘那样来使用OSS存储服务,可以通过配置云存储网关来实现。

2.5. 阿里云对象存储OSS [官网]

阿里云对象存储OSS官网地址 :

https://cn.aliyun.com/product/oss

阿里云对象存储OSS在线文档地址:

https://help.aliyun.com/product/31815.html?spm=5176.19720258.J_2686872250.3.54212c4ac3QCCP

2.6. 对象存储OSS注册和配置

2.6.1. 注册和登录

进入官网后, 首先就是注册和登录, 可以使用支付宝登录, 阿里云手机客户端扫码登录, 账号密码登录, 阿里云提供多种登录形式。

在这里插入图片描述

2.6.2. 开通对象存储OSS服务

  • 首先找到阿里云的对象存储OSS服务进入

在这里插入图片描述

  • 点击开通按钮进行开通对象存储OSS服务

在这里插入图片描述

2.6.3. 管理控制台

  • 注册, 登录, 开通OSS服务后点击管理控制台, 进入控制台界面

在这里插入图片描述

  • 进入到控制台界面

在这里插入图片描述

  • 创建Bucket桶, 点击Bucket列表菜单, 点击创建Bucket按钮, 按照下面内容填写:

在这里插入图片描述

在这里插入图片描述

2.6.4. 使用控制台上传图片

  • 创建完Bucket桶后就可以使用控制台上传图片进行测试了, 上传操作如下:

在这里插入图片描述

  • 成功上传结果如下:

在这里插入图片描述

2.7. AccessKey管理

2.7.1. 什么是AccessKey

写代码的时候, 需要在项目配置文件中配置自己阿里云服务的账号和密码,如果写真实的支付宝账号密码会造成账号密码泄露, 不安全,所以创建AccessKey也就是在当前账户下, 创建子账户和密码使用, 可以随时更换, 启用, 停用。

2.7.2. 如何使用AccessKey

  • 鼠标悬停在那个小人的头像上不动, 就会出现下面菜单, 然后点击AccessKey管理

在这里插入图片描述

  • 点击继续使用AccessKey

在这里插入图片描述

  • 点击创建AccessKey创建密钥对

在这里插入图片描述

  • 查看生成后的密钥对, 一定要复制保存下来, 一会写代码的时候需要用到

在这里插入图片描述

2.8. OSS-Browser管理工具使用

在资料的 软件文件夹 中有两个压缩包, 就是OSS-Browser工具, 此工具为阿里提供的管理对象存储OSS的桌面工具.
下面演示以Windows版本为例

  • oss-browser-mac-x64.zip 为mac版本

  • oss-browser-win32-x64.zip 为windows版本

  • 解压windows版本后, 看到下面内容, oss-browser.exe为此工具启动文件

在这里插入图片描述

  • 启动后, 输入子账户名称和密码进行登录, 也就是AccessKey和AccessSecret

在这里插入图片描述

  • 进入后, 可以点击 新建Bucket按钮, 创建桶, 填写内容如下, 也可以对桶进行维护操作

在这里插入图片描述

  • 创建好桶后, 点击桶, 可以进入桶中

在这里插入图片描述

  • 在桶中, 可以使用文件按钮上传文件, 对上传的文件还有下载和删除功能可以使用, 对文件进行维护管理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EG3HciQq-1666243333103)(Pictures\35.png)]

2.9. 写代码前准备工作

2.9.1. 下载SDK安装包

阿里云对象存储OSS在线文档地址:

https://help.aliyun.com/product/31815.html?spm=5176.19720258.J_2686872250.3.54212c4ac3QCCP

在这里插入图片描述

2.9.2. SDK包安装到本地maven仓库

在这里插入图片描述

  • 将下载的SDK安装包解压, 然后安装到本地的maven仓库, 命令如下:
mvn install:install-file -DgroupId=com.aliyun.oss -DartifactId=aliyun-sdk-oss -Dversion=3.10.2 -Dpackaging=jar -Dfile=aliyun-sdk-oss-3.10.2.jar

命令解释如下:

mvn install:install-file //安装到maven本地仓库命令

  • DgroupId=com.aliyun.oss //pom文件坐标的groupId

  • DartifactId=aliyun-sdk-oss //pom文件坐标的artifactId

  • Dversion=3.10.2 //版本号

  • Dpackaging=jar //打包方式

  • Dfile=aliyun-sdk-oss-3.10.2.jar //解压后的jar包

2.10. 代码操作使用案例

2.10.1. 搭建项目环境

  • 创建项目名称为aliyunossDemo, maven项目, 不要选择骨架.
  • 在pom.xml中导入依赖
<!-- 继承Spring boot工程 -->
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.1.5.RELEASE</version>
</parent>

<properties>
    <!-- 项目源码及编译输出的编码 -->
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

    <!-- 项目编译JDK版本 -->
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>

    <!-- 依赖包版本管理 -->
    <spring.boot.version>2.1.5.RELEASE</spring.boot.version>
    <aliyun-oss-version>3.10.2</aliyun-oss-version>
    <httpcore-verison>4.4.3</httpcore-verison>
    <httpclient-version>4.5.1</httpclient-version>
</properties>

<dependencies>
    <!-- Spring boot starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
        <version>${spring.boot.version}</version>
    </dependency>
    <dependency>
        <groupId>com.aliyun.oss</groupId>
        <artifactId>aliyun-sdk-oss</artifactId>
        <version>${aliyun-oss-version}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpcore</artifactId>
        <version>${httpcore-verison}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>${httpclient-version}</version>
    </dependency>
</dependencies>

JDK如果是1.9或者以上版本需要加入jaxb相关依赖, 其他JDK版本不需要.

<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>
  • 在resources目录下创建application.yml配置文件
spring:
  servlet:
    multipart:
      max-file-size: 10MB
      max-request-size: 10MB
  application:
    name: aliyun-oss-demo
server:
  port: 9001
aliyun:
  oss:
    #服务器地址, 我选择的是华北2-北京地址如下
    endpoint: http://oss-cn-beijing.aliyuncs.com
    #子账户名称
    accessKeyId: 就不告诉你
    #子账户密码
    accessKeySecret: 就不告诉你
    #自己创建的桶的名字
    bucketName: qianfeng-file
  • 创建启动类AliyunOssApplication.java
package com.qianfeng;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * 微服务启动类
 * @Author zhaojian
 */
@SpringBootApplication
public class AliyunOssApplication {

    public static void main(String[] args) {
        SpringApplication.run(AliyunOssApplication.class, args);
    }
}
  • 创建com.ymk.util包, 放入文件操作工具类AliyunOSSUtil.java
package com.ymk.util;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.util.Date;

/**
 * 阿里云OSS上传,下载, 删除文件工具类
 * @Author zhaojian
 */
public class AliyunOSSUtil {


    /**
     * byte数组格式上传文件
     * @param endpoint          OSS对外服务的访问域名
     * @param accessKeyId       accessKey账号
     * @param accessKeySecret   accessKey密码
     * @param bucketName        桶名字
     * @param objectName        完整文件名, 例如abc/efg/123.jpg
     * @param content           文件内容, byte数组格式
     * @Author zhaojian
     */
    public static void uploadByByteArrayFile(String endpoint,
                                             String accessKeyId,
                                             String accessKeySecret,
                                             String bucketName,
                                             String objectName,
                                             byte[] content) throws Exception {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        //创建上传请求对象
        PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, new ByteArrayInputStream(content));

        // 上传
        PutObjectResult putObjectResult = ossClient.putObject(putObjectRequest);

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 输入流格式上传文件
     * @param endpoint          OSS对外服务的访问域名
     * @param accessKeyId       accessKey账号
     * @param accessKeySecret   accessKey密码
     * @param bucketName        桶名字
     * @param objectName        完整文件名, 例如abc/efg/123.jpg
     * @param content           文件内容, 输入流格式
     * @Author zhaojian
     */
    public static void uploadByInputStreamFile(String endpoint,
                                               String accessKeyId,
                                               String accessKeySecret,
                                               String bucketName,
                                               String objectName,
                                               InputStream content) {

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 上传
        ossClient.putObject(bucketName, objectName, content);
        // 关闭OSSClient
        ossClient.shutdown();
    }

    /**
     * byte数组格式上传文件并返回上传后的URL地址
     * @param endpoint          OSS对外服务的访问域名
     * @param accessKeyId       accessKey账号
     * @param accessKeySecret   accessKey密码
     * @param bucketName        桶名字
     * @param objectName        完整文件名, 例如abc/efg/123.jpg
     * @param content           文件内容, byte数组格式
     * @Author zhaojian
     */
    public static String uploadImage(String endpoint,
                              String accessKeyId,
                              String accessKeySecret,
                              String bucketName,
                              String objectName,
                              byte[] content)  throws Exception {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        // 创建上传文件的元信息,可以通过文件元信息设置HTTP header(设置了才能通过返回的链接直接访问)。
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType("image/jpg");
        // 文件上传
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content), objectMetadata);
        // 设置URL过期时间为1小时。
        Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
        //返回url地址
        String url = ossClient.generatePresignedUrl(bucketName, objectName, expiration).toString();
        //关闭OSSClient。
        ossClient.shutdown();
        return url;
    }

    /**
     * 下载文件到本地
     * @param endpoint          OSS对外服务的访问域名
     * @param accessKeyId       accessKey账号
     * @param accessKeySecret   accessKey密码
     * @param bucketName        桶名字
     * @param objectName        完整文件名, 例如abc/efg/123.jpg
     * @param localFile         下载到本地文件目录
     * @Author zhaojian
     */
    public static void downFile(String endpoint,
                                String accessKeyId,
                                String accessKeySecret,
                                String bucketName,
                                String objectName,
                                String localFile) throws Exception {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
        ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(localFile));

        // 关闭OSSClient。
        ossClient.shutdown();
    }

    /**
     * 删除文件
     * @param endpoint          OSS对外服务的访问域名
     * @param accessKeyId       accessKey账号
     * @param accessKeySecret   accessKey密码
     * @param bucketName        桶名字
     * @param objectName        完整文件名, 例如abc/efg/123.jpg
     * @Author zhaojian
     */
    public static void deleteFile(String endpoint,
                                  String accessKeyId,
                                  String accessKeySecret,
                                  String bucketName,
                                  String objectName) {
        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

        // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
        ossClient.deleteObject(bucketName, objectName);

        // 关闭OSSClient。
        ossClient.shutdown();
    }
}

2.10.2. 上传文件

package com.ymk.controller;

import com.ymk.util.AliyunOSSUtil;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * 文件管理接口
 * 提供文件各种形式上传, 下载, 删除等操作
 * @Author zhaojian
 */
@RestController
@RequestMapping("/file")
public class FileManagerController {

    //OSS服务器访问域名
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;

    //子账户名
    @Value("${aliyun.oss.accessKeyId}")
    private String accessKeyId;

    //子账户密码
    @Value("${aliyun.oss.accessKeySecret}")
    private String accessKeySecret;

    //桶名字
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * byte数组形式上传
     * @param file
     * @Author zhaojian
     */
    @PostMapping("/upload1")
    public void upload(@RequestParam("file") MultipartFile file) throws Exception {
        AliyunOSSUtil.uploadByByteArrayFile(endpoint, accessKeyId, accessKeySecret, bucketName, file.getOriginalFilename(), file.getBytes());
    }
    
    /**
     * 输入流形式上传
     * @param file
     * @Author zhaojian
     */
    @PostMapping("/upload2")
    public void upload2(@RequestParam("file") MultipartFile file) throws Exception {
        AliyunOSSUtil.uploadByInputStreamFile(endpoint, accessKeyId, accessKeySecret, bucketName, file.getOriginalFilename(), file.getInputStream());
    }
}

2.10.3. 下载文件到本地目录

/**
 * 下载文件到本地
 * @param objName   需要下载的对象名称
 * @param filePath  将对象下载到本地的路径和文件名, 重名则覆盖. 
 *                  例如: F:\test\7.jpg
 * @Author zhaojian
 */
@GetMapping("/download")
public void download(String objName, String filePath) throws Exception {
    AliyunOSSUtil.downFile(endpoint, accessKeyId, accessKeySecret, bucketName, objName, filePath);
}

2.10.4. 上传图片并返回访问路径

/**
 * 上传图片并返回上传后的URL地址
 * @param file
 * @Author zhaojian
 */
@PostMapping("/upload3")
public String upload3(@RequestParam("file") MultipartFile file) throws Exception {
    String url = AliyunOSSUtil.uploadImage(endpoint, accessKeyId, accessKeySecret, bucketName, file.getOriginalFilename(), file.getBytes());
    System.out.println("=====" + url);
    return url;
}

2.10.5. 删除文件

/**
 * 删除文件
 * @param objName 需要删除的对象名称
 * @Author zhaojian
 */
@DeleteMapping("/delete")
public void deleteFile(String objName) {
    AliyunOSSUtil.deleteFile(endpoint, accessKeyId, accessKeySecret, bucketName, objName);
}

3. 总结

3.1. FastDFS优缺点

优点 :

  • Tracker管理端和Storage存储端服务器都有心跳检测机制, 高可用

  • Storage存储端服务器, 主机和备机自动同步数据, 冗余备份, 容灾性强

  • Tracker管理端服务器具有对Storage存储端服务器负载均衡的功能, 可以抗高并发.

  • Storage存储端服务器具有线性扩容功能, 理论上FastDFS存储容量无上限, 实时扩容.

缺点 :

  • 费钱

  • FastDFS分布式文件系统对服务器需求量大

  • 搭建FastDFS需要自己搭建机房, 并且运维.

  • 如果存储数据量不是特别大, 成本则无法降低.

使用场景 :

适合大公司,自有IDC机房. 数据量和并发量得有一定规模才适用.

3.2. 阿里对象存储OSS优缺点 :

优点 :

  • 支持高并发

  • 支持海量数据

  • 支持高可用, 高可靠.

  • 以上特点都由阿里对象存储OSS提供保障, 无需自己运维.

缺点 :

  • 数据量和并发量不高的情况下, 费用适中.

  • 并发和数据量越大越贵. 这个时候不如自己购买服务器搭建FastDFS分布式文件系统使用

使用场景 :

  • 适合中小型公司, 数据量不大,并发不高情况使用.

  • 并不是阿里OSS不支持高并发和大数据量, 而是并发越高, 数据量越大, 越贵.