XC-08


vm虚拟机启动命令

[root@localhost ~]# /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
[root@localhost ~]# /usr/bin/fdfs_storaged /etc/fdfs/storage.conf
[root@localhost conf]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf

分布式文件系统

技术应用场景

传智播客拥有大量优质的视频教程,并且免费提供给用户去下载,文件太多如何高效储存?用户访问量大如何保证下载速度?
分布式系统将解决这些问题
分布式系统解决海量文件存储以及传输访问瓶颈问题,对海量视频,文件的管理等.
系统文件量增长的速度,远远大于扩充硬盘的速度
借助于互联网来存储
在这里插入图片描述

什么是分布式文件系统?

什么是分布式文件系统?

首先,先了解什么是文件系统
引用百度百科中的描述:
文件系统
文件系统是操作系统的明确存储设备(常见是磁盘,也有基于NAND Flash固态硬盘)或分区上的文件的方法或者数据结构;
即在存储设备上组织文件的方法 . 操作系统中负责管理和存储文件信息的软件机构称为文件管理系统,简称文件系统. 文件系统由三部分组成:文件系统的接口,对对象的操作和管理软件的集合,对象及属性.从操作系统角度来看,从系统角度来看,文件系统是对文件存设备空间上的组织和分配,负责文件存储并对存储文件进行保护和检索的系统,具体来说,它负责为用户建立文件,存入,读出,修改,和转存文件,控制文件的存取,当用户不在使用时撤销文件等.

总结:文件系统是负责管理文件和存储文件的系统软件,操作系统通过文件系统提供的接口取存取文件,用户通过操作系统访问磁盘上的文件.
在这里插入图片描述
常见的文件系统:
FAT16/FAT32 , NTFS , HFS,UFS,APFS,XFS,Ext4等.

如果没有文件系统,那么我们该怎么管理自己的文件?
在这里插入图片描述
这个就是硬盘,不同的内容存在于不用的扇区

什么是分布式文件系统

分布式文件系统
引用百度百科:
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上,而是通过计算机网路于节点相连接,分布式文件系统的设计基于客户机/服务器模式.一个典型的网络可能包括供多个用户访问的服务器.另外,对等特性允许一些系统扮演客户机和服务器的双重角色.例如,用户可以发表一个允许其他客户访问的目录,一旦被访问,这个目录对于客户机来说就像使用本地驱动器一样,下面是三个基本的分布式文件系统.
为什么会有分布式文件系统呢?
分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?靠简单的增加硬盘的个数已经无法满足.我们的要求.因为硬盘的传输速度有限但是数据在急速的增长,另外,我们要做好数据的备份,数据安全等.
采用分布式文件系统可以将多个地点的文件系统通过网络连接起来,组成一个文件系统网络,节点之间通过网络进行通信,一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算机共同传输.
在这里插入图片描述
好处:

  1. 一台计算机的文件系统的处理能力扩充到多台计算机上同时处理.
  2. 一台计算机挂了还有另外副本计算机提供数据.
  3. 每台计算机可以放在不同的地域,这样用户就可以就近访问,提高访问速度

主流的分布式文件系统

NFS

NFS(网络文件系统)
百度百科:
NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客户端应用可以透明的读写位于远端的NFS服务器上的文件,就像访问本地文件一样.
在这里插入图片描 述
1.在客户端上映射NFS服务器的驱动器.
2.客户通过网络访问NFS的服务器的硬盘完全透明.

GFS

googleFs
百度百科:
GFS是一个可拓展的分布式文件系统,用于大型的,分布式的,对大量数据进行访问的应用.它用于廉价的普通硬件上,可以提供容错功能,它可以给大量用户提供总体性能较高的服务.
在这里插入图片描述

  1. GFS采用主从结构,一个GFS由一个master和大量的chunkserver组成.
  2. master存储了数据文件的元数据,一个文件被分成了若干块存储在chunkserver中.
  3. 用户从master中获取元信息,从chunkserver中存储数据.

在这里插入图片描述
将同一个文件的不同部分分别存储在不同的服务器上 这样性能高,速度快,而且安全.

HDFS

