当前位置:   article > 正文

FastDFS_fastdfs fastfilestorageclient 归还连接重新获取连接

fastdfs fastfilestorageclient 归还连接重新获取连接

FastDFS安装与使用

下载地址

FastDFS所需软件:
链接: https://pan.baidu.com/s/15Lm9qWxmoyY1Mqz9pdCG9w 提取码: 99bg

什么是分布式文件系统

分布式文件系统解决了海量文件存储及传输访问的瓶颈问题,对海量视频的管理、对海量图片的管理等。
分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源不一定直接连接在本地节点上, 而是通过计算机网络与节点相连。

为什么会有分布文件系统

存在问题

分布式文件系统是面对互联网的需求而产生,互联网时代对海量数据如何存储?
靠简单的增加硬盘的个数已经满足 不了我们的要求,因为硬盘传输速度有限但是数据在急剧增长,
另外我们还要要做好数据备份、数据安全等。

解决办法

采用分布式文件系统可以将多个地点的文件系统通过网络连接起来
组成一个文件系统网络,结点之间通过网络进 行通信
一台文件系统的存储和传输能力有限,我们让文件在多台计算机上存储,通过多台计算共同传输
示例图
在这里插入图片描述

好处

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

主流的分布式文件系统

  1. NFS
    在客户端上映射NFS服务器的驱动器
    客户端通过网络访问NFS服务器的硬盘完全透明。
    结构图
    在这里插入图片描述
  2. GFS
    GFS采用主从结构,一个GFS集群由一个master和大量的chunkserver组成
    master存储了数据文件的元数据,一个文件被分成了若干块存储在多个chunkserver中。
    用户从master中获取数据元信息,从chunkserver存储数据
    结构图
    在这里插入图片描述
  3. HDFS
    Hadoop分布式文件系统主要用于大数据
    HDFS采用主从结构,一个HDFS集群由一个名称结点和若干数据结点组成
    名称结点存储数据的元信息,一个完整的数据文件分成若干块存储在数据结点。
    客户端从名称结点获取数据的元信息及数据分块的信息,得到信息客户端即可从数据块来存取数据。
    结构 在这里插入图片描述

什么是fastDFS

简介

FastDFS是用c语言编写的一款开源的分布式文件系统,它是由淘宝资深架构师余庆编写并开源。
FastDFS专为互联 网量身定制,充分考虑了冗余备份、负载均衡、线性扩容等机制,并注重高可用、高性能等指标,
使用FastDFS很 容易搭建一套高性能的文件服务器集群提供文件上传、下载等服务

为什么要使用fastDFS

通用分布式文件系统
NFS、GFS都是通用的分布式文件系统
通用的分布式文件系统的优点的是开发体验好,但是系统复杂 性高、性能一般
|
专用分布式文件系统
专用的分布式文件系统虽然开发体验性差,但是系统复杂性低并且性能高。
fastDFS非常适合 存储图片等那些小文件,fastDFS不对文件进行分块,
所以它就没有分块合并的开销,fastDFS网络通信采用 socket,通信速度很快

fastDFS工作原理

FastDFS架构包括 Tracker server和Storageserver。
客户端请求Tracker server进行文件上传、下载,通过Tracker server调度最终由Storage server完成文件上传和下载。

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

Tracker

作用:

  1. Tracker Server作用是负载均衡和调度,
  2. 通过Tracker server在文件上传时可以根据一些策略找到Storage server提 供文件上传服务。
  3. 可以将tracker称为追踪服务器或调度服务器。

集群:

FastDFS集群中的Tracker server可以有多台
Tracker server之间是相互平等关系同时提供服务.
客户端请求Tracker server采用轮询方式,如果请求的tracker无法提供服务则换另一个tracker。

Storage

作用:

Storage Server作用是文件存储,客户端上传的文件最终存储在Storage服务器上

集群

Storage集群采用了分组存储方式。storage集群由一个或多个组构成,集群存储总容量为集群中所有组的存储容 量之和
一个组由一台或多台存储服务器组成,组内的Storage server之间是平等关系,
不同组的Storage server 之间不会相互通信
同组内的Storage server之间会相互连接进行文件同步,从而保证同组内每个storage上的文件 完全一致的
一个组的存储容量为该组内的存储服务器容量最小的那个

