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称为存储服务器。
客户端上传文件后存储服务器将文件 ID 返回给客户端,此文件 ID用于以后访问该文件的索引信息。文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名。
组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。
虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path对应。如果配置了
store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。
数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据
文件。
文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储
服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
注意 :
提供的虚拟机中FastDFS已经搭建完成, 并且是开机自动启动, 配置好虚拟机网络后直接使用即可。
虚拟机ip地址固定为 : 自己默认地址
用户名 : xxx
密码 : xxx
- 导入虚拟机镜像步骤:
- 文件菜单 -> 打开选项 -> 选择需要打开的虚拟机镜像文件(镜像文件需要提前解压)
如需使用本课程提供的虚拟机镜像, Vmware软件配置如下:
- 点击vmware软件的编辑菜单, 虚拟网络编辑器
- 在弹出的框中配置如下:
注意: vmware软件中只能有一个nat模式网络连接, 如果没有点击添加网络添加一个,如果已经存在那么照着下面配置内容修改,
子网ip必须是: 192.168.200.0
因为虚拟机镜像中已经将虚拟机的ip锁死为192.168.200.128
- 点击Nat设置, 配置网关IP如下:
- 虚拟机配置好后, 需要本地和虚拟机网络连通
所以在本地windows网络适配器选项中找到
以太网8
虚拟网卡进行配置.因为我们vmware软件中配置的时候VMnet8, 右键属性配合如下:
注意 : 配置本地虚拟网卡的时候, ip地址一定要处于200网段
网关一定要写上面配置的网关地址, 否则windows本机和虚拟机网络无法连通
- 启动虚拟机后在windows的cmd中可以ping服务器, 看是否能够连通虚拟机
ping 192.168.200.128
我们使用Docker容器化搭建FastDFS
docker pull morunchang/fastdfs
创建FastDFS管理端tracker容器
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
创建FastDFS存储端storage容器
docker run -d --name storage --net=host -e TRACKER_IP=:22122 -e 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服务器,再次运行该命令,注意更换 新组名
进入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
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
创建文件管理微服务fastdfsDemo,该工程主要用于实现文件上传以及文件删除等功能。
创建微服务时, 项目为Maven项目, 不要选择骨架.
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5.RELEASEversion>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<spring.boot.version>2.1.5.RELEASEspring.boot.version>
<fastdfs.client.version>1.27.0.0fastdfs.client.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>${spring.boot.version}version>
dependency>
<dependency>
<groupId>net.oschina.zcx7878groupId>
<artifactId>fastdfs-client-javaartifactId>
<version>${fastdfs.client.version}version>
dependency>
dependencies>
在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和端口设置
在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是设置总上传的数据大小
创建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);
}
}
文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的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 ...
}
创建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;
}
}
创建一个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、选择post请求方式,输入请求地址 http://localhost:9001/file/upload
2、填写Headers
Key:Content-Type
Value:multipart/form-data
3、填写body
选择form-data 然后选择文件file 点击添加文件,最后发送即可。
postman填写信息如下:
注意Headers请求头中内容
注意body请求体中内容:
阿里云对象存储OSS(Object Storage Service)是阿里云提供的海量、安全、低成本、高持久的云存储服务。其数据设计持久性不低于99.9999999999%(12个9),服务可用性(或业务连续性)不低于99.995%。
OSS具有与平台无关的RESTful API接口,您可以在任何应用、任何时间、任何地点存储和访问任意类型的数据。
您可以使用阿里云提供的API、SDK接口或者OSS迁移工具轻松地将海量数据移入或移出阿里云OSS。数据存储到阿里云OSS以后,您可以选择标准存储(Standard)作为移动应用、大型网站、图片分享或热点音视频的主要存储方式,也可以选择成本更低、存储期限更长的低频访问存储(Infrequent
Access)、归档存储(Archive)、冷归档存储(Cold Archive)作为不经常访问数据的存储方式。
阿里云对象存储OSS简单的说就是我们花钱在阿里购买存储空间
然后我们可以将项目中的图片文件等资源存储在对象存储OSS服务器上
对象存储OSS提供对文件的上传,下载, 删除等管理操作
这样我们就省去了购买存储服务器, 搭建存储服务器, 运营管理存储服务器的繁琐操作.
本方案适用于中小型规模公司, 对于并发量, 存储的数据量不大的情况下使用, 因为如果高并发大数据量阿里虽然也支持,
但是每年付出的费用相当昂贵, 这个时候可以选用FastDFS自己去购买服务器搭建并运营管理. 则更省钱.
- 存储类型(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用来验证签名字符串的密钥,必须保密。
OSS提供多种灵活的上传、下载和管理方式。
通过控制台管理OSS
OSS提供了Web服务页面,您可以登录OSS控制台管理您的OSS资源。
通过API或SDK管理OSS
OSS提供RESTful API和各种语言的SDK开发包,方便您快速进行二次开发。
通过工具管理OSS
OSS提供图形化管理工具ossbrowser、命令行管理工具ossutil、FTP管理工具ossftp等各种类型的管理工具。
通过云存储网关管理OSS
OSS的存储空间内部是扁平的,没有文件系统的目录等概念,所有的对象都直接隶属于其对应的存储空间。如果您想要像使用本地文件夹和磁盘那样来使用OSS存储服务,可以通过配置云存储网关来实现。
阿里云对象存储OSS官网地址 :
https://cn.aliyun.com/product/oss
阿里云对象存储OSS在线文档地址:
https://help.aliyun.com/product/31815.html?spm=5176.19720258.J_2686872250.3.54212c4ac3QCCP
进入官网后, 首先就是注册和登录, 可以使用支付宝登录, 阿里云手机客户端扫码登录, 账号密码登录, 阿里云提供多种登录形式。
- 首先找到阿里云的对象存储OSS服务进入
- 点击开通按钮进行开通对象存储OSS服务
- 注册, 登录, 开通OSS服务后点击管理控制台, 进入控制台界面
- 进入到控制台界面
- 创建Bucket桶, 点击Bucket列表菜单, 点击创建Bucket按钮, 按照下面内容填写:
- 创建完Bucket桶后就可以使用控制台上传图片进行测试了, 上传操作如下:
- 成功上传结果如下:
写代码的时候, 需要在项目配置文件中配置自己阿里云服务的账号和密码,如果写真实的支付宝账号密码会造成账号密码泄露, 不安全,所以创建AccessKey也就是在当前账户下, 创建子账户和密码使用, 可以随时更换, 启用, 停用。
- 鼠标悬停在那个小人的头像上不动, 就会出现下面菜单, 然后点击AccessKey管理
- 点击继续使用AccessKey
- 点击创建AccessKey创建密钥对
- 查看生成后的密钥对, 一定要复制保存下来, 一会写代码的时候需要用到
在资料的
软件文件夹
中有两个压缩包, 就是OSS-Browser工具, 此工具为阿里提供的管理对象存储OSS的桌面工具.
下面演示以Windows版本为例
oss-browser-mac-x64.zip 为mac版本
oss-browser-win32-x64.zip 为windows版本
- 解压windows版本后, 看到下面内容, oss-browser.exe为此工具启动文件
- 启动后, 输入子账户名称和密码进行登录, 也就是AccessKey和AccessSecret
- 进入后, 可以点击
新建Bucket按钮
, 创建桶, 填写内容如下, 也可以对桶进行维护操作
- 创建好桶后, 点击桶, 可以进入桶中
- 在桶中, 可以使用文件按钮上传文件, 对上传的文件还有下载和删除功能可以使用, 对文件进行维护管理
阿里云对象存储OSS在线文档地址:
https://help.aliyun.com/product/31815.html?spm=5176.19720258.J_2686872250.3.54212c4ac3QCCP
- 将下载的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包
- 创建项目名称为aliyunossDemo, maven项目, 不要选择骨架.
- 在pom.xml中导入依赖
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.5.RELEASEversion>
parent>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<maven.compiler.source>1.8maven.compiler.source>
<maven.compiler.target>1.8maven.compiler.target>
<spring.boot.version>2.1.5.RELEASEspring.boot.version>
<aliyun-oss-version>3.10.2aliyun-oss-version>
<httpcore-verison>4.4.3httpcore-verison>
<httpclient-version>4.5.1httpclient-version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
<version>${spring.boot.version}version>
dependency>
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>${aliyun-oss-version}version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpcoreartifactId>
<version>${httpcore-verison}version>
dependency>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>${httpclient-version}version>
dependency>
dependencies>
JDK如果是1.9或者以上版本需要加入jaxb相关依赖, 其他JDK版本不需要.
<dependency>
<groupId>javax.xml.bindgroupId>
<artifactId>jaxb-apiartifactId>
<version>2.3.1version>
dependency>
<dependency>
<groupId>javax.activationgroupId>
<artifactId>activationartifactId>
<version>1.1.1version>
dependency>
<dependency>
<groupId>org.glassfish.jaxbgroupId>
<artifactId>jaxb-runtimeartifactId>
<version>2.3.3version>
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();
}
}
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());
}
}
/**
* 下载文件到本地
* @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);
}
/**
* 上传图片并返回上传后的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;
}
/**
* 删除文件
* @param objName 需要删除的对象名称
* @Author zhaojian
*/
@DeleteMapping("/delete")
public void deleteFile(String objName) {
AliyunOSSUtil.deleteFile(endpoint, accessKeyId, accessKeySecret, bucketName, objName);
}
优点 :
Tracker管理端和Storage存储端服务器都有心跳检测机制, 高可用
Storage存储端服务器, 主机和备机自动同步数据, 冗余备份, 容灾性强
Tracker管理端服务器具有对Storage存储端服务器负载均衡的功能, 可以抗高并发.
Storage存储端服务器具有线性扩容功能, 理论上FastDFS存储容量无上限, 实时扩容.
缺点 :
费钱
FastDFS分布式文件系统对服务器需求量大
搭建FastDFS需要自己搭建机房, 并且运维.
如果存储数据量不是特别大, 成本则无法降低.
使用场景 :
适合大公司,自有IDC机房. 数据量和并发量得有一定规模才适用.
优点 :
支持高并发
支持海量数据
支持高可用, 高可靠.
以上特点都由阿里对象存储OSS提供保障, 无需自己运维.
缺点 :
数据量和并发量不高的情况下, 费用适中.
并发和数据量越大越贵. 这个时候不如自己购买服务器搭建FastDFS分布式文件系统使用
使用场景 :
适合中小型公司, 数据量不大,并发不高情况使用.
并不是阿里OSS不支持高并发和大数据量, 而是并发越高, 数据量越大, 越贵.