HDFS:
Hadoop分布式文件系统(HDFS)被设计成适合运行在通用硬件(Commodity hardware)上的分布式文件系统.它和现有的分布式文件系统有很多共同点.但同时,它和其他分布式文件系统也有很大的区别.HDFS是一个高度容错性的系统,适合部署在廉价的机器上.HDFS能提高吞吐量的数据访问,但非常适合大规模数据集上的应用.HDFS放宽了一部分POSIX约束,来实现流式读取分布式文件系统的目的.HDFS在最开始是Apach Nutch搜索引擎项目的基础架构而开发的.HDFS是ApachHadoopCore项目的一部分.
HDFS有着高容错性(fault-tolerant)的特点,并且设计用拉力部署在低廉的(low-cost)硬件上.而且它提高吞吐量(highThroughPut)来访问应用程序数据,适合那些有着超大数据集(largeDataSet)的应用程序.HDFS放宽了(relax)POSIX的要求(requirement)这样可以实现流的形式访问(streamingAccess)文件系统中的数据.
在这里插入图片描述

  1. HDFS采用主从结构,一个HDFS汲取能有一个名称节点和若干个数据节点组成.名称节点存储数据的元信息,一个完整的文件分成若干块存储在数据节点.
  2. 客户端从名称节点获取数据的元信息,得到信息客户端即可从数据块来存取数据.

分布式文件服务提供商

阿里的OSS

什么是OSS
阿里云对象存储服务(objectStorageService,简称OSS),是阿里提供的海量,安全,低成本,可靠的云存储服务.它具有与平台无关的RestfulApi接口,能提供99.999999999%的服务持久性.您可以在任何应用,任何时间,任何地点存储和访问任意类型的数据.OSS适合各种网站,开发企业及开发者使用.
您可以使用阿里云提供的API/SDK接口或者OSS迁移工具轻松的将海量数据移入移出阿里云OSS.数据存储到阿里云OSS以后,您可以选择标准类型(Standard)的阿里云OSS服务作为移动应用,大型网站,图片分享或热点视频的主要存储方式,也可以选择低成本,存储期限更长的低频访问类型(InfrequentAccess)和归档类型(Archive)的阿里云OSS服务作为不经常访问数据的备份和归档类型.

七牛云存储

百度云存储

什么是fastDFS

fastDFS介绍

FastDFS是用c语言编写的一个分布式文件管理系统,它由淘宝资深架构师余庆编写并且开源 , FastDFS专为互联网量身定制, 从分考虑冗余备份,负载均衡,线性扩容等机制,并且注重高可用,高性能等指标,使用fastDFS很容易单间一个高性能文件服务器集群,提供文件上传,下载等服务.
为什么要用fastDFS呢?
上边介绍的NFS,GFS都是通过分布式文件系统,通过分布式文件系统的有点就是开发体验好,但是系统的复杂度高,性能一般,而且专用的分布式系统虽然开发体验差,但是系统复杂性低并且性能高,fastDFS非常适合用来存储图片等那些小的文件,fastDFS不对文件进行分块,所以他就没有分块合并的开销,fastDFS网络通信采用socker,通信速度很快

fastDFS工作原理

fastDFS架构

在这里插入图片描述

文件上传流程

在这里插入图片描述
客户端上传文件后存储服务器将文件id返回给客服端,此文件id用于后续访问该文件的索引信息.文件索引信息包括:组名,虚拟磁盘路径,数据两级目录,文件名.
文件id格式在这里插入图片描述

  • 组名:文件上传所在的storage组名称,在文件上传成功后,由storage服务器返回,需要客服端自行保存.
  • 虚拟磁盘路径:storage配置的虚拟路径,与磁盘选项store_path*对应,如果配置了store_path0,则是M00,
  • 数据两级目录:strage服务器在每个虚拟磁盘路径下创建两级目录,用于存储数据文件
  • 文件名:与文件上传不同,是由存储服务器根据特定信息生成,文件名包含:原存储服务器ip地址,文件创建时间戳,文件大小,随机数和文件拓展名等信息.

文件下载流程

下载流程
tracker根据请求文件的路径即文件id来快速定义文件.
比如请求下边的文件:
在这里插入图片描述

fastDFS入门

fastDFS安装与配置

导入虚拟机

对fastDFS安装过程不需要掌握

关于tracker和storage的配置,可以自行查询,我这里就不再一一介绍了,
过程可能有点麻烦,
但是我们作为学者,纵使知道不可为
而为之
这就是我们的精神,
正是有着这种学者精神,
人类的历史书页,
才会那样的多姿多彩

在idea中新建一个项目
test-fdfs
在pom文件中加入依赖

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- https://mvnrepository.com/artifact/net.oschina.zcx7878/fastdfs-client-java -->
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
            <version>1.27.0.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
            <version>1.3.2</version>
        </dependency>
    </dependencies>