采用分组存储方式的好处

灵活、可控性较强。比如上传文件时,可以由客户端直接指定上传到的组也可以由 tracker进行调度选择。
一个分组的存储服务器访问压力较大时,可以在该组增加存储服务器来扩充服务能力(纵向 扩容)
当系统容量不足时,可以增加组来扩充存储容量(横向扩容)。

Storage状态收集

Storage server会连接集群中所有的Tracker server,定时向他们报告自己的状态,
包括磁盘剩余空间、文件同步 状况、文件上传下载次数等统计信息。

FastDFS安装与配置

FastDFS是 C 语言开发,建议在 linux 上运行
安装 FastDFS需要先将官网下载的源码进行编译,编译依赖 gcc 环境

1. 需要安装 gcc

yum install gcc-c++
在这里插入图片描述
在这里插入图片描述

2. 安装libevent

FastDFS依赖libevent库
yum -y install libevent
在这里插入图片描述

3.安装libfastcommon

libfastcommon 是 FastDFS 官方提供的,libfastcommon 包含了 FastDFS 运行所需要的一些基础库

  1. 将libfastcommonV1.0.7.tar.gz拷贝至/usr/local/下在这里插入图片描述

  2. 解压libfastcommonV1.0.7.tar.gz
    tar -zxvf libfastcommonV1.0.7.tar.gz

  3. 执行以下命令
    cd libfastcommon-1.0.7
    ./make.sh
    在这里插入图片描述
    ./make.sh install
    在这里插入图片描述

libfastcommon安装好后会自动将库文件拷贝至/usr/lib64下
由于FastDFS程序引用usr/lib目录

所以需要将/usr/lib64下的库文件拷贝至/usr/lib下。
ll /usr/lib64/
在这里插入图片描述

4.安装libevent

  1. 上传 libevent到服务器中
    执行以下命令

  2. 解压
    tar -zxvf libevent-2.0.15-stable.tar.gz

  3. 进入 libevent目录
    cd libevent-2.0.15-stable/

  4. 执行
    第一步: ./configure
    第二步:make && make install
    第三步:ln -s /usr/local/lib/libevent-2.0.so.5 /usr/lib/libevent-2.0.so.5

