一、体系结构
二、上传流程
什么是fastDFS:
fastDFS是一个底层使用C语言编写的, 开源的免费的分布式文件系统
fastDFS作用:
fastDFS主要作用就是上传文件, 下载文件, 删除文件等对文件的管理存储.
fastDFS运行原理:
1. fastDFS分为三部分: 客户端, 是指我们的购物项目。
tracker端, 也就是管理端是指管理服务器, 管理服务器不存储文件, 只负责管理存储端服务器。
storage端, 也就是存储端, 负责存储具体文件内容。
2. 存储端启动后会到管理端注册, 告诉管理端他的ip, 端口和状态, 我们需要存储文件的时候, 连接管理端,管理端会给我们返回具体服务器的ip地址, 端口号, 客户端就拿着ip和端口去调用存储端服务器存储文件,存储后会返回文件存储的路径和文件名, 存储端服务器会对文件自动重命名, 防止文件重名。
3. 管理端: 一台主机, 多台备机, 主备之间有心跳检测机制, 可以高可用,管理端有负载均衡的功能, 可以将请求均匀的分配给每一台存储端服务器处理。
存储端: 一台主机, 一台备机, 主备之间有心跳检测机制, 高可用, 存储的时候, 向主机中存储内容。
主机会将内容同步到备机, 主备之间存储的内容一样, 叫做冗余备份功能, 容灾效果强,存储端服务器可以理论上无限扩容, 扩展性强。
优点:
1. 管理端有高可用, 负载均衡功能, 可以承载高并发
2. 存储端冗余备份, 高可用, 无限扩容
缺点:
服务器集群需要企业自行搭建运维, 成本比较高.
使用场景:
适合大型互联网公司, 大规模存储任务使用.
fastDFS硬件服务器:
fastDFS服务器叫做存储服务器: 要求读写效率高
1. 如果经费充足: 可以购买ibm的nas服务器
2. 如果经费不够充足: 一般可以使用8块硬盘组成raid10磁盘阵列系统
硬盘分类: 5400转
7200转
12000转 读最快500多兆每秒, 写最快300多兆每秒
我们使用Docker搭建FastDFS的开发环境
拉取镜像
docker pull morunchang/fastdfs
运行tracker
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
运行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
<group name> 是组名,即storage的组
如果想要增加新的storage服务器,再次运行该命令,注意更换 新组名
修改nginx的配置
docker exec -it storage /bin/bash
进入后
vi /data/nginx/conf/nginx.conf
添加以下内容
location /group1/M00 {
proxy_next_upstream http_502 http_504 error timeout invalid_header;
proxy_cache http-cache;
proxy_cache_valid 200 304 12h;
proxy_cache_key $uri$is_args$args;
proxy_pass http://fdfs_group1;
expires 30d;
}
退出容器
exit
重启storage容器
docker restart storage
创建文件管理微服务changgou_service_file,该工程主要用于实现文件上传以及文件删除等功能。
(1)修改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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>changgou_service</artifactId> <groupId>com.changgou</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>changgou_service_file</artifactId> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>net.oschina.zcx7878</groupId> <artifactId>fastdfs-client-java</artifactId> <version>1.27.0.0</version> </dependency> <dependency> <groupId>com.changgou</groupId> <artifactId>changgou_common</artifactId> <version>1.0-SNAPSHOT</version> </dependency> </dependencies> </project>
(2)在resources文件夹下创建fasfDFS的配置文件fdfs_client.conf
connect_timeout = 60
network_timeout = 60
charset = UTF-8
http.tracker_http_port = 8080
tracker_server = 192.168.200.128:22122
connect_timeout:连接超时时间,单位为秒。
network_timeout:通信超时时间,单位为秒。发送或接收数据时。假设在超时时间后还不能发送或接收数据,则本次网络通信失败
charset: 字符集
http.tracker_http_port :.tracker的http端口
tracker_server: tracker服务器IP和端口设置
(3)在resources文件夹下创建application.yml
spring:
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
server:
port: 9008
eureka:
client:
service-url:
defaultZone: http://127.0.0.1:6868/eureka
instance:
prefer-ip-address: true
feign:
hystrix:
enabled: true
max-file-size是单个文件大小,max-request-size是设置总上传的数据大小
(4)启动类 创建com.changgou包,创建启动类FileApplication
@SpringBootApplication
@EnableEurekaClient
public class FileApplication {
public static void main(String[] args) {
SpringApplication.run(FileApplication.class);
}
}
文件上传一般都有文件的名字、文件的内容、文件的扩展名、文件的md5值、文件的作者等相关属性,我们可以创建一个对象封装这些属性,代码如下:
创建com.changgou.file.pojo.FastDFSFile
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.itheima.file.util下在该类中实现FastDFS信息获取以及文件的相关操作,
代码如下:
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; } }
@RestController @CrossOrigin public class FileController { @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; } /** * @param multipartFile * @return * @throws IOException */ 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:9007/upload
2、填写Headers
Key:Content-Type
Value:multipart/form-data
3、填写body
选择form-data 然后选择文件file 点击添加文件,最后发送即可。
原文:https://www.cnblogs.com/hujunwei/p/11341614.html