在这里插入图片描述
这个时test文件中的测试代码
在测试之前,需要在java文件下编写运行代码

package com.xuecheng.test.fastdfs;

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

/**
 * @author Administrator
 * @version 1.0
 * @create 2018-06-21 12:40
 **/

@SpringBootApplication
public class TestFastDFSApplication {
    public static void main(String[] args) {
        SpringApplication.run(TestFastDFSApplication.class,args);

    }
}

上传测试中的Test代码

package com.xuecheng.test.fastdfs;

import org.csource.common.MyException;
import org.csource.fastdfs.*;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import sun.usagetracker.UsageTrackerClient;

import java.io.IOException;

/**
 * @author Andrewer
 * @version 1.0
 * @project xcEduService01
 * @description
 * @date 2022/12/11 14:06:13
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestFastDFS  {
//    上传测试
@Test
    public void  testUplod(){
    try {
//    加载fastdfs-client.properties配置文件
        ClientGlobal.initByProperties("config/fastdfs-client.properties");
//     定义,TrackerClient,用于请求TrackerServer
    TrackerClient trackerClient = new TrackerClient();
//    连接tracker
        TrackerServer trackerServer = trackerClient.getConnection();
//        获取Storage
        StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
//        创建storageClient
        StorageClient1 storageClient1 = new StorageClient1(trackerServer,storeStorage);
//        向Storage服务器上传文件
//        确定本地文件的路径
        String filePath = "E:/screen/2b9fd311f7e3d71ed7f99725d03010f5.jpeg";
//        上传成功后拿到文件的id
        String fileId = storageClient1.upload_file1(filePath, "jpeg", null);//meta_list辕信息,就是文件的一些原始的摘要信息
        System.out.println(fileId);
//group1/M00/00/00/wKjqg2OVfIqAeDVqAABnB9qZjYw28.jpeg
//        group1/M00/00/00/wKjqg2OV4pWAZx0SAABnB9qZjYw11.jpeg
    } catch (Exception e) {
        e.printStackTrace();
    }

}

//    下载测试
}

通过在sout(fileId)处打断点,可以得到fileId的内容
通过fileId在Storage处查询,即可查到
在这里插入图片描述

[root@localhost data]#ll 00/00/wKjqg2OV4pWAZx0SAABnB9qZjYw11.jpeg
-rw-r--r--. 1 root root 26375 1211 22:00 00/00/wKjqg2OV4pWAZx0SAABnB9qZjYw11.jpeg
[root@localhost data]#

文件下载流程

在这里插入图片描述
下载测试代码:

//    下载测试
    @Test
    public void testsDownload(){
        try {
//    加载fastdfs-client.properties配置文件
            ClientGlobal.initByProperties("config/fastdfs-client.properties");
//            定义TracekrClient,用于请求TrackerServer
            TrackerClient trackerClient  = new TrackerClient();
//            连接Tracker
            TrackerServer trackerServer = trackerClient.getConnection();
//            获取storage
            StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
//            创建SotrageClient
            StorageClient1 storageClient1 = new StorageClient1(trackerServer,storeStorage);
//
//
//            下载文件
//           文件的id
            String fileId = "group1/M00/00/00/wKjqg2OV4pWAZx0SAABnB9qZjYw11.jpeg";
            byte[] bytes = storageClient1.download_file1(fileId);
//            使用输出流,来保存文件
            FileOutputStream fileOutputStream = new FileOutputStream(new File("d:/testdfs/logo.jpeg"));
            fileOutputStream.write(bytes);


        } catch (Exception e) {
            e.printStackTrace();
        }

和上传测试差不多,

  1. 加载fastdfs配置文件
  2. 定义trackerclient
  3. 连接tracker
  4. 获取storage
  5. 创建storageclient
  6. 下载文件
  7. 使用输出流保存文件
  8. 调用write方法输出

加载fastdfs配置文件
后面的上传变成了下载,其中fileoutputStream流中可能会遇到访问不允许,
这个文件是下载文件所在文件夹有权限设置,idea无法操作导致的报错
修改文件的安全属性就可以了.
下载成功!
在这里插入图片描述

文件查询

 
    @Test
    public void testQueryFile() throws MyException, IOException {
    ClientGlobal.initByProperties("config/fastdfs-client.properties");
    TrackerClient trackerClient = new TrackerClient();
        TrackerServer trackerServer = trackerClient.getConnection();
        StorageServer storageServer = null;
        StorageClient storageClient = new StorageClient(trackerServer,storageServer);
        FileInfo fileInfo = storageClient.query_file_info("group1","M00/00/00/wKjqg2OV4pWAZx0SAABnB9qZjYw11.jpeg");
        System.out.println(fileInfo);

运行后输出fileInfo

source_ip_addr = 192.168.234.131, file_size = 26375, create_timestamp = 2022-12-11 22:00:53, crc32 = -627470964

搭建图片虚拟主机

在storage上安装nginx

cd进入到nginx-1.18.0目录内执行

[root@centos7 nginx-1.18.0]# ./configure --prefix=/usr/local/nginx
[root@centos7 nginx-1.18.0]# make
[root@centos7 nginx-1.18.0]# make install

ps:–prefix=path 定义一个目录,存放服务器上的文件 ,也就是nginx的安装目录,默认使用 /usr/local/nginx
这步你会看到local目录下有一个跟你安装的nginx1.12.2同级的nginx目录,里面就有sbin目录了。

启动:cd /usr/local/nginx/sbin;输入./nginx 启动nginx。如果nginx被配置成了服务可以这样启动/etc/init.d/nginx start

配置Nginx图片服务虚拟机主机

图片服务虚拟主机的作用是负载均衡,将土拍你请求转发到storage server上.
1.通过图片服务虚拟主机请求图片流程图

在这里插入图片描述

在这里插入图片描述

这个是虚拟机上面的tracker和storage,nginx启动后面跟着的是配置文件

[root@localhost ~]# /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf
[root@localhost ~]# /usr/bin/fdfs_storaged /etc/fdfs/storage.conf
[root@localhost conf]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf

启动nginx
这里的配置文件目录更具不同人的操作不同,其中nginx-fdfs.conf 是我自己配置的文件
文件内容如下:

http
{


        server{
                listen  80;
                server_name  192.168.234.131;
                location /group1/M00/{
                        root /home/fastdfs/fdfs_storage/data;



}

}
}

        events {
  worker_connections  1024;  ## Default: 1024
}

这里有的的人可能会遇到nginx包中没有sbin这个问题

将nginx-1.8.0.tar.gz拷贝到/usr/local下
解压nginx-1.8.0.tar.gz
进入nginx-1.8.0目录,执行如下配置命令:
下边红色部分表示添加FastDFS-nginx-module模块

./configure --prefix=/usr/local/nginx
./configure  --pid-path=/var/run/nginx/nginx.pid
./configure  --lock-path=/var/lock/nginx.lock
./configure  --error-log-path=/var/log/nginx/error.log
./configure  --http-log-path=/var/log/nginx/access.log
./configure  --with-http_gzip_static_module
./configure  --http-client-body-temp-path=/var/temp/nginx/client
./configure  --http-proxy-temp-path=/var/temp/nginx/proxy
./configure  --http-fastcgi-temp-path=/var/temp/nginx/fastcgi
./configure  --http-uwsgi-temp-path=/var/temp/nginx/uwsgi
./configure  --http-scgi-temp-path=/var/temp/nginx/scgi

./configure --add-module=/usr/local/FastDFS-nginx-module/src

make
make install
查看fdfs进程

[root@localhost conf]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf
[root@localhost conf]# ps aux|grep fdfs
root       6562  0.0  6.6 212720 66772 ?        Sl   1211   0:24 /usr/bin/fdfs_storaged /etc/fdfs/storage.conf
root      61487  0.0  0.0  24884   748 ?        Ss   01:45   0:00 nginx: master process /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf
root      61518  5.5  0.0 112828   988 pts/1    S+   01:58   0:00 grep --color=auto fdfs
[root@localhost conf]# 

这里会遇到这个问题,显示fastdfs这个module无法理解
,可能是这个包未导入也就是上面
./configure --add-module=/usr/local/FastDFS-nginx-module/src
这句的问题,如果已经导入的话,也有可能是名字的问题,我这里把FastDFS换成小写的就成功了

[root@localhost sbin]# ./nginx -t
nginx: [emerg] unknown directive "ngx_FastDFS_module" in /usr/local/nginx/conf/nginx.conf:49
nginx: configuration file /usr/local/nginx/conf/nginx.conf test failed
[root@localhost sbin]# ./nginx -t
ngx_http_fastdfs_set pid=94877
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/
pkill -9 nginx
./nginx

反正无论是什么样子的问题,只要耐心下来仔细解决,看清楚系统提示的错误,那么,就一定会解决的!
加载成功后,

`

[root@localhost conf]# /usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx-fdfs.conf
ngx_http_fastdfs_set pid=27453

在这里插入图片描述
访问web端口,得到图片

在win主机上的nginx中,调节conf




   #CMS页面预览
	upstream cms_server_pool{
	 server 127.0.0.1:31001 weight=10;
	    }
#图片服务配置了group1下的storage服务器地址
	upstream img_server_pool{
	#server 192.168.234.128:80 weight=10;
	server 192.168.234.131:80 weight=10;
	}
#upstream img_server_pool_group2{
	#server 192.168.234.128:80 weight=10;
#	server 192.168.234.131:80 weight=10;
	}
       server {
        listen       80;
        server_name  www.xuechengliuguanghan.com;
	ssi on;
	ssi_silent_errors on;
	location / {
		alias E:/jetbrain/ws/xc-ui-pc-static-portal/;
		
		index index.html;
	}
	#页面预览
	location /cms/preview/{
		proxy_pass http://cms_server_pool/cms/preview/;
	}

  }
  #学成网图片服务
  server{
	listen 80;
	server_name img.xuecheng.com
	
	#个人中心
	location /group1{
		proxy_pass http://img_server_pool;
		}
	}
    
    


}

C:\Windows\System32\drivers\etc
下有一个文件hosts
打开
配置

0.0.0.0		account.jetbrains.com
127.0.0.1	www.xuecheng.com
127.0.0.1	img.xuecheng.com
127.0.0.1	ucenter.xuecheng.com
127.0.0.1	system.xuecheng.com
127.0.0.1	teacher.xuecheng.com
127.0.0.1	video.xuecheng.com

127.0.0.1 image.xuecheng.com

#user  nobody;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

#pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    #log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
    #                  '$status $body_bytes_sent "$http_referer" '
    #                  '"$http_user_agent" "$http_x_forwarded_for"';

    #access_log  logs/access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    #gzip  on;

   #CMS页面预览
	upstream cms_server_pool{
	 server 127.0.0.1:31001 weight=10;
	    }
#图片服务配置了group1下的storage服务器地址
	upstream img_server_pool{
	#server 192.168.234.128:80 weight=10;
	server 192.168.234.131:80 weight=10;
	}

       server {
        listen       80;
        server_name  www.xuecheng.com;
	
	location / {
	ssi on;
	ssi_silent_errors on;
		alias E:/jetbrain/ws/xc-ui-pc-static-portal/;
		
		index index.html;
	}
	#页面预览
	location /cms/preview/{
		proxy_pass http://cms_server_pool/cms/preview/;
	}

  }
  #学成网图片服务
  server{
	listen 80;
	server_name img.xuecheng.com;
	
	#个人中心
	location /group1{
		proxy_pass http://img_server_pool;
		}
	}
    
    

    # another virtual host using mix of IP-, name-, and port-based configuration
    #
    #server {
    #    listen       8000;
    #    listen       somename:8080;
    #    server_name  somename  alias  another.alias;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}


    # HTTPS server
    #
    #server {
    #    listen       443 ssl;
    #    server_name  localhost;

    #    ssl_certificate      cert.pem;
    #    ssl_certificate_key  cert.key;

    #    ssl_session_cache    shared:SSL:1m;
    #    ssl_session_timeout  5m;

    #    ssl_ciphers  HIGH:!aNULL:!MD5;
    #    ssl_prefer_server_ciphers  on;

    #    location / {
    #        root   html;
    #        index  index.html index.htm;
    #    }
    #}

}


在这里我遇到了一个问题,就是nginx访问img.xuecheng.com时候拒绝访问
host没有问题,
nginx.conf也没有问题,
log日志没有出错
虚拟机那边也没有问题
换了个浏览器也没有问题
我这边判断可能是hosts这里出的问题,可能是应为没有走内网络导致的拒绝访问
更具网上的资料修改host,文件格式,内容格式,ipconfig /flushdns清除内缓存等,都没有用
卸载掉nginx也没有用,这时查看任务管理器中发现有两个nginx,以为有一个是真的而我修改的这个是假的,查了一下,一个是工程nginx,一个是守护nginx
但是新下载的未配置内域名,访问localhost的时候,却还是弹出之前配置好的网页
在这里插入图片描述

我觉得我这个应该是假的nginx,应该还有一个真的nginx在运行,抢占了我一直再修改的nginx,查询了一下之前可能存在过使用另一个nginx的踪迹,终于找到了,但是当我打开另一个的conf文件时,却发现这个conf是初始化的文件,
打开任务栏窗口,发现此时却有七个nginx.exe进程在运行,全部结束掉之后,重新打开新下载的nginx,未配置conf运行localhost
弹出
在这里插入图片描述
在这个conf中开始配置内域名和映射,
再次访问img.xuecheng.com/group1/M00/00/00/wKjqg2OYJjyAX2t-AC5x3kz8Zco29.jpeg
在这里插入图片描述
获取到虚拟机中storage中的图片

上传图片开发

需求分析

在很多系统都有上传图片/上传文件的需求,比如:上传课程图片,上传课程资料,上传用户头像等,为了提供系统的可重用性,装维设立文件系统服务承担图片/文件的管理,文件系统服务实现对文件的上传,删除,查询等功能进行管理.
各各子系统不在开发上传文件请求,各各子系统同通过文件系统服务进行文件的上传,删除等操作,文件系统服务最总会将文件存储到fastDFS文件系统中.
下图是各各子系统与文件系统服务之间的关系:
在这里插入图片描述
下图是课程管理中上传图片处理流程:
执行流程如下:
在这里插入图片描述

创建文件系统服务工程

导入xc-service-base-filesystem.zip工程
1.工程目录结构
在这里插入图片描述
将这个工程加入项目module

    <dependencies>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-service-api</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-model</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>com.xuecheng</groupId>
            <artifactId>xc-framework-common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>net.oschina.zcx7878</groupId>
            <artifactId>fastdfs-client-java</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-io</artifactId>
        </dependency>

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

pom中的依赖文件
里里面有fastdfs
和mongdb
在mongdb中新建xc_fs
对应配置问年中的数据
application.yml

server:
  port: 22100
spring:
  application:
    name: xc-service-base-filesystem
#mongo配置
  data:
    mongodb:
#      文件系统服务的数据库
      database: xc_fs
      uri: mongodb://root:123@127.0.0.1:27017
#SpringMVC上传文件配置
  servlet:
    multipart:
      #默认支持文件上传.
      enabled: true
      #支持文件写入磁盘.
      file-size-threshold: 0
      # 上传文件的临时目录
      location:
#       最大支持文件大小
      max-file-size: 1MB
      # 最大支持请求大小
      max-request-size: 30MB
xuecheng:
  fastdfs:
    connect_timeout_in_seconds: 5
    network_timeout_in_seconds: 30
    charset: UTF-8
    tracker_servers: 192.168.234.131:22122 #多个 trackerServer中间以逗号分隔

因为在model中存在

在这里插入图片描述
文件,导入配置之后会自动在xc_fs中根据model填写mongdb中的文件

Api接口

package com.xuecheng.api.filesystem;

import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jdk.internal.org.objectweb.asm.tree.analysis.Value;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author Andrewer
 * @version 1.0
 * @project xcEduService01
 * @description
 * @date 2022/12/14 13:01:49
 */