5. tracker编译安装

  1. 将FastDFS_v5.05.tar.gz拷贝至/usr/local/下

  2. 解压:
    tar -zxvf FastDFS_v5.05.tar.gz

  3. 进入FastDFS目录
    cd FastDFS

  4. 执行以下命令
    ./make.sh
    ./make.sh install

  5. 安装成功将安装目录下的conf下的文件拷贝到/etc/fdfs/下
    cp -ri conf/* /etc/fdfs

  6. 进入/etc/fdfs目录
    cd /etc/fdfs

  7. 修改tracker.conf
    vim tracker.conf
    在这里插入图片描述

在这里插入图片描述

base_path=/home/fastdfs
http.server_port=80

  1. 创建目录
    mkdir -p /home/fastdfs

  2. 启动
    /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
    在这里插入图片描述

  3. 查看是否启动
    ps aux|grep dfs
    在这里插入图片描述

6.进入/etc/fdfs

执行 修改配置文件
vim storage.conf

  1. group_name=group1
  2. base_path=/home/yuqing/FastDFS改为:base_path=/home/fastdfs
  3. store_path0=/home/fastdfs/fdfs_storage
  4. tracker_server=192.168.0.108:22122 #配置 tracker服务器:IP如果有多个则配置多个tracke
  5. http.server_port=80
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
创建文件夹:
mkdir -p /home/fastdfs/fdfs_storage

启动
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart

文件上传流程

流程图
在这里插入图片描述
文件信息

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

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

通过客户端上传图片

  1. 创建maven工程
    在这里插入图片描述
  2. 安装fastdfs架包
mvn install:install-file -DgroupId=org.csource.fastdfs -DartifactId=fastdfs -Dversion=1.2 -Dpackaging=jar -Dfile=fastdfs_client_v1.20.jar
  • 1
  1. 引入依赖
   <dependency>
            <groupId>org.csource.fastdfs</groupId>
            <artifactId>fastdfs</artifactId>
            <version>1.2</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 在resources当中创建fdfs_client.conf配置文件
# connect timeout in seconds
# default value is 30s
connect_timeout=30

# network timeout in seconds
# default value is 30s
network_timeout=60

# the base path to store log files
base_path=/home/fastdfs

# tracker_server can ocur more than once, and tracker_server format is
#  "host:port", host can be hostname or ip address
tracker_server=192.168.0.108:22122

#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level=info

# if use connection pool
# default value is false
# since V4.05
use_connection_pool = false

# connections whose the idle time exceeds this time will be closed
# unit: second
# default value is 3600
# since V4.05
connection_pool_max_idle_time = 3600

# if load FastDFS parameters from tracker server
# since V4.05
# default value is false
load_fdfs_parameters_from_tracker=false

# if use storage ID instead of IP address
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# default value is false
# since V4.05
use_storage_id = false

# specify storage ids filename, can use relative or absolute path
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# since V4.05
storage_ids_filename = storage_ids.conf


#HTTP settings
http.tracker_server_port=80

#use "#include" directive to include HTTP other settiongs
##include http.conf



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  1. 创建测试, 上传图片
 public static void main(String[] args) throws Exception {
        //1. 加载配置文件
        ClientGlobal.init("src/main/resources/fdfs_client.conf");
        //2. 创建管理端对象
        TrackerClient trackerClient = new TrackerClient();
        //3. 通过管理端对象获取连接
        TrackerServer connection = trackerClient.getConnection();
        //4. 创建存储端对象
        StorageClient1 storageClient = new StorageClient1(connection, null);

        //创建文件属性信息对象数组
        NameValuePair[] meta_list = new NameValuePair[3];
        meta_list[0] = new NameValuePair("fileName","time");
        meta_list[1] = new NameValuePair("ExtName","jpg");
        meta_list[2] = new NameValuePair("zuozhe","joker");

        //5. 上传文件
        String path = storageClient.upload_file1("C:\\Users\\Joker_DJ\\Pictures\\timg.jpg", "jpg", meta_list);
        System.out.println("======" + path);
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

启动测试
在这里插入图片描述
查看文件存放目录
cd /home/fastdfs/fdfs_storage/data/00/00
在这里插入图片描述

搭建图片服务虚拟主机

在Storage上安装nginx

在storage server上安装nginx的目的是对外通过http访问storage server 上的文件
使用 nginx 的模块 FastDFS-nginx-module 的作用是通过 http 方式访问 storage 中的文件

安装FastDFS-nginx

  1. 将 FastDFS-nginx-module_v1.16.tar.gz上到usr/local下

  2. 解压
    tar -zxvf fastdfs-nginx-module_v1.16.tar.gz

  3. 进入src目录
    cd fastdfs-nginx-module/src

  4. 修改config文件将/usr/local/路径改为/usr/
    vim config
    在这里插入图片描述

  5. 将FastDFS-nginx-module/src下的mod_FastDFS.conf拷贝至/etc/fdfs/下
    cp mod_fastdfs.conf /etc/fdfs/

  6. 修改mod_fastdfs.conf
    vim /etc/fdfs/mod_fastdfs.conf

  1. base_path=/home/fastdfs
    在这里插入图片描述
  2. tracker_server=192.168.0.108:22122
    在这里插入图片描述
  3. url_have_group_name=true 在这里插入图片描述
  4. store_path0=/home/fastdfs/fdfs_storage
    在这里插入图片描述
    esc后保存并退出 :wq
  1. 将libfdfsclient.so拷贝至/usr/lib下
    cp /usr/lib64/libfdfsclient.so /usr/lib/

  2. 复制 FastDFS的部分配置文件到/etc/fdfs目录
    cd /usr/local/FastDFS/conf/
    cp http.conf mime.types /etc/fdfs/

nginx安装

将nginx-1.8.1.tar.gz拷贝到/usr/local下

  1. 解压nginx-1.8.1.tar.gz
    tar -zxvf nginx-1.8.1.tar.gz

  2. 依赖包
    sudo yum -y install pcre pcre-devel zlib zlib-devel openssl openssl-devel

  3. 进入nginx目录
    cd nginx-1.8.1/

  4. 执行配置
    ./configure --prefix=/opt/nginx --sbin-path=/usr/bin/nginx --add-module=/usr/local/fastdfs-nginx-module/src

  5. 在 nginx-1.8.1目录下依次执行
    make
    make install
    useradd -s /sbin/nologin -M nginx
    id nginx

  6. 启动ngnix
    nginx

  7. 停止nginx
    nginx -s stop

  8. 重新加载配置
    nginx -s reload

  9. 查看是否启动
    ps -ef|grep nginx
    在这里插入图片描述

  10. 修改配置文件
    vim /opt/nginx/conf/nginx.conf

	# 监听域名中带有group的,交给FastDFS模块处理
	        location ~/group([0-9])/ {
	            ngx_fastdfs_module;
	        }
  • 1
  • 2
  • 3
  • 4

在这里插入图片描述
重新加载配置
nginx -s reload

查看是否生效
在主机通过ip地址访问nginx
http://192.168.0.108
在这里插入图片描述

启动

/usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
/usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
nginx

访问上传图片的地址

http://192.168.0.108/group1/M00/00/00/wKgAbF8pL5KAUR9AAABCFe5hWE4513.jpg
在这里插入图片描述

云服务器访问需要开启的端口

  1. 22122
  2. 50548
  3. 55704
  4. 23000
    在这里插入图片描述
    在这里插入图片描述

设置FastDFS开机自启

虚拟机每次启动之后都要重新启动FastDFS和nginx,比较麻烦所以增加开机自启

在centos7 /etc/rc.d/rc.local 文件的权限被降低了,所以给rc.local文件增加可执行的权限
执行命令:chmod +x /etc/rc.d/rc.local

编辑 /etc/rc.d/rc.local文件,增加启动项

  1. 编辑文件
    vim /etc/rc.d/rc.local
  2. 增加文件如下
    #fastdfs start
    /usr/bin/fdfs_trackerd /etc/fdfs/tracker.conf restart
    /usr/bin/fdfs_storaged /etc/fdfs/storage.conf restart
    #nginx start
    /usr/local/nginx/sbin/nginx
    在这里插入图片描述

基于SSM+FastDFS+vue实现图片上传

  1. 编写上传按钮事件
    在这里插入图片描述
    在这里插入图片描述

  2. 注意开启SpringMVC的媒体解析器
    在这里插入图片描述

 <!-- 配置多媒体解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="defaultEncoding" value="UTF-8"></property>
        <!-- 设定文件上传的最大值5MB,5*1024*1024 -->
        <property name="maxUploadSize" value="5242880"></property>
    </bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  1. 引入pom文件 从本地安装
  		<dependency>
            <groupId>org.csource.fastdfs</groupId>
            <artifactId>fastdfs</artifactId>
            <version>1.2</version>
        </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 引入fastDFS配置文件和服务地址配置文件
    在这里插入图片描述
    application.properties
FILE_SERVER_URL=http://192.168.0.108/
  • 1

新建fastDFS配置文件夹
在这里插入图片描述
fdfs_client.conf

# connect timeout in seconds
# default value is 30s
connect_timeout=30

# network timeout in seconds
# default value is 30s
network_timeout=60

# the base path to store log files
base_path=/home/fastdfs

# tracker_server can ocur more than once, and tracker_server format is
#  "host:port", host can be hostname or ip address
tracker_server=192.168.0.108:22122

#standard log level as syslog, case insensitive, value list:
### emerg for emergency
### alert
### crit for critical
### error
### warn for warning
### notice
### info
### debug
log_level=info

# if use connection pool
# default value is false
# since V4.05
use_connection_pool = false

# connections whose the idle time exceeds this time will be closed
# unit: second
# default value is 3600
# since V4.05
connection_pool_max_idle_time = 3600

# if load FastDFS parameters from tracker server
# since V4.05
# default value is false
load_fdfs_parameters_from_tracker=false

# if use storage ID instead of IP address
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# default value is false
# since V4.05
use_storage_id = false

# specify storage ids filename, can use relative or absolute path
# same as tracker.conf
# valid only when load_fdfs_parameters_from_tracker is false
# since V4.05
storage_ids_filename = storage_ids.conf


#HTTP settings
http.tracker_server_port=80

#use "#include" directive to include HTTP other settiongs
##include http.conf



  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  1. 在spring-mvc.xml加载属文件
    在这里插入图片描述
<context:property-placeholder location="classpath:config/application.properties" />
  • 1
  1. 编写工具类
    在这里插入图片描述

import org.apache.commons.io.FilenameUtils;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import java.io.IOException;

public class FastDFSClient {

    private TrackerClient trackerClient = null;
    private TrackerServer trackerServer = null;
    private StorageServer storageServer = null;
    private StorageClient1 storageClient = null;

    public FastDFSClient(String conf) throws Exception {
        if (conf.contains("classpath:")) {
            conf = conf.replace("classpath:", this.getClass().getResource("/").getPath());
        }
        ClientGlobal.init(conf);
        trackerClient = new TrackerClient();
        trackerServer = trackerClient.getConnection();
        storageServer = null;
        storageClient = new StorageClient1(trackerServer, storageServer);
    }

    /**
     * @param file 文件二进制
     * @param fileName 文件名
     * @param fileSize 文件大小
     * @return
     * @throws Exception
     */
    public String uploadFile(byte[] file, String fileName, long fileSize) throws Exception {
        NameValuePair[] metas = new NameValuePair[3];
        metas[0] = new NameValuePair("fileName", fileName);
        metas[1] = new NameValuePair("fileSize", String.valueOf(fileSize));
        metas[2] = new NameValuePair("fileExt", FilenameUtils.getExtension(fileName));
        String result = storageClient.upload_file1(file, FilenameUtils.getExtension(fileName), metas);
        return result;
    }

    /**
     *
     * @param storagePath  文件的全部路径 如:group1/M00/00/00/wKgRsVjtwpSAXGwkAAAweEAzRjw471.jpg
     * @return -1失败,0成功
     * @throws Exception
     */
    public Integer delete_file(String storagePath){
        int result=-1;
        try {
            result = storageClient.delete_file1(storagePath);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return  result;
    }



}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  1. 在UploadController方法中上传图片
    在这里插入图片描述