@Api(value = "文件管理接口",description = "文件的管理接口,提供文件的上传服务")
public interface FileSystemControllerApi {
//     上传文件
    @ApiOperation("上传文件接口")
    public UploadFileResult upload(MultipartFile multipartFile,//文件本身
                                   String filetag,//文件tag
                                   String businesskey,//文件业务标识
                                   String metadata);//文件原信息,上传json格式,妆化为map
}

Dao

将文本信息存入数据库,主要存储文件系统中的文件路径

package com.xuecheng.filesystem.dao;

import com.xuecheng.framework.domain.filesystem.FileSystem;
import org.springframework.data.mongodb.repository.MongoRepository;

/**
 * @author Andrewer
 * @version 1.0
 * @project xcEduService01
 * @description
 * @date 2022/12/14 13:15:01
 */
//FileSystem类型,主键String
public interface FileSystemRepository extends MongoRepository<FileSystem,String> {
}

Surround with 快捷键 cont+art+t
在这里插入图片描述
Service

package com.xuecheng.filesystem.service;

import com.alibaba.fastjson.JSON;
import com.xuecheng.filesystem.dao.FileSystemRepository;
import com.xuecheng.framework.domain.filesystem.FileSystem;
import com.xuecheng.framework.domain.filesystem.response.FileSystemCode;
import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
import com.xuecheng.framework.exception.ExceptionCast;
import com.xuecheng.framework.model.response.CommonCode;
import org.apache.commons.lang3.StringUtils;
import org.csource.common.MyException;
import org.csource.fastdfs.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.Map;

/**
 * @author Andrewer
 * @version 1.0
 * @project xcEduService01
 * @description
 * @date 2022/12/14 13:17:02
 */
@Service
public class FileSystemService {

    //将application中的配置信息注入到service中
    @Value("${xuecheng.fastdfs.tracker_servers}")
    String tracker_servers;
    @Value("${xuecheng.fastdfs.connect_timeout_in_seconds}")
    int connect_timeout_in_seconds;
    @Value("${xuecheng.fastdfs.network_timeout_in_seconds}")
    int network_timeout_in_seconds;
    @Value("${xuecheng.fastdfs.charset}")
    String charset;

    @Autowired
    FileSystemRepository fileSystemRepository;

    //    上传文件
    public UploadFileResult upload(MultipartFile multipartFile,
                                   String filetag,
                                   String businesskey,
                                   String metadata) {
        if (multipartFile ==null){
            ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_FILEISNULL);
        }

//第一步,将文件上传到fastDFS中 ,得到一个文件的id
        String fileId = fdfs_upload(multipartFile);
        if (StringUtils.isEmpty(fileId)){
            ExceptionCast.cast(FileSystemCode.FS_UPLOADFILE_SERVERFAIL);
        }
//        第二步,将文件的id以及文件的信息存储到mongodb中
        FileSystem fileSystem = new FileSystem();