@RestController
@RequestMapping("/upload")
public class UploadController {

    @Value("${FILE_SERVER_URL}")
    private String FILE_SERVER;

    @RequestMapping("/uploadFile")
    public Result uploadFile(MultipartFile file) throws Exception {
        try {
            FastDFSClient fastDFS = new FastDFSClient("classpath:fastDFS/fdfs_client.conf");
            //上传文件返回文件保存的路径和文件名
            String path = fastDFS.uploadFile(file.getBytes(), file.getOriginalFilename(), file.getSize());
            /**
             保存数据库...
             */
            //拼接上服务器的地址返回给前端
            return new Result(true, FILE_SERVER + path);
        } catch (Exception e) {
            e.printStackTrace();
            return new Result(false, "上传失败!");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  1. 删除图片
    在这里插入图片描述
    /*删除图片*/
    @RequestMapping("/delteImage")
    public Result delteImage(String url){
        try {
            String path  = url.substring(FILE_SERVER.length());
            FastDFSClient fastDFS =new FastDFSClient("classpath:fastDFS/fdfs_client.conf");
            Integer integer = fastDFS.delete_file(path);
            if (integer == 0){
                return new Result(true, "删除成功");
            }else {
                return new Result(false, "删除失败");
            }
        } catch (Exception e) {
            return new Result(false, "删除失败");
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/169884
推荐阅读
相关标签
  

闽ICP备14008679号