        fileSystem.setFileId(fileId);
        fileSystem.setFilePath(fileId);
        fileSystem.setFiletag(filetag);
        fileSystem.setBusinesskey(businesskey);
        fileSystem.setFileName(multipartFile.getOriginalFilename());
        fileSystem.setFileType(multipartFile.getContentType());
//        注意
        if(StringUtils.isNotEmpty(metadata)){
            try {
                Map map = JSON.parseObject(metadata, Map.class);//转化为map格式
        fileSystem.setMetadata(map);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        fileSystemRepository.save(fileSystem);
        return new UploadFileResult(CommonCode.SUCCESS,fileSystem);

    }
//    上传文件到dfs中

    /**
     * @param multipartFile 文件本身
     * @return 返回文件的id
     */
    private String fdfs_upload(MultipartFile multipartFile) {
//初始化fastDFS的环境
        initFdfsConfig();
//        创建一个trackerClient

        TrackerClient trackerClient = new TrackerClient();
        try {
            TrackerServer trackerServer = trackerClient.getConnection();
//            得到storage服务器
            StorageServer storeStorage = trackerClient.getStoreStorage(trackerServer);
//            创建也给storageCLient来上传文件
            StorageClient1 storageClient1  =new StorageClient1(trackerServer,storeStorage);
//            上传文件
//            得到文件的字节
            byte[] bytes = multipartFile.getBytes();
//            得到文件的原始名称
            String originalFilename = multipartFile.getOriginalFilename();
//            得到扩展名
            String ex = originalFilename.substring(originalFilename.lastIndexOf(".") + 1);//获取文件最后一个点加1的index开始的字符串
            String fileId = storageClient1.upload_file1(bytes, ex, null);
            return fileId;
        } catch (Exception e) {
            e.printStackTrace();
        }
return null;

    }

    //    初始化fastDFS环境
    private void initFdfsConfig() {
//        初始化tracker服务器(多个tracker服务器,中间是以半角逗号分割(英文状态下打一个逗号))
        try {
            ClientGlobal.initByTrackers(tracker_servers);
            ClientGlobal.setG_charset(charset);
            ClientGlobal.setG_network_timeout(network_timeout_in_seconds);
            ClientGlobal.setG_connect_timeout(connect_timeout_in_seconds);
        } catch (Exception e) {
            e.printStackTrace();
//            抛出异常
            ExceptionCast.cast(FileSystemCode.FS_INITFDFS_ERROR);
        }
    }
}

Controller

package com.xuecheng.filesystem.controller;

import com.xuecheng.api.filesystem.FileSystemControllerApi;
import com.xuecheng.filesystem.service.FileSystemService;
import com.xuecheng.framework.domain.filesystem.response.UploadFileResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * @author Andrewer
 * @version 1.0
 * @project xcEduService01
 * @description
 * @date 2022/12/14 19:00:09
 */
@RestController
@RequestMapping("/filesystem")
public class FileSystemController implements FileSystemControllerApi {
    @Autowired
    FileSystemService fileSystemService;
    @Override
    @PostMapping("/upload")
    public UploadFileResult upload(MultipartFile multipartFile, String filetag, String businesskey, String metadata) {

        return fileSystemService.upload(multipartFile, filetag, businesskey, metadata);
    }
}

在这里插入图片描述
运行application文件,
访问swagger-ui.html
得到接口,通过此处,在idea中打断点测试
测试成功!

{
  "success": true,
  "code": 10000,
  "message": "操作成功!",
  "fileSystem": {
    "fileId": "group1/M00/00/00/wKjqg2OZOWKAAr2yAACaiorb23o22.jpeg",
    "filePath": "group1/M00/00/00/wKjqg2OZOWKAAr2yAACaiorb23o22.jpeg",
    "fileSize": 0,
    "fileName": "9ae58735c9a6d0bb483bfa6d95de3562.jpeg",
    "fileType": "image/jpeg",
    "fileWidth": 0,
    "fileHeight": 0,
    "userId": null,
    "businesskey": "businesskey",
    "filetag": "filetag",
    "metadata": {
      "name": "test"
    }
  }
}

在这里插入图片描述
mongodb中文件成功被写入
在这里插入图片描述
启动前端服务器
打开页面,
选择管理课程,打开后选择添加图片
在这里插入图片描述
加载完成后在idea中跳过断点,
在这里插入图片描述
web端显示文件为空
打开course_picture.vue
在这里插入图片描述
action中/api/filesystem/upload
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
加上name属性之后,上传成功
在这里插入图片描述

保存课程图片

需求分析

图片上传到文件系统之后,其他子系统如果想使用图片可以引用图片的地址,课程管理模块使用图片的方式是将图片保存到课程数据库中.
业务流程如下:
1.上传图片到文件系统服务
2.保存图片地址到课程管理服务
在课程管理服务创建保存课程与图片对应关系的表course_pic

课程管理服务端开发

API

课程管理需要使用图片则在课程管理服务中要提供保存课程图片的api
在CourseControllerApi中加入

 @ApiOperation(("添加课程图片"))
    public ResponseResult addCoursePic(String courseId,String pic);
 

CourseController:

   @Override
    @PostMapping("/coursepic/add")
    public ResponseResult addCoursePic(@RequestParam("cousrseId") String courseId, @RequestParam("pic") String pic) {

        return courseService.addCoursePic();
    }


CourseService:

    //像课程管理数据添加课程与图片的关联信息
    @Transactional


    public ResponseResult addCoursePic(String courseId, String pic) {
//有了就更新,没有就新添;
//        课程图片的信息
        CoursePic coursePic = null;
//        查询课程图片
        Optional<CoursePic> picOptional = coursePicRepository.findById(courseId);
        if (picOptional.isPresent()) {
            coursePic = picOptional.get();
        }
        if (coursePic==null){
            coursePic = new CoursePic();
        }
        coursePic.setPic(pic);
        coursePic.setCourseid(courseId);
        coursePicRepository.save(coursePic);
        return new ResponseResult(CommonCode.SUCCESS);
    }

前端开发

前端需要在上传图片成功之后保存课程图片信息

Api方法

在前端的config文件中的course.js中进行方法调用


//保存课程图片地址到课程数据 库
export const addCoursePic= (courseId,pic) => {
  return http.requestPost(apiUrl+'/course/coursepic/add?courseId='+courseId+"&pic="+pic)
}

图片查询

需求分析

课程图片上传成功,再次进入课程上传页面应该显示出来已上传的图片.

APi

在课程管理服务定义查询方法

页面测试

1.before-remove钩子方法
在upload组件的before-remove钩子方法中,实现删除动作.

befrore-remove说明:删除文件之前的钩子,参数为上传文文件和文件列表,若返回false或者返回Pormise,且被reject,则停止删除.
Promise对象在处理过程中有三种状态:
pending:进行中
resolved:操作成功
rejected:操作失败
Promise的构建方法如下:
在这里插入图片描述

定义一个Promise对象非常简单,new一个对象就可以了
function功能里面有两个参数,resolve是执行成功调用的参数,
reject是执行失败调用的参数
Promise是专门用于异步请求的操作方法
上边的构造方法function(reslve,reject)执行的流程如下:
1.方法执行一些业务逻辑.
2.如果操作成功,Promise的状态由pending变为resolved,并将操作结果传出去.
3.如果操作失败,会将Promise的状态由pending变为rejected,并将失败结果传出.
上边说的操作成功将操作结果传给谁了呢,操作失败将失败结果传给谁了呢?
通过promise的then,catch来指定